diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri index 3e89cabfe42ffe70f412e220722dc0db48f33021..aaa9cacbb3823b6230a29cefbb28b940437fe5f7 100644 --- a/src/libs/qmljs/qmljs-lib.pri +++ b/src/libs/qmljs/qmljs-lib.pri @@ -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 diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..349ec8efa609fbb75e29910047bb1db6f38a3034 --- /dev/null +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -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; +} + diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h new file mode 100644 index 0000000000000000000000000000000000000000..a5db9614e9ebb5f1449503eb9afdddff0e43adb2 --- /dev/null +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -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