forked from qt-creator/qt-creator
		
	Initial work on the QML/JS expression evaluator.
This commit is contained in:
		| @@ -21,7 +21,8 @@ HEADERS += \ | ||||
|     $$PWD/qmljspackageinfo.h \ | ||||
|     $$PWD/qmljsscanner.h \ | ||||
|     $$PWD/qmljssymbol.h \ | ||||
|     $$PWD/qmljstypesystem.h | ||||
|     $$PWD/qmljstypesystem.h \ | ||||
|     $$PWD/qmljsinterpreter.h | ||||
|  | ||||
| SOURCES += \ | ||||
|     $$PWD/qmljsbind.cpp \ | ||||
| @@ -32,7 +33,8 @@ SOURCES += \ | ||||
|     $$PWD/qmljspackageinfo.cpp \ | ||||
|     $$PWD/qmljsscanner.cpp \ | ||||
|     $$PWD/qmljssymbol.cpp \ | ||||
|     $$PWD/qmljstypesystem.cpp | ||||
|     $$PWD/qmljstypesystem.cpp \ | ||||
|     $$PWD/qmljsinterpreter.cpp | ||||
|  | ||||
| contains(QT_CONFIG, declarative) { | ||||
|     QT += declarative | ||||
|   | ||||
							
								
								
									
										954
									
								
								src/libs/qmljs/qmljsinterpreter.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										954
									
								
								src/libs/qmljs/qmljsinterpreter.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,954 @@ | ||||
| /************************************************************************** | ||||
| ** | ||||
| ** This file is part of Qt Creator | ||||
| ** | ||||
| ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). | ||||
| ** | ||||
| ** Contact: Nokia Corporation (qt-info@nokia.com) | ||||
| ** | ||||
| ** Commercial Usage | ||||
| ** | ||||
| ** Licensees holding valid Qt Commercial licenses may use this file in | ||||
| ** accordance with the Qt Commercial License Agreement provided with the | ||||
| ** Software or, alternatively, in accordance with the terms contained in | ||||
| ** a written agreement between you and Nokia. | ||||
| ** | ||||
| ** GNU Lesser General Public License Usage | ||||
| ** | ||||
| ** Alternatively, this file may be used under the terms of the GNU Lesser | ||||
| ** General Public License version 2.1 as published by the Free Software | ||||
| ** Foundation and appearing in the file LICENSE.LGPL included in the | ||||
| ** packaging of this file.  Please review the following information to | ||||
| ** ensure the GNU Lesser General Public License version 2.1 requirements | ||||
| ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||||
| ** | ||||
| ** If you are unsure which license is appropriate for your use, please | ||||
| ** contact the sales department at http://qt.nokia.com/contact. | ||||
| ** | ||||
| **************************************************************************/ | ||||
|  | ||||
| #include "qmljsinterpreter.h" | ||||
| #include <QtCore/QDebug> | ||||
|  | ||||
| using namespace QmlJS::Interpreter; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // 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 *) {} | ||||
|  | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // 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; } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Environment | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| Environment::Environment() {} | ||||
| Environment::~Environment() {} | ||||
| const Environment *Environment::parent() const { return 0; } | ||||
|  | ||||
| const Value *Environment::lookup(const QString &name) const | ||||
| { | ||||
|     if (const Value *member = lookupMember(name)) | ||||
|         return member; | ||||
|  | ||||
|     else if (const Environment *p = parent()) | ||||
|         return p->lookup(name); | ||||
|  | ||||
|     else | ||||
|         return 0; | ||||
| } | ||||
|  | ||||
| const Value *Environment::lookupMember(const QString &name) const { | ||||
|     Q_UNUSED(name); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // 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; | ||||
|  | ||||
|     return lookupMember(name); | ||||
| } | ||||
|  | ||||
| void ObjectValue::setPrototype(const ObjectValue *prototype) | ||||
| { | ||||
|     QSet<const ObjectValue *> processed; | ||||
|  | ||||
|     if (! prototype || isValidPrototype(prototype, &processed)) | ||||
|         _prototype = prototype; | ||||
|     else | ||||
|         qWarning() << "**** invalid prototype:"; | ||||
| } | ||||
|  | ||||
| bool ObjectValue::isValidPrototype(const ObjectValue *proto, QSet<const ObjectValue *> *processed) const | ||||
| { | ||||
|     const int previousSize = processed->size(); | ||||
|     processed->insert(this); | ||||
|  | ||||
|     if (previousSize != processed->size()) { | ||||
|         if (this == proto) | ||||
|             return false; | ||||
|  | ||||
|         if (prototype() && ! prototype()->isValidPrototype(proto, processed)) | ||||
|             return false; | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| const Value *ObjectValue::member(const QString &name) const | ||||
| { | ||||
|     MemberIterator 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) {} | ||||
| 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) { 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::property(const QString &name) const | ||||
| { | ||||
|     if (name == "length") | ||||
|         return engine()->numberValue(); | ||||
|  | ||||
|     return FunctionValue::property(name); | ||||
| } | ||||
|  | ||||
| const Value *Function::call(const Value *thisValue, const QList<const Value *> &) const | ||||
| { | ||||
|     return thisValue; // ### FIXME it should return undefined | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // typing environment | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| ConvertToNumber::ConvertToNumber(Engine *engine): _engine(engine), _result(0) {} | ||||
|  | ||||
| const Value *ConvertToNumber::operator()(const Value *value) { | ||||
|     const Value *previousValue = switchResult(0); | ||||
|  | ||||
|     if (value) | ||||
|         value->accept(this); | ||||
|  | ||||
|     return switchResult(previousValue); | ||||
| } | ||||
|  | ||||
| const Value *ConvertToNumber::switchResult(const Value *value) { | ||||
|     const Value *previousResult = _result; | ||||
|     _result = value; | ||||
|     return previousResult; | ||||
| } | ||||
|  | ||||
| ConvertToString::ConvertToString(Engine *engine): _engine(engine), _result(0) {} | ||||
|  | ||||
| const Value *ConvertToString::operator()(const Value *value) { | ||||
|     const Value *previousValue = switchResult(0); | ||||
|  | ||||
|     if (value) | ||||
|         value->accept(this); | ||||
|  | ||||
|     return switchResult(previousValue); | ||||
| } | ||||
|  | ||||
| const Value *ConvertToString::switchResult(const Value *value) { | ||||
|     const Value *previousResult = _result; | ||||
|     _result = value; | ||||
|     return previousResult; | ||||
| } | ||||
|  | ||||
| ConvertToObject::ConvertToObject(Engine *engine): _engine(engine), _result(0) {} | ||||
|  | ||||
| const Value *ConvertToObject::operator()(const Value *value) { | ||||
|     const Value *previousValue = switchResult(0); | ||||
|  | ||||
|     if (value) | ||||
|         value->accept(this); | ||||
|  | ||||
|     return switchResult(previousValue); | ||||
| } | ||||
|  | ||||
| const Value *ConvertToObject::switchResult(const Value *value) { | ||||
|     const Value *previousResult = _result; | ||||
|     _result = value; | ||||
|     return previousResult; | ||||
| } | ||||
|  | ||||
|  | ||||
| QString TypeId::operator()(const Value *value) | ||||
| { | ||||
|     _result = QLatin1String("unknown"); | ||||
|  | ||||
|     if (value) | ||||
|         value->accept(this); | ||||
|  | ||||
|     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 | ||||
| { | ||||
| public: | ||||
|     FunctionCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class ArrayCtor: public Function | ||||
| { | ||||
| public: | ||||
|     ArrayCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class StringCtor: public Function | ||||
| { | ||||
| public: | ||||
|     StringCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class BooleanCtor: public Function | ||||
| { | ||||
| public: | ||||
|     BooleanCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class NumberCtor: public Function | ||||
| { | ||||
| public: | ||||
|     NumberCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class DateCtor: public Function | ||||
| { | ||||
| public: | ||||
|     DateCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; | ||||
| }; | ||||
|  | ||||
| class RegExpCtor: public Function | ||||
| { | ||||
| public: | ||||
|     RegExpCtor(Engine *engine); | ||||
|  | ||||
|     virtual const Value *call(const Value *thisValue, const QList<const Value *> &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) {} | ||||
|  | ||||
| Engine::Engine() | ||||
|     : _objectPrototype(0), | ||||
|       _functionPrototype(0), | ||||
|       _numberPrototype(0), | ||||
|       _booleanPrototype(0), | ||||
|       _stringPrototype(0), | ||||
|       _arrayPrototype(0), | ||||
|       _datePrototype(0), | ||||
|       _regexpPrototype(0), | ||||
|       _objectCtor(0), | ||||
|       _functionCtor(0), | ||||
|       _arrayCtor(0), | ||||
|       _stringCtor(0), | ||||
|       _booleanCtor(0), | ||||
|       _numberCtor(0), | ||||
|       _dateCtor(0), | ||||
|       _regexpCtor(0), | ||||
|       _globalObject(0), | ||||
|       _mathObject(0), | ||||
|       _convertToNumber(this), | ||||
|       _convertToString(this), | ||||
|       _convertToObject(this) | ||||
| { | ||||
|  | ||||
|     initializePrototypes(); | ||||
| } | ||||
|  | ||||
| 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 Value *Engine::newArrayValue() { return call(arrayCtor()); } | ||||
|  | ||||
| ObjectValue *Engine::newObject() | ||||
| { | ||||
|     return newObject(_objectPrototype); | ||||
| } | ||||
|  | ||||
| ObjectValue *Engine::newObject(const ObjectValue *prototype) | ||||
| { | ||||
|     ObjectValue *object = new ObjectValue(this); | ||||
|     object->setPrototype(prototype); | ||||
|     _objects.push_back(object); | ||||
|     return object; | ||||
| } | ||||
|  | ||||
| Function *Engine::newFunction() { | ||||
|     Function *function = new Function(this); | ||||
|     function->setPrototype(functionPrototype()); | ||||
|     _objects.push_back(function); | ||||
|     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); } | ||||
|  | ||||
| const Value *Engine::call(const FunctionValue *function, const QList<const Value *> &actuals) | ||||
| { | ||||
|     return call(function, globalObject(), actuals); | ||||
| } | ||||
|  | ||||
| const Value *Engine::call(const FunctionValue *function, const ObjectValue *thisValue, const QList<const Value *> &actuals) | ||||
| { | ||||
|     return function->call(thisValue, actuals); | ||||
| } | ||||
|  | ||||
| void Engine::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount) | ||||
| { | ||||
|     Function *function = newFunction(); | ||||
|     function->setReturnValue(result); | ||||
|     for (int i = 0; i < argumentCount; ++i) | ||||
|         function->addArgument(undefinedValue()); // ### introduce unknownValue | ||||
|     object->setProperty(name, function); | ||||
| } | ||||
|  | ||||
| void Engine::addFunction(ObjectValue *object, const QString &name, int argumentCount) | ||||
| { | ||||
|     Function *function = newFunction(); | ||||
|     for (int i = 0; i < argumentCount; ++i) | ||||
|         function->addArgument(undefinedValue()); // ### introduce unknownValue | ||||
|     object->setProperty(name, function); | ||||
| } | ||||
|  | ||||
| void Engine::initializePrototypes() | ||||
| { | ||||
|     _objectPrototype   = newObject(/*prototype = */ 0); | ||||
|     _functionPrototype = newObject(_objectPrototype); | ||||
|     _numberPrototype   = newObject(_objectPrototype); | ||||
|     _booleanPrototype  = newObject(_objectPrototype); | ||||
|     _stringPrototype   = newObject(_objectPrototype); | ||||
|     _arrayPrototype    = newObject(_objectPrototype); | ||||
|     _datePrototype     = newObject(_objectPrototype); | ||||
|     _regexpPrototype   = newObject(_objectPrototype); | ||||
|  | ||||
|     // set up the Global object | ||||
|     _globalObject = newObject(); | ||||
|     _globalObject->setClassName("Global"); | ||||
|  | ||||
|     // set up the default Object prototype | ||||
|     _objectCtor = new ObjectCtor(this); | ||||
|     _objectCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_objectCtor); | ||||
|     _objectCtor->setProperty("prototype", _objectPrototype); | ||||
|  | ||||
|     _functionCtor = new FunctionCtor(this); | ||||
|     _functionCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_functionCtor); | ||||
|     _functionCtor->setProperty("prototype", _functionPrototype); | ||||
|  | ||||
|     _arrayCtor = new ArrayCtor(this); | ||||
|     _arrayCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_arrayCtor); | ||||
|     _arrayCtor->setProperty("prototype", _arrayPrototype); | ||||
|  | ||||
|     _stringCtor = new StringCtor(this); | ||||
|     _stringCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_stringCtor); | ||||
|     _stringCtor->setProperty("prototype", _stringPrototype); | ||||
|  | ||||
|     _booleanCtor = new BooleanCtor(this); | ||||
|     _booleanCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_booleanCtor); | ||||
|     _booleanCtor->setProperty("prototype", _booleanPrototype); | ||||
|  | ||||
|     _numberCtor = new NumberCtor(this); | ||||
|     _numberCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_numberCtor); | ||||
|     _numberCtor->setProperty("prototype", _numberPrototype); | ||||
|  | ||||
|     _dateCtor = new DateCtor(this); | ||||
|     _dateCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_dateCtor); | ||||
|     _dateCtor->setProperty("prototype", _datePrototype); | ||||
|  | ||||
|     _regexpCtor = new RegExpCtor(this); | ||||
|     _regexpCtor->setPrototype(_functionPrototype); | ||||
|     _objects.push_back(_regexpCtor); | ||||
|     _regexpCtor->setProperty("prototype", _regexpPrototype); | ||||
|  | ||||
|     addFunction(_objectCtor, "getPrototypeOf", 1); | ||||
|     addFunction(_objectCtor, "getOwnPropertyDescriptor", 2); | ||||
|     addFunction(_objectCtor, "getOwnPropertyNames", newArrayValue(), 1); | ||||
|     addFunction(_objectCtor, "create", 1); | ||||
|     addFunction(_objectCtor, "defineProperty", 3); | ||||
|     addFunction(_objectCtor, "defineProperties", 2); | ||||
|     addFunction(_objectCtor, "seal", 1); | ||||
|     addFunction(_objectCtor, "freeze", 1); | ||||
|     addFunction(_objectCtor, "preventExtensions", 1); | ||||
|     addFunction(_objectCtor, "isSealed", booleanValue(), 1); | ||||
|     addFunction(_objectCtor, "isFrozen", booleanValue(), 1); | ||||
|     addFunction(_objectCtor, "isExtensible", booleanValue(), 1); | ||||
|     addFunction(_objectCtor, "keys", newArrayValue(), 1); | ||||
|  | ||||
|     addFunction(_objectPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_objectPrototype, "toLocaleString", stringValue(), 0); | ||||
|     addFunction(_objectPrototype, "valueOf", 0); // ### FIXME it should return thisValue | ||||
|     addFunction(_objectPrototype, "hasOwnProperty", booleanValue(), 1); | ||||
|     addFunction(_objectPrototype, "isPrototypeOf", booleanValue(), 1); | ||||
|     addFunction(_objectPrototype, "propertyIsEnumerable", booleanValue(), 1); | ||||
|  | ||||
|     // set up the default Function prototype | ||||
|     _functionPrototype->setProperty("constructor", _functionCtor); | ||||
|     addFunction(_functionPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_functionPrototype, "apply", 2); | ||||
|     addFunction(_functionPrototype, "call", 1); | ||||
|     addFunction(_functionPrototype, "bind", 1); | ||||
|  | ||||
|     // set up the default Array prototype | ||||
|     addFunction(_arrayCtor, "isArray", booleanValue(), 1); | ||||
|  | ||||
|     _arrayPrototype->setProperty("constructor", _arrayCtor); | ||||
|     addFunction(_arrayPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_arrayPrototype, "toLocalString", stringValue(), 0); | ||||
|     addFunction(_arrayPrototype, "concat", 0); | ||||
|     addFunction(_arrayPrototype, "join", 1); | ||||
|     addFunction(_arrayPrototype, "pop", 0); | ||||
|     addFunction(_arrayPrototype, "push", 0); | ||||
|     addFunction(_arrayPrototype, "reverse", 0); | ||||
|     addFunction(_arrayPrototype, "shift", 0); | ||||
|     addFunction(_arrayPrototype, "slice", 2); | ||||
|     addFunction(_arrayPrototype, "sort", 1); | ||||
|     addFunction(_arrayPrototype, "splice", 2); | ||||
|     addFunction(_arrayPrototype, "unshift", 0); | ||||
|     addFunction(_arrayPrototype, "indexOf", numberValue(), 1); | ||||
|     addFunction(_arrayPrototype, "lastIndexOf", numberValue(), 1); | ||||
|     addFunction(_arrayPrototype, "every", 1); | ||||
|     addFunction(_arrayPrototype, "some", 1); | ||||
|     addFunction(_arrayPrototype, "forEach", 1); | ||||
|     addFunction(_arrayPrototype, "map", 1); | ||||
|     addFunction(_arrayPrototype, "filter", 1); | ||||
|     addFunction(_arrayPrototype, "reduce", 1); | ||||
|     addFunction(_arrayPrototype, "reduceRight", 1); | ||||
|  | ||||
|     // set up the default String prototype | ||||
|     addFunction(_stringCtor, "fromCharCode", stringValue(), 0); | ||||
|  | ||||
|     _stringPrototype->setProperty("constructor", _stringCtor); | ||||
|     addFunction(_stringPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "valueOf", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "charAt", stringValue(), 1); | ||||
|     addFunction(_stringPrototype, "charCodeAt", stringValue(), 1); | ||||
|     addFunction(_stringPrototype, "concat", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "indexOf", numberValue(), 2); | ||||
|     addFunction(_stringPrototype, "lastIndexOf", numberValue(), 2); | ||||
|     addFunction(_stringPrototype, "localeCompare", booleanValue(), 1); | ||||
|     addFunction(_stringPrototype, "match", newArrayValue(), 1); | ||||
|     addFunction(_stringPrototype, "replace", stringValue(), 2); | ||||
|     addFunction(_stringPrototype, "search", numberValue(), 1); | ||||
|     addFunction(_stringPrototype, "slice", stringValue(), 2); | ||||
|     addFunction(_stringPrototype, "split", newArrayValue(), 2); | ||||
|     addFunction(_stringPrototype, "substring", stringValue(), 2); | ||||
|     addFunction(_stringPrototype, "toLowerCase", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "toLocaleLowerCase", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "toUpperCase", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "toLocaleUpperCase", stringValue(), 0); | ||||
|     addFunction(_stringPrototype, "trim", stringValue(), 0); | ||||
|  | ||||
|     // set up the default Boolean prototype | ||||
|     addFunction(_booleanCtor, "fromCharCode", 0); | ||||
|  | ||||
|     _booleanPrototype->setProperty("constructor", _booleanCtor); | ||||
|     addFunction(_booleanPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_booleanPrototype, "valueOf", booleanValue(), 0); | ||||
|  | ||||
|     // set up the default Number prototype | ||||
|     _numberCtor->setProperty("MAX_VALUE", numberValue()); | ||||
|     _numberCtor->setProperty("MIN_VALUE", numberValue()); | ||||
|     _numberCtor->setProperty("NaN", numberValue()); | ||||
|     _numberCtor->setProperty("NEGATIVE_INFINITY", numberValue()); | ||||
|     _numberCtor->setProperty("POSITIVE_INFINITY", numberValue()); | ||||
|  | ||||
|     addFunction(_numberCtor, "fromCharCode", 0); | ||||
|  | ||||
|     _numberPrototype->setProperty("constructor", _numberCtor); | ||||
|     addFunction(_numberPrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_numberPrototype, "toLocaleString", stringValue(), 0); | ||||
|     addFunction(_numberPrototype, "valueOf", numberValue(), 0); | ||||
|     addFunction(_numberPrototype, "toFixed", numberValue(), 1); | ||||
|     addFunction(_numberPrototype, "toExponential", numberValue(), 1); | ||||
|     addFunction(_numberPrototype, "toPrecision", numberValue(), 1); | ||||
|  | ||||
|     // set up the Math object | ||||
|     _mathObject = newObject(); | ||||
|     _mathObject->setProperty("E", numberValue()); | ||||
|     _mathObject->setProperty("LN10", numberValue()); | ||||
|     _mathObject->setProperty("LN2", numberValue()); | ||||
|     _mathObject->setProperty("LOG2E", numberValue()); | ||||
|     _mathObject->setProperty("LOG10E", numberValue()); | ||||
|     _mathObject->setProperty("PI", numberValue()); | ||||
|     _mathObject->setProperty("SQRT1_2", numberValue()); | ||||
|     _mathObject->setProperty("SQRT2", numberValue()); | ||||
|  | ||||
|     addFunction(_mathObject, "abs", numberValue(), 1); | ||||
|     addFunction(_mathObject, "acos", numberValue(), 1); | ||||
|     addFunction(_mathObject, "asin", numberValue(), 1); | ||||
|     addFunction(_mathObject, "atan", numberValue(), 1); | ||||
|     addFunction(_mathObject, "atan2", numberValue(), 2); | ||||
|     addFunction(_mathObject, "ceil", numberValue(), 1); | ||||
|     addFunction(_mathObject, "cos", numberValue(), 1); | ||||
|     addFunction(_mathObject, "exp", numberValue(), 1); | ||||
|     addFunction(_mathObject, "floor", numberValue(), 1); | ||||
|     addFunction(_mathObject, "log", numberValue(), 1); | ||||
|     addFunction(_mathObject, "max", numberValue(), 1); | ||||
|     addFunction(_mathObject, "min", numberValue(), 1); | ||||
|     addFunction(_mathObject, "pow", numberValue(), 2); | ||||
|     addFunction(_mathObject, "random", numberValue(), 1); | ||||
|     addFunction(_mathObject, "round", numberValue(), 1); | ||||
|     addFunction(_mathObject, "sin", numberValue(), 1); | ||||
|     addFunction(_mathObject, "sqrt", numberValue(), 1); | ||||
|     addFunction(_mathObject, "tan", numberValue(), 1); | ||||
|  | ||||
|     // set up the default Boolean prototype | ||||
|     addFunction(_dateCtor, "parse", numberValue(), 1); | ||||
|     addFunction(_dateCtor, "now", numberValue(), 0); | ||||
|  | ||||
|     _datePrototype->setProperty("constructor", _dateCtor); | ||||
|     addFunction(_datePrototype, "toString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toDateString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toTimeString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toLocaleString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toLocaleDateString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toLocaleTimeString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "valueOf", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getTime", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getFullYear", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCFullYear", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getMonth", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCMonth", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getDate", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCDate", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getHours", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCHours", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getMinutes", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCMinutes", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getSeconds", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCSeconds", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getMilliseconds", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getUTCMilliseconds", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "getTimezoneOffset", numberValue(), 0); | ||||
|     addFunction(_datePrototype, "setTime", 1); | ||||
|     addFunction(_datePrototype, "setMilliseconds", 1); | ||||
|     addFunction(_datePrototype, "setUTCMilliseconds", 1); | ||||
|     addFunction(_datePrototype, "setSeconds", 1); | ||||
|     addFunction(_datePrototype, "setUTCSeconds", 1); | ||||
|     addFunction(_datePrototype, "setMinutes", 1); | ||||
|     addFunction(_datePrototype, "setUTCMinutes", 1); | ||||
|     addFunction(_datePrototype, "setHours", 1); | ||||
|     addFunction(_datePrototype, "setUTCHours", 1); | ||||
|     addFunction(_datePrototype, "setDate", 1); | ||||
|     addFunction(_datePrototype, "setUTCDate", 1); | ||||
|     addFunction(_datePrototype, "setMonth", 1); | ||||
|     addFunction(_datePrototype, "setUTCMonth", 1); | ||||
|     addFunction(_datePrototype, "setFullYear", 1); | ||||
|     addFunction(_datePrototype, "setUTCFullYear", 1); | ||||
|     addFunction(_datePrototype, "toUTCString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toISOString", stringValue(), 0); | ||||
|     addFunction(_datePrototype, "toJSON", stringValue(), 1); | ||||
|  | ||||
|     // set up the default Boolean prototype | ||||
|     _regexpPrototype->setProperty("constructor", _regexpCtor); | ||||
|     addFunction(_regexpPrototype, "exec", newArrayValue(), 1); | ||||
|     addFunction(_regexpPrototype, "test", booleanValue(), 1); | ||||
|     addFunction(_regexpPrototype, "toString", stringValue(), 0); | ||||
|  | ||||
|     // fill the Global object | ||||
|     _globalObject->setProperty("Math", _mathObject); | ||||
|     _globalObject->setProperty("Object", objectCtor()); | ||||
|     _globalObject->setProperty("Function", functionCtor()); | ||||
|     _globalObject->setProperty("Array", arrayCtor()); | ||||
|     _globalObject->setProperty("String", stringCtor()); | ||||
|     _globalObject->setProperty("Boolean", booleanCtor()); | ||||
|     _globalObject->setProperty("Number", numberCtor()); | ||||
|     _globalObject->setProperty("Date", dateCtor()); | ||||
|     _globalObject->setProperty("RegExp", regexpCtor()); | ||||
| } | ||||
|  | ||||
| const Value *FunctionValue::call(const Value *thisValue, const QList<const Value *> & /*actuals*/) const | ||||
| { | ||||
|     return thisValue; // ### FIXME: it should return undefined | ||||
| } | ||||
|  | ||||
| const Value *FunctionValue::argument(int /*index*/) const | ||||
| { | ||||
|     return engine()->undefinedValue(); | ||||
| } | ||||
|  | ||||
| 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 | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| void ConvertToNumber::visit(const NullValue *) | ||||
| { | ||||
|     _result = _engine->numberValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToNumber::visit(const UndefinedValue *) | ||||
| { | ||||
|     _result = _engine->numberValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToNumber::visit(const NumberValue *value) | ||||
| { | ||||
|     _result = value; | ||||
| } | ||||
|  | ||||
| void ConvertToNumber::visit(const BooleanValue *) | ||||
| { | ||||
|     _result = _engine->numberValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToNumber::visit(const StringValue *) | ||||
| { | ||||
|     _result = _engine->numberValue(); | ||||
| } | ||||
|  | ||||
| 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? | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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? | ||||
|     } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // convert to string | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| void ConvertToString::visit(const NullValue *) | ||||
| { | ||||
|     _result = _engine->stringValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToString::visit(const UndefinedValue *) | ||||
| { | ||||
|     _result = _engine->stringValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToString::visit(const NumberValue *) | ||||
| { | ||||
|     _result = _engine->stringValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToString::visit(const BooleanValue *) | ||||
| { | ||||
|     _result = _engine->stringValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToString::visit(const StringValue *value) | ||||
| { | ||||
|     _result = 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? | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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? | ||||
|     } | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // convert to object | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| void ConvertToObject::visit(const NullValue *value) | ||||
| { | ||||
|     _result = value; | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const UndefinedValue *) | ||||
| { | ||||
|     _result = _engine->nullValue(); | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const NumberValue *) | ||||
| { | ||||
|     _result = _engine->call(_engine->numberCtor()); | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const BooleanValue *) | ||||
| { | ||||
|     _result = _engine->call(_engine->booleanCtor()); | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const StringValue *) | ||||
| { | ||||
|     _result = _engine->call(_engine->stringCtor()); | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const ObjectValue *object) | ||||
| { | ||||
|     _result = object; | ||||
| } | ||||
|  | ||||
| void ConvertToObject::visit(const FunctionValue *object) | ||||
| { | ||||
|     _result = object; | ||||
| } | ||||
|  | ||||
							
								
								
									
										476
									
								
								src/libs/qmljs/qmljsinterpreter.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										476
									
								
								src/libs/qmljs/qmljsinterpreter.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,476 @@ | ||||
| /************************************************************************** | ||||
| ** | ||||
| ** This file is part of Qt Creator | ||||
| ** | ||||
| ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). | ||||
| ** | ||||
| ** Contact: Nokia Corporation (qt-info@nokia.com) | ||||
| ** | ||||
| ** Commercial Usage | ||||
| ** | ||||
| ** Licensees holding valid Qt Commercial licenses may use this file in | ||||
| ** accordance with the Qt Commercial License Agreement provided with the | ||||
| ** Software or, alternatively, in accordance with the terms contained in | ||||
| ** a written agreement between you and Nokia. | ||||
| ** | ||||
| ** GNU Lesser General Public License Usage | ||||
| ** | ||||
| ** Alternatively, this file may be used under the terms of the GNU Lesser | ||||
| ** General Public License version 2.1 as published by the Free Software | ||||
| ** Foundation and appearing in the file LICENSE.LGPL included in the | ||||
| ** packaging of this file.  Please review the following information to | ||||
| ** ensure the GNU Lesser General Public License version 2.1 requirements | ||||
| ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||||
| ** | ||||
| ** If you are unsure which license is appropriate for your use, please | ||||
| ** contact the sales department at http://qt.nokia.com/contact. | ||||
| ** | ||||
| **************************************************************************/ | ||||
|  | ||||
| #ifndef QMLJS_INTERPRETER_H | ||||
| #define QMLJS_INTERPRETER_H | ||||
|  | ||||
| #include "qmljs_global.h" | ||||
|  | ||||
| #include <QtCore/QList> | ||||
| #include <QtCore/QString> | ||||
| #include <QtCore/QHash> | ||||
| #include <QtCore/QSet> | ||||
|  | ||||
| namespace QmlJS { | ||||
| namespace Interpreter { | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Forward declarations | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| class Engine; | ||||
| class Value; | ||||
| class NullValue; | ||||
| class UndefinedValue; | ||||
| class NumberValue; | ||||
| class BooleanValue; | ||||
| class StringValue; | ||||
| class ObjectValue; | ||||
| class FunctionValue; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Value visitor | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| class QMLJS_EXPORT ValueVisitor | ||||
| { | ||||
| public: | ||||
|     ValueVisitor(); | ||||
|     virtual ~ValueVisitor(); | ||||
|  | ||||
|     virtual void visit(const NullValue *); | ||||
|     virtual void visit(const UndefinedValue *); | ||||
|     virtual void visit(const NumberValue *); | ||||
|     virtual void visit(const BooleanValue *); | ||||
|     virtual void visit(const StringValue *); | ||||
|     virtual void visit(const ObjectValue *); | ||||
|     virtual void visit(const FunctionValue *); | ||||
| }; | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // QML/JS value | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| class QMLJS_EXPORT Value | ||||
| { | ||||
|     Value(const Value &other); | ||||
|     void operator = (const Value &other); | ||||
|  | ||||
| public: | ||||
|     Value(); | ||||
|     virtual ~Value(); | ||||
|  | ||||
|     virtual const NullValue *asNullValue() const; | ||||
|     virtual const UndefinedValue *asUndefinedValue() const; | ||||
|     virtual const NumberValue *asNumberValue() const; | ||||
|     virtual const BooleanValue *asBooleanValue() const; | ||||
|     virtual const StringValue *asStringValue() const; | ||||
|     virtual const ObjectValue *asObjectValue() const; | ||||
|     virtual const FunctionValue *asFunctionValue() const; | ||||
|  | ||||
|     virtual void accept(ValueVisitor *) const = 0; | ||||
| }; | ||||
|  | ||||
| template <typename _RetTy> _RetTy value_cast(const Value *v); | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const NullValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asNullValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const UndefinedValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asUndefinedValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const NumberValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asNumberValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const BooleanValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asBooleanValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const StringValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asStringValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const ObjectValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asObjectValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| template <> Q_INLINE_TEMPLATE const FunctionValue *value_cast(const Value *v) | ||||
| { | ||||
|     if (v) return v->asFunctionValue(); | ||||
|     else   return 0; | ||||
| } | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Execution environment | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| class QMLJS_EXPORT Environment | ||||
| { | ||||
| public: | ||||
|     Environment(); | ||||
|     virtual ~Environment(); | ||||
|  | ||||
|     virtual const Environment *parent() const; | ||||
|     virtual const Value *lookup(const QString &name) const; | ||||
|     virtual const Value *lookupMember(const QString &name) const; | ||||
| }; | ||||
|  | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // Value nodes | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| class QMLJS_EXPORT NullValue: public Value | ||||
| { | ||||
| public: | ||||
|     virtual const NullValue *asNullValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT UndefinedValue: public Value | ||||
| { | ||||
| public: | ||||
|     virtual const UndefinedValue *asUndefinedValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT NumberValue: public Value | ||||
| { | ||||
| public: | ||||
|     virtual const NumberValue *asNumberValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT BooleanValue: public Value | ||||
| { | ||||
| public: | ||||
|     virtual const BooleanValue *asBooleanValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT StringValue: public Value | ||||
| { | ||||
| public: | ||||
|     virtual const StringValue *asStringValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT ObjectValue: public Value, public Environment | ||||
| { | ||||
| public: | ||||
|     ObjectValue(Engine *engine); | ||||
|  | ||||
|     Engine *engine() const; | ||||
|  | ||||
|     QString className() const; | ||||
|     void setClassName(const QString &className); | ||||
|  | ||||
|     const ObjectValue *prototype() const; | ||||
|     void setPrototype(const ObjectValue *prototype); | ||||
|  | ||||
|     const ObjectValue *scope() const; | ||||
|     void setScope(const ObjectValue *scope); | ||||
|  | ||||
|     typedef QHash<QString, const Value *>::const_iterator MemberIterator; | ||||
|  | ||||
|     MemberIterator firstMember() const; | ||||
|     MemberIterator lastMember() 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; | ||||
|     virtual const Value *lookupMember(const QString &name) const; | ||||
|  | ||||
|     // Value interface | ||||
|     virtual const ObjectValue *asObjectValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
|  | ||||
| private: | ||||
|     bool isValidPrototype(const ObjectValue *prototype, QSet<const ObjectValue *> *processed) const; | ||||
|  | ||||
| private: | ||||
|     Engine *_engine; | ||||
|     const ObjectValue *_prototype; | ||||
|     const ObjectValue *_scope; | ||||
|     QHash<QString, const Value *> _members; | ||||
|     QString _className; | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT FunctionValue: public ObjectValue | ||||
| { | ||||
| public: | ||||
|     FunctionValue(Engine *engine); | ||||
|  | ||||
|     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*/ = QList<const Value *>()) const; | ||||
|  | ||||
|     // Value interface | ||||
|     virtual const FunctionValue *asFunctionValue() const; | ||||
|     virtual void accept(ValueVisitor *visitor) const; | ||||
| }; | ||||
|  | ||||
| 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 setReturnValue(const Value *returnValue); | ||||
|  | ||||
|     // ObjectValue interface | ||||
|     virtual const Value *property(const QString &name) const; | ||||
|  | ||||
|     // FunctionValue interface | ||||
|     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; | ||||
|  | ||||
| private: | ||||
|     QList<const Value *> _arguments; | ||||
|     const Value *_returnValue; | ||||
| }; | ||||
|  | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
| // typing environment | ||||
| //////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| class ConvertToNumber: protected ValueVisitor // ECMAScript ToInt() | ||||
| { | ||||
| public: | ||||
|     ConvertToNumber(Engine *engine); | ||||
|  | ||||
|     const Value *operator()(const Value *value); | ||||
|  | ||||
| protected: | ||||
|     const Value *switchResult(const Value *value); | ||||
|  | ||||
|     virtual void visit(const NullValue *); | ||||
|     virtual void visit(const UndefinedValue *); | ||||
|     virtual void visit(const NumberValue *); | ||||
|     virtual void visit(const BooleanValue *); | ||||
|     virtual void visit(const StringValue *); | ||||
|     virtual void visit(const ObjectValue *); | ||||
|     virtual void visit(const FunctionValue *); | ||||
|  | ||||
| private: | ||||
|     Engine *_engine; | ||||
|     const Value *_result; | ||||
| }; | ||||
|  | ||||
| class ConvertToString: protected ValueVisitor // ECMAScript ToString | ||||
| { | ||||
| public: | ||||
|     ConvertToString(Engine *engine); | ||||
|  | ||||
|     const Value *operator()(const Value *value); | ||||
|  | ||||
| protected: | ||||
|     const Value *switchResult(const Value *value); | ||||
|  | ||||
|     virtual void visit(const NullValue *); | ||||
|     virtual void visit(const UndefinedValue *); | ||||
|     virtual void visit(const NumberValue *); | ||||
|     virtual void visit(const BooleanValue *); | ||||
|     virtual void visit(const StringValue *); | ||||
|     virtual void visit(const ObjectValue *); | ||||
|     virtual void visit(const FunctionValue *); | ||||
|  | ||||
| private: | ||||
|     Engine *_engine; | ||||
|     const Value *_result; | ||||
| }; | ||||
|  | ||||
| class ConvertToObject: protected ValueVisitor // ECMAScript ToObject | ||||
| { | ||||
| public: | ||||
|     ConvertToObject(Engine *engine); | ||||
|  | ||||
|     const Value *operator()(const Value *value); | ||||
|  | ||||
| protected: | ||||
|     const Value *switchResult(const Value *value); | ||||
|  | ||||
|     virtual void visit(const NullValue *); | ||||
|     virtual void visit(const UndefinedValue *); | ||||
|     virtual void visit(const NumberValue *); | ||||
|     virtual void visit(const BooleanValue *); | ||||
|     virtual void visit(const StringValue *); | ||||
|     virtual void visit(const ObjectValue *); | ||||
|     virtual void visit(const FunctionValue *); | ||||
|  | ||||
| private: | ||||
|     Engine *_engine; | ||||
|     const Value *_result; | ||||
| }; | ||||
|  | ||||
| class TypeId: protected ValueVisitor | ||||
| { | ||||
|     QString _result; | ||||
|  | ||||
| public: | ||||
|     QString operator()(const Value *value); | ||||
|  | ||||
| protected: | ||||
|     virtual void visit(const NullValue *); | ||||
|     virtual void visit(const UndefinedValue *); | ||||
|     virtual void visit(const NumberValue *); | ||||
|     virtual void visit(const BooleanValue *); | ||||
|     virtual void visit(const StringValue *); | ||||
|     virtual void visit(const ObjectValue *object); | ||||
|     virtual void visit(const FunctionValue *object); | ||||
| }; | ||||
|  | ||||
| class QMLJS_EXPORT Engine | ||||
| { | ||||
|     Engine(const Engine &other); | ||||
|     void operator = (const Engine &other); | ||||
|  | ||||
| public: | ||||
|     Engine(); | ||||
|     ~Engine(); | ||||
|  | ||||
|     const NullValue *nullValue() const; | ||||
|     const UndefinedValue *undefinedValue() const; | ||||
|     const NumberValue *numberValue() const; | ||||
|     const BooleanValue *booleanValue() const; | ||||
|     const StringValue *stringValue() const; | ||||
|  | ||||
|     const Value *newArrayValue(); // ### remove me | ||||
|  | ||||
|     ObjectValue *newObject(); | ||||
|     Function *newFunction(); | ||||
|  | ||||
|     // global object | ||||
|     ObjectValue *globalObject() const; | ||||
|     const ObjectValue *mathObject() const; | ||||
|  | ||||
|     // prototypes | ||||
|     ObjectValue *objectPrototype() const; | ||||
|     ObjectValue *functionPrototype() const; | ||||
|     ObjectValue *numberPrototype() const; | ||||
|     ObjectValue *booleanPrototype() const; | ||||
|     ObjectValue *stringPrototype() const; | ||||
|     ObjectValue *arrayPrototype() const; | ||||
|     ObjectValue *datePrototype() const; | ||||
|     ObjectValue *regexpPrototype() const; | ||||
|  | ||||
|     // ctors | ||||
|     const FunctionValue *objectCtor() const; | ||||
|     const FunctionValue *functionCtor() const; | ||||
|     const FunctionValue *arrayCtor() const; | ||||
|     const FunctionValue *stringCtor() const; | ||||
|     const FunctionValue *booleanCtor() const; | ||||
|     const FunctionValue *numberCtor() const; | ||||
|     const FunctionValue *dateCtor() const; | ||||
|     const FunctionValue *regexpCtor() const; | ||||
|  | ||||
|     // operators | ||||
|     const Value *convertToBool(const Value *value); | ||||
|     const Value *convertToNumber(const Value *value); | ||||
|     const Value *convertToString(const Value *value); | ||||
|     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(); | ||||
|  | ||||
|     ObjectValue *newObject(const ObjectValue *prototype); | ||||
|  | ||||
|     void addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount); | ||||
|     void addFunction(ObjectValue *object, const QString &name, int argumentCount); | ||||
|  | ||||
| private: | ||||
|     ObjectValue *_objectPrototype; | ||||
|     ObjectValue *_functionPrototype; | ||||
|     ObjectValue *_numberPrototype; | ||||
|     ObjectValue *_booleanPrototype; | ||||
|     ObjectValue *_stringPrototype; | ||||
|     ObjectValue *_arrayPrototype; | ||||
|     ObjectValue *_datePrototype; | ||||
|     ObjectValue *_regexpPrototype; | ||||
|  | ||||
|     Function *_objectCtor; | ||||
|     Function *_functionCtor; | ||||
|     Function *_arrayCtor; | ||||
|     Function *_stringCtor; | ||||
|     Function *_booleanCtor; | ||||
|     Function *_numberCtor; | ||||
|     Function *_dateCtor; | ||||
|     Function *_regexpCtor; | ||||
|  | ||||
|     ObjectValue *_globalObject; | ||||
|     ObjectValue *_mathObject; | ||||
|  | ||||
|     NullValue _nullValue; | ||||
|     UndefinedValue _undefinedValue; | ||||
|     NumberValue _numberValue; | ||||
|     BooleanValue _booleanValue; | ||||
|     StringValue _stringValue; | ||||
|     QList<ObjectValue *> _objects; | ||||
|  | ||||
|     ConvertToNumber _convertToNumber; | ||||
|     ConvertToString _convertToString; | ||||
|     ConvertToObject _convertToObject; | ||||
|     TypeId _typeId; | ||||
| }; | ||||
|  | ||||
| } } // end of namespace QmlJS::Interpreter | ||||
|  | ||||
| #endif // QMLJS_INTERPRETER_H | ||||
		Reference in New Issue
	
	Block a user