1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qdeclarativescript_p.h"
44 #include "parser/qdeclarativejsengine_p.h"
45 #include "parser/qdeclarativejsparser_p.h"
46 #include "parser/qdeclarativejslexer_p.h"
47 #include "parser/qdeclarativejsmemorypool_p.h"
48 #include "parser/qdeclarativejsastvisitor_p.h"
49 #include "parser/qdeclarativejsast_p.h"
50 #include "private/qdeclarativerewrite_p.h"
53 #include <QCoreApplication>
58 using namespace QDeclarativeJS;
59 using namespace QDeclarativeScript;
64 QDeclarativeScript::Object::Object()
65 : type(-1), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), parserStatusCast(-1),
66 componentCompileState(0), nextAliasingObject(0), nextIdObject(0)
70 QDeclarativeScript::Object::~Object()
72 if (synthCache) synthCache->release();
75 void Object::setBindingBit(int b)
77 while (bindingBitmask.size() < 4 * (1 + b / 32))
78 bindingBitmask.append(char(0));
80 quint32 *bits = (quint32 *)bindingBitmask.data();
81 bits[b / 32] |= (1 << (b % 32));
84 const QMetaObject *Object::metaObject() const
86 if (!metadata.isEmpty() && metatype)
92 QDeclarativeScript::Property *Object::getDefaultProperty()
94 if (!defaultProperty) {
95 defaultProperty = pool()->New<Property>();
96 defaultProperty->parent = this;
98 return defaultProperty;
101 void QDeclarativeScript::Object::addValueProperty(Property *p)
103 valueProperties.append(p);
106 void QDeclarativeScript::Object::addSignalProperty(Property *p)
108 signalProperties.append(p);
111 void QDeclarativeScript::Object::addAttachedProperty(Property *p)
113 attachedProperties.append(p);
116 void QDeclarativeScript::Object::addGroupedProperty(Property *p)
118 groupedProperties.append(p);
121 void QDeclarativeScript::Object::addValueTypeProperty(Property *p)
123 valueTypeProperties.append(p);
126 void QDeclarativeScript::Object::addScriptStringProperty(Property *p)
128 scriptStringProperties.append(p);
131 // This lookup is optimized for missing, and having to create a new property.
132 Property *QDeclarativeScript::Object::getProperty(const QHashedStringRef &name, bool create)
135 quint32 h = name.hash();
136 if (propertiesHashField.testAndSet(h)) {
137 for (Property *p = properties.first(); p; p = properties.next(p)) {
138 if (p->name() == name)
143 Property *property = pool()->New<Property>();
144 property->parent = this;
145 property->_name = name;
146 property->isDefault = false;
147 properties.prepend(property);
150 for (Property *p = properties.first(); p; p = properties.next(p)) {
151 if (p->name() == name)
159 Property *QDeclarativeScript::Object::getProperty(const QStringRef &name, bool create)
161 return getProperty(QHashedStringRef(name), create);
164 Property *QDeclarativeScript::Object::getProperty(const QString &name, bool create)
166 for (Property *p = properties.first(); p; p = properties.next(p)) {
167 if (p->name() == name)
172 Property *property = pool()->New<Property>();
173 property->parent = this;
174 property->_name = QStringRef(pool()->NewString(name));
175 propertiesHashField.testAndSet(property->_name.hash());
176 property->isDefault = false;
177 properties.prepend(property);
184 QDeclarativeScript::Object::DynamicProperty::DynamicProperty()
185 : isDefaultProperty(false), type(Variant), defaultValue(0), nextProperty(0),
186 resolvedCustomTypeName(0)
190 QDeclarativeScript::Object::DynamicSignal::DynamicSignal()
195 // Returns length in utf8 bytes
196 int QDeclarativeScript::Object::DynamicSignal::parameterTypesLength() const
199 for (int ii = 0; ii < parameterTypes.count(); ++ii)
200 rv += parameterTypes.at(ii).length();
204 // Returns length in utf8 bytes
205 int QDeclarativeScript::Object::DynamicSignal::parameterNamesLength() const
208 for (int ii = 0; ii < parameterNames.count(); ++ii)
209 rv += parameterNames.at(ii).utf8length();
213 QDeclarativeScript::Object::DynamicSlot::DynamicSlot()
218 int QDeclarativeScript::Object::DynamicSlot::parameterNamesLength() const
221 for (int ii = 0; ii < parameterNames.count(); ++ii)
222 rv += parameterNames.at(ii).length();
226 QDeclarativeScript::Property::Property()
227 : parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false),
228 isValueTypeSubProperty(false), isAlias(false), scriptStringScope(-1),
229 nextMainProperty(0), nextProperty(0)
233 QDeclarativeScript::Object *QDeclarativeScript::Property::getValue(const LocationSpan &l)
235 if (!value) { value = pool()->New<Object>(); value->location = l; }
239 void QDeclarativeScript::Property::addValue(Value *v)
244 void QDeclarativeScript::Property::addOnValue(Value *v)
249 bool QDeclarativeScript::Property::isEmpty() const
251 return !value && values.isEmpty() && onValues.isEmpty();
254 QDeclarativeScript::Value::Value()
255 : type(Unknown), object(0), bindingReference(0), signalExpressionContextStack(0), nextValue(0)
259 QDeclarativeScript::Variant::Variant()
264 QDeclarativeScript::Variant::Variant(const Variant &o)
265 : t(o.t), d(o.d), asWritten(o.asWritten)
269 QDeclarativeScript::Variant::Variant(bool v)
274 QDeclarativeScript::Variant::Variant(double v, const QStringRef &asWritten)
275 : t(Number), d(v), asWritten(asWritten)
279 QDeclarativeScript::Variant::Variant(QDeclarativeJS::AST::StringLiteral *v)
284 QDeclarativeScript::Variant::Variant(const QStringRef &asWritten, QDeclarativeJS::AST::Node *n)
285 : t(Script), n(n), asWritten(asWritten)
289 QDeclarativeScript::Variant &QDeclarativeScript::Variant::operator=(const Variant &o)
293 asWritten = o.asWritten;
297 QDeclarativeScript::Variant::Type QDeclarativeScript::Variant::type() const
302 bool QDeclarativeScript::Variant::asBoolean() const
307 QString QDeclarativeScript::Variant::asString() const
311 return l->value.toString();
313 return asWritten.toString();
317 double QDeclarativeScript::Variant::asNumber() const
322 //reverse of Lexer::singleEscape()
323 QString escapedString(const QString &string)
325 QString tmp = QLatin1String("\"");
326 for (int i = 0; i < string.length(); ++i) {
327 const QChar &c = string.at(i);
328 switch(c.unicode()) {
330 tmp += QLatin1String("\\b");
333 tmp += QLatin1String("\\t");
336 tmp += QLatin1String("\\n");
339 tmp += QLatin1String("\\v");
342 tmp += QLatin1String("\\f");
345 tmp += QLatin1String("\\r");
348 tmp += QLatin1String("\\\"");
351 tmp += QLatin1String("\\\'");
354 tmp += QLatin1String("\\\\");
361 tmp += QLatin1Char('\"');
365 QString QDeclarativeScript::Variant::asScript() const
372 return b?QLatin1String("true"):QLatin1String("false");
374 if (asWritten.isEmpty())
375 return QString::number(d);
377 return asWritten.toString();
379 return escapedString(asString());
381 if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(n)) {
383 return i->name.toString();
385 return asWritten.toString();
389 QDeclarativeJS::AST::Node *QDeclarativeScript::Variant::asAST() const
391 if (type() == Script)
397 bool QDeclarativeScript::Variant::isStringList() const
402 if (type() != Script || !n)
405 AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
409 AST::ElementList *elements = array->elements;
413 if (!AST::cast<AST::StringLiteral *>(elements->expression))
416 elements = elements->next;
422 QStringList QDeclarativeScript::Variant::asStringList() const
430 AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
434 AST::ElementList *elements = array->elements;
437 AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression);
439 return QStringList();
440 rv.append(string->value.toString());
442 elements = elements->next;
449 // Actual parser classes
451 void QDeclarativeScript::Import::extractVersion(int *maj, int *min) const
453 *maj = -1; *min = -1;
455 if (!version.isEmpty()) {
456 int dot = version.indexOf(QLatin1Char('.'));
458 *maj = version.toInt();
461 *maj = version.left(dot).toInt();
462 *min = version.mid(dot+1).toInt();
469 class ProcessAST: protected AST::Visitor
472 State() : object(0), property(0) {}
473 State(QDeclarativeScript::Object *o) : object(o), property(0) {}
474 State(QDeclarativeScript::Object *o, Property *p) : object(o), property(p) {}
476 QDeclarativeScript::Object *object;
480 struct StateStack : public QStack<State>
482 void pushObject(QDeclarativeScript::Object *obj)
487 void pushProperty(const QString &name, const LocationSpan &location)
489 const State &state = top();
490 if (state.property) {
491 State s(state.property->getValue(location),
492 state.property->getValue(location)->getProperty(name));
493 s.property->location = location;
496 State s(state.object, state.object->getProperty(name));
498 s.property->location = location;
503 void pushProperty(const QStringRef &name, const LocationSpan &location)
505 const State &state = top();
506 if (state.property) {
507 State s(state.property->getValue(location),
508 state.property->getValue(location)->getProperty(name));
509 s.property->location = location;
512 State s(state.object, state.object->getProperty(name));
514 s.property->location = location;
521 ProcessAST(QDeclarativeScript::Parser *parser);
522 virtual ~ProcessAST();
524 void operator()(const QString &code, AST::Node *node);
528 QDeclarativeScript::Object *defineObjectBinding(AST::UiQualifiedId *propertyName, bool onAssignment,
529 const QString &objectType,
530 AST::SourceLocation typeLocation,
531 LocationSpan location,
532 AST::UiObjectInitializer *initializer = 0);
534 QDeclarativeScript::Variant getVariant(AST::Statement *stmt);
535 QDeclarativeScript::Variant getVariant(AST::ExpressionNode *expr);
537 LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
538 LocationSpan location(AST::UiQualifiedId *);
540 using AST::Visitor::visit;
541 using AST::Visitor::endVisit;
543 virtual bool visit(AST::UiProgram *node);
544 virtual bool visit(AST::UiImport *node);
545 virtual bool visit(AST::UiObjectDefinition *node);
546 virtual bool visit(AST::UiPublicMember *node);
547 virtual bool visit(AST::UiObjectBinding *node);
549 virtual bool visit(AST::UiScriptBinding *node);
550 virtual bool visit(AST::UiArrayBinding *node);
551 virtual bool visit(AST::UiSourceElement *node);
553 void accept(AST::Node *node);
555 QString asString(AST::UiQualifiedId *node) const;
557 const State state() const;
558 QDeclarativeScript::Object *currentObject() const;
559 Property *currentProperty() const;
561 QString qualifiedNameId() const;
563 QString textAt(const AST::SourceLocation &loc) const
564 { return _contents->mid(loc.offset, loc.length); }
566 QStringRef textRefAt(const AST::SourceLocation &loc) const
567 { return QStringRef(_contents, loc.offset, loc.length); }
569 QString textAt(const AST::SourceLocation &first,
570 const AST::SourceLocation &last) const
571 { return _contents->mid(first.offset, last.offset + last.length - first.offset); }
573 QStringRef textRefAt(const AST::SourceLocation &first,
574 const AST::SourceLocation &last) const
575 { return QStringRef(_contents, first.offset, last.offset + last.length - first.offset); }
577 QString asString(AST::ExpressionNode *expr)
582 return textAt(expr->firstSourceLocation(), expr->lastSourceLocation());
585 QStringRef asStringRef(AST::ExpressionNode *expr)
590 return textRefAt(expr->firstSourceLocation(), expr->lastSourceLocation());
593 QString asString(AST::Statement *stmt)
598 QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
599 s += QLatin1Char('\n');
603 QStringRef asStringRef(AST::Statement *stmt)
608 return textRefAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
612 QDeclarativeScript::Parser *_parser;
613 StateStack _stateStack;
615 const QString *_contents;
618 ProcessAST::ProcessAST(QDeclarativeScript::Parser *parser)
623 ProcessAST::~ProcessAST()
627 void ProcessAST::operator()(const QString &code, AST::Node *node)
633 void ProcessAST::accept(AST::Node *node)
635 AST::Node::acceptChild(node, this);
638 const ProcessAST::State ProcessAST::state() const
640 if (_stateStack.isEmpty())
643 return _stateStack.back();
646 QDeclarativeScript::Object *ProcessAST::currentObject() const
648 return state().object;
651 Property *ProcessAST::currentProperty() const
653 return state().property;
656 QString ProcessAST::qualifiedNameId() const
658 return _scope.join(QLatin1String("/"));
661 QString ProcessAST::asString(AST::UiQualifiedId *node) const
665 for (AST::UiQualifiedId *it = node; it; it = it->next) {
666 s.append(it->name.toString());
669 s.append(QLatin1Char('.'));
675 QDeclarativeScript::Object *
676 ProcessAST::defineObjectBinding(AST::UiQualifiedId *propertyName,
678 const QString &objectType,
679 AST::SourceLocation typeLocation,
680 LocationSpan location,
681 AST::UiObjectInitializer *initializer)
683 int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.'));
684 bool isType = !objectType.isEmpty() &&
685 (objectType.at(0).isUpper() ||
686 (lastTypeDot >= 0 && objectType.at(lastTypeDot+1).isUpper()));
688 int propertyCount = 0;
689 for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
691 _stateStack.pushProperty(name->name,
692 this->location(name));
695 if (!onAssignment && propertyCount && currentProperty() && !currentProperty()->values.isEmpty()) {
696 QDeclarativeError error;
697 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
698 error.setLine(this->location(propertyName).start.line);
699 error.setColumn(this->location(propertyName).start.column);
700 _parser->_errors << error;
706 if(propertyCount || !currentObject()) {
707 QDeclarativeError error;
708 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected type name"));
709 error.setLine(typeLocation.startLine);
710 error.setColumn(typeLocation.startColumn);
711 _parser->_errors << error;
715 LocationSpan loc = ProcessAST::location(typeLocation, typeLocation);
717 loc = ProcessAST::location(propertyName);
719 _stateStack.pushProperty(objectType, loc);
728 QString resolvableObjectType = objectType;
729 if (lastTypeDot >= 0)
730 resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/'));
732 QDeclarativeScript::Object *obj = _parser->_pool.New<QDeclarativeScript::Object>();
734 QDeclarativeScript::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType);
735 obj->type = typeRef->id;
737 typeRef->refObjects.append(obj);
739 // XXX this doesn't do anything (_scope never builds up)
740 _scope.append(resolvableObjectType);
741 obj->typeName = qualifiedNameId().toUtf8();
744 obj->location = location;
747 Property *prop = currentProperty();
748 QDeclarativeScript::Value *v = _parser->_pool.New<QDeclarativeScript::Value>();
750 v->location = obj->location;
756 while (propertyCount--)
761 if (! _parser->tree()) {
762 _parser->setTree(obj);
764 const State state = _stateStack.top();
765 QDeclarativeScript::Value *v = _parser->_pool.New<QDeclarativeScript::Value>();
767 v->location = obj->location;
768 if (state.property) {
769 state.property->addValue(v);
771 Property *defaultProp = state.object->getDefaultProperty();
772 if (defaultProp->location.start.line == -1) {
773 defaultProp->location = v->location;
774 defaultProp->location.end = defaultProp->location.start;
775 defaultProp->location.range.length = 0;
777 defaultProp->addValue(v);
782 _stateStack.pushObject(obj);
790 LocationSpan ProcessAST::location(AST::UiQualifiedId *id)
792 return location(id->identifierToken, id->identifierToken);
795 LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end)
798 rv.start.line = start.startLine;
799 rv.start.column = start.startColumn;
800 rv.end.line = end.startLine;
801 rv.end.column = end.startColumn + end.length - 1;
802 rv.range.offset = start.offset;
803 rv.range.length = end.offset + end.length - start.offset;
807 // UiProgram: UiImportListOpt UiObjectMemberList ;
808 bool ProcessAST::visit(AST::UiProgram *node)
810 accept(node->imports);
811 accept(node->members->member);
815 // UiImport: T_IMPORT T_STRING_LITERAL ;
816 bool ProcessAST::visit(AST::UiImport *node)
819 QDeclarativeScript::Import import;
821 if (!node->fileName.isNull()) {
822 uri = node->fileName.toString();
824 if (uri.endsWith(QLatin1String(".js"))) {
825 import.type = QDeclarativeScript::Import::Script;
827 import.type = QDeclarativeScript::Import::File;
830 import.type = QDeclarativeScript::Import::Library;
831 uri = asString(node->importUri);
834 AST::SourceLocation startLoc = node->importToken;
835 AST::SourceLocation endLoc = node->semicolonToken;
838 if (!node->importId.isNull()) {
839 import.qualifier = node->importId.toString();
840 if (!import.qualifier.at(0).isUpper()) {
841 QDeclarativeError error;
842 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid import qualifier ID"));
843 error.setLine(node->importIdToken.startLine);
844 error.setColumn(node->importIdToken.startColumn);
845 _parser->_errors << error;
848 if (import.qualifier == QLatin1String("Qt")) {
849 QDeclarativeError error;
850 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Reserved name \"Qt\" cannot be used as an qualifier"));
851 error.setLine(node->importIdToken.startLine);
852 error.setColumn(node->importIdToken.startColumn);
853 _parser->_errors << error;
857 // Check for script qualifier clashes
858 bool isScript = import.type == QDeclarativeScript::Import::Script;
859 for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
860 const QDeclarativeScript::Import &other = _parser->_imports.at(ii);
861 bool otherIsScript = other.type == QDeclarativeScript::Import::Script;
863 if ((isScript || otherIsScript) && import.qualifier == other.qualifier) {
864 QDeclarativeError error;
865 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import qualifiers must be unique."));
866 error.setLine(node->importIdToken.startLine);
867 error.setColumn(node->importIdToken.startColumn);
868 _parser->_errors << error;
873 } else if (import.type == QDeclarativeScript::Import::Script) {
874 QDeclarativeError error;
875 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Script import requires a qualifier"));
876 error.setLine(node->fileNameToken.startLine);
877 error.setColumn(node->fileNameToken.startColumn);
878 _parser->_errors << error;
882 if (node->versionToken.isValid()) {
883 import.version = textAt(node->versionToken);
884 } else if (import.type == QDeclarativeScript::Import::Library) {
885 QDeclarativeError error;
886 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Library import requires a version"));
887 error.setLine(node->importIdToken.startLine);
888 error.setColumn(node->importIdToken.startColumn);
889 _parser->_errors << error;
894 import.location = location(startLoc, endLoc);
897 _parser->_imports << import;
902 bool ProcessAST::visit(AST::UiPublicMember *node)
904 static const struct TypeNameToType {
907 Object::DynamicProperty::Type type;
910 } propTypeNameToTypes[] = {
911 { "int", strlen("int"), Object::DynamicProperty::Int, "int", strlen("int") },
912 { "bool", strlen("bool"), Object::DynamicProperty::Bool, "bool", strlen("bool") },
913 { "double", strlen("double"), Object::DynamicProperty::Real, "double", strlen("double") },
914 { "real", strlen("real"), Object::DynamicProperty::Real, "qreal", strlen("qreal") },
915 { "string", strlen("string"), Object::DynamicProperty::String, "QString", strlen("QString") },
916 { "url", strlen("url"), Object::DynamicProperty::Url, "QUrl", strlen("QUrl") },
917 { "color", strlen("color"), Object::DynamicProperty::Color, "QColor", strlen("QColor") },
918 // Internally QTime, QDate and QDateTime are all supported.
919 // To be more consistent with JavaScript we expose only
920 // QDateTime as it matches closely with the Date JS type.
921 // We also call it "date" to match.
922 // { "time", strlen("time"), Object::DynamicProperty::Time, "QTime", strlen("QTime") },
923 // { "date", strlen("date"), Object::DynamicProperty::Date, "QDate", strlen("QDate") },
924 { "date", strlen("date"), Object::DynamicProperty::DateTime, "QDateTime", strlen("QDateTime") },
925 { "variant", strlen("variant"), Object::DynamicProperty::Variant, "QVariant", strlen("QVariant") }
927 static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
928 sizeof(propTypeNameToTypes[0]);
930 if(node->type == AST::UiPublicMember::Signal) {
931 Object::DynamicSignal *signal = _parser->_pool.New<Object::DynamicSignal>();
932 signal->name = node->name;
934 AST::UiParameterList *p = node->parameters;
936 while (p) { paramLength++; p = p->next; }
937 p = node->parameters;
940 signal->parameterTypes = _parser->_pool.NewRawList<QHashedCStringRef>(paramLength);
941 signal->parameterNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength);
946 const QStringRef &memberType = p->type;
948 const TypeNameToType *type = 0;
949 for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
950 const TypeNameToType *t = propTypeNameToTypes + typeIndex;
951 if (t->nameLength == memberType.length() &&
952 QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
959 QDeclarativeError error;
960 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected parameter type"));
961 error.setLine(node->typeToken.startLine);
962 error.setColumn(node->typeToken.startColumn);
963 _parser->_errors << error;
967 signal->parameterTypes[index] = QHashedCStringRef(type->qtName, type->qtNameLength);
968 signal->parameterNames[index] = QHashedStringRef(p->name);
973 signal.location = location(node->typeToken, node->semicolonToken);
974 _stateStack.top().object->dynamicSignals.append(signal);
976 const QStringRef &memberType = node->memberType;
977 const QStringRef &name = node->name;
979 bool typeFound = false;
980 Object::DynamicProperty::Type type;
982 if ((unsigned)memberType.length() == strlen("alias") &&
983 QHashedString::compare(memberType.constData(), "alias", strlen("alias"))) {
984 type = Object::DynamicProperty::Alias;
988 for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
989 const TypeNameToType *t = propTypeNameToTypes + ii;
990 if (t->nameLength == memberType.length() &&
991 QHashedString::compare(memberType.constData(), t->name, t->nameLength)) {
997 if (!typeFound && memberType.at(0).isUpper()) {
998 const QStringRef &typeModifier = node->typeModifier;
1000 if (typeModifier.isEmpty()) {
1001 type = Object::DynamicProperty::Custom;
1002 } else if((unsigned)typeModifier.length() == strlen("list") &&
1003 QHashedString::compare(typeModifier.constData(), "list", strlen("list"))) {
1004 type = Object::DynamicProperty::CustomList;
1006 QDeclarativeError error;
1007 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Invalid property type modifier"));
1008 error.setLine(node->typeModifierToken.startLine);
1009 error.setColumn(node->typeModifierToken.startColumn);
1010 _parser->_errors << error;
1014 } else if (!node->typeModifier.isNull()) {
1015 QDeclarativeError error;
1016 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Unexpected property type modifier"));
1017 error.setLine(node->typeModifierToken.startLine);
1018 error.setColumn(node->typeModifierToken.startColumn);
1019 _parser->_errors << error;
1024 QDeclarativeError error;
1025 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Expected property type"));
1026 error.setLine(node->typeToken.startLine);
1027 error.setColumn(node->typeToken.startColumn);
1028 _parser->_errors << error;
1032 if (node->isReadonlyMember) {
1033 QDeclarativeError error;
1034 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Readonly not yet supported"));
1035 error.setLine(node->readonlyToken.startLine);
1036 error.setColumn(node->readonlyToken.startColumn);
1037 _parser->_errors << error;
1042 Object::DynamicProperty *property = _parser->_pool.New<Object::DynamicProperty>();
1043 property->isDefaultProperty = node->isDefaultMember;
1044 property->type = type;
1045 if (type >= Object::DynamicProperty::Custom) {
1046 QDeclarativeScript::TypeReference *typeRef =
1047 _parser->findOrCreateType(memberType.toString());
1048 typeRef->refObjects.append(_stateStack.top().object);
1049 property->customType = memberType;
1052 property->name = QHashedStringRef(name);
1053 property->location = location(node->firstSourceLocation(),
1054 node->lastSourceLocation());
1056 if (node->statement) { // default value
1057 property->defaultValue = _parser->_pool.New<Property>();
1058 property->defaultValue->parent = _stateStack.top().object;
1059 property->defaultValue->location =
1060 location(node->statement->firstSourceLocation(),
1061 node->statement->lastSourceLocation());
1062 QDeclarativeScript::Value *value = _parser->_pool.New<QDeclarativeScript::Value>();
1063 value->location = location(node->statement->firstSourceLocation(),
1064 node->statement->lastSourceLocation());
1065 value->value = getVariant(node->statement);
1066 property->defaultValue->values.append(value);
1069 _stateStack.top().object->dynamicProperties.append(property);
1071 // process QML-like initializers (e.g. property Object o: Object {})
1072 accept(node->binding);
1079 // UiObjectMember: UiQualifiedId UiObjectInitializer ;
1080 bool ProcessAST::visit(AST::UiObjectDefinition *node)
1082 LocationSpan l = location(node->firstSourceLocation(),
1083 node->lastSourceLocation());
1085 const QString objectType = asString(node->qualifiedTypeNameId);
1086 const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
1088 defineObjectBinding(/*propertyName = */ 0, false, objectType,
1089 typeLocation, l, node->initializer);
1095 // UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
1096 bool ProcessAST::visit(AST::UiObjectBinding *node)
1098 LocationSpan l = location(node->qualifiedTypeNameId->identifierToken,
1099 node->initializer->rbraceToken);
1101 const QString objectType = asString(node->qualifiedTypeNameId);
1102 const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
1104 defineObjectBinding(node->qualifiedId, node->hasOnToken, objectType,
1105 typeLocation, l, node->initializer);
1110 QDeclarativeScript::Variant ProcessAST::getVariant(AST::Statement *stmt)
1113 if (AST::ExpressionStatement *exprStmt = AST::cast<AST::ExpressionStatement *>(stmt))
1114 return getVariant(exprStmt->expression);
1116 return QDeclarativeScript::Variant(asStringRef(stmt), stmt);
1119 return QDeclarativeScript::Variant();
1122 QDeclarativeScript::Variant ProcessAST::getVariant(AST::ExpressionNode *expr)
1124 if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
1125 return QDeclarativeScript::Variant(lit);
1126 } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
1127 return QDeclarativeScript::Variant(true);
1128 } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
1129 return QDeclarativeScript::Variant(false);
1130 } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
1131 return QDeclarativeScript::Variant(lit->value, asStringRef(expr));
1134 if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
1135 if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
1136 return QDeclarativeScript::Variant(-lit->value, asStringRef(expr));
1140 return QDeclarativeScript::Variant(asStringRef(expr), expr);
1145 // UiObjectMember: UiQualifiedId T_COLON Statement ;
1146 bool ProcessAST::visit(AST::UiScriptBinding *node)
1148 int propertyCount = 0;
1149 AST::UiQualifiedId *propertyName = node->qualifiedId;
1150 for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
1152 _stateStack.pushProperty(name->name,
1156 Property *prop = currentProperty();
1158 if (!prop->values.isEmpty()) {
1159 QDeclarativeError error;
1160 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
1161 error.setLine(this->location(propertyName).start.line);
1162 error.setColumn(this->location(propertyName).start.column);
1163 _parser->_errors << error;
1167 QDeclarativeScript::Variant primitive;
1169 if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) {
1170 primitive = getVariant(stmt->expression);
1171 } else { // do binding
1172 primitive = QDeclarativeScript::Variant(asStringRef(node->statement), node->statement);
1175 prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset;
1176 prop->location.range.offset = node->qualifiedId->identifierToken.offset;
1177 QDeclarativeScript::Value *v = _parser->_pool.New<QDeclarativeScript::Value>();
1178 v->value = primitive;
1179 v->location = location(node->statement->firstSourceLocation(),
1180 node->statement->lastSourceLocation());
1184 while (propertyCount--)
1190 // UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
1191 bool ProcessAST::visit(AST::UiArrayBinding *node)
1193 int propertyCount = 0;
1194 AST::UiQualifiedId *propertyName = node->qualifiedId;
1195 for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
1197 _stateStack.pushProperty(name->name,
1201 Property* prop = currentProperty();
1203 if (!prop->values.isEmpty()) {
1204 QDeclarativeError error;
1205 error.setDescription(QCoreApplication::translate("QDeclarativeParser","Property value set multiple times"));
1206 error.setLine(this->location(propertyName).start.line);
1207 error.setColumn(this->location(propertyName).start.column);
1208 _parser->_errors << error;
1212 accept(node->members);
1214 // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range:
1215 prop->listValueRange.offset = node->lbracketToken.offset;
1216 prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset;
1218 while (propertyCount--)
1224 bool ProcessAST::visit(AST::UiSourceElement *node)
1226 QDeclarativeScript::Object *obj = currentObject();
1228 if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
1230 Object::DynamicSlot *slot = _parser->_pool.New<Object::DynamicSlot>();
1231 slot->location = location(funDecl->firstSourceLocation(), funDecl->lastSourceLocation());
1233 AST::FormalParameterList *f = funDecl->formals;
1235 slot->parameterNames << f->name.toUtf8();
1239 AST::SourceLocation loc = funDecl->rparenToken;
1240 loc.offset = loc.end();
1241 loc.startColumn += 1;
1242 QString body = textAt(loc, funDecl->rbraceToken);
1243 slot->name = funDecl->name;
1245 obj->dynamicSlots.append(slot);
1248 QDeclarativeError error;
1249 error.setDescription(QCoreApplication::translate("QDeclarativeParser","JavaScript declaration outside Script element"));
1250 error.setLine(node->firstSourceLocation().startLine);
1251 error.setColumn(node->firstSourceLocation().startColumn);
1252 _parser->_errors << error;
1257 } // end of anonymous namespace
1260 QDeclarativeScript::Parser::Parser()
1266 QDeclarativeScript::Parser::~Parser()
1271 namespace QDeclarativeScript {
1272 class ParserJsASTData
1275 ParserJsASTData(const QString &filename)
1276 : filename(filename) {}
1283 bool QDeclarativeScript::Parser::parse(const QByteArray &qmldata, const QUrl &url)
1287 const QString fileName = url.toString();
1288 _scriptFile = fileName;
1290 QTextStream stream(qmldata, QIODevice::ReadOnly);
1291 #ifndef QT_NO_TEXTCODEC
1292 stream.setCodec("UTF-8");
1294 QString *code = _pool.NewString(stream.readAll());
1296 data = new QDeclarativeScript::ParserJsASTData(fileName);
1298 Lexer lexer(&data->engine);
1299 lexer.setCode(*code, /*line = */ 1);
1301 QDeclarativeJS::Parser parser(&data->engine);
1303 if (! parser.parse() || !_errors.isEmpty()) {
1305 // Extract errors from the parser
1306 foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
1311 QDeclarativeError error;
1313 error.setDescription(m.message);
1314 error.setLine(m.loc.startLine);
1315 error.setColumn(m.loc.startColumn);
1321 if (_errors.isEmpty()) {
1322 ProcessAST process(this);
1323 process(*code, parser.ast());
1325 // Set the url for process errors
1326 for(int ii = 0; ii < _errors.count(); ++ii)
1327 _errors[ii].setUrl(url);
1330 return _errors.isEmpty();
1333 QList<QDeclarativeScript::TypeReference*> QDeclarativeScript::Parser::referencedTypes() const
1338 QDeclarativeScript::Object *QDeclarativeScript::Parser::tree() const
1343 QList<QDeclarativeScript::Import> QDeclarativeScript::Parser::imports() const
1348 QList<QDeclarativeError> QDeclarativeScript::Parser::errors() const
1353 static void replaceWithSpace(QString &str, int idx, int n)
1355 QChar *data = str.data() + idx;
1356 const QChar space(QLatin1Char(' '));
1357 for (int ii = 0; ii < n; ++ii)
1361 static QDeclarativeScript::LocationSpan
1362 locationFromLexer(const QDeclarativeJS::Lexer &lex, int startLine, int startColumn, int startOffset)
1364 QDeclarativeScript::LocationSpan l;
1366 l.start.line = startLine; l.start.column = startColumn;
1367 l.end.line = lex.tokenEndLine(); l.end.column = lex.tokenEndColumn();
1368 l.range.offset = startOffset;
1369 l.range.length = lex.tokenOffset() + lex.tokenLength() - startOffset;
1375 Searches for ".pragma <value>" declarations within \a script. Currently supported pragmas
1379 QDeclarativeScript::Object::ScriptBlock::Pragmas QDeclarativeScript::Parser::extractPragmas(QString &script)
1381 QDeclarativeScript::Object::ScriptBlock::Pragmas rv = QDeclarativeScript::Object::ScriptBlock::None;
1383 const QString pragma(QLatin1String("pragma"));
1384 const QString library(QLatin1String("library"));
1386 QDeclarativeJS::Lexer l(0);
1387 l.setCode(script, 0);
1389 int token = l.lex();
1392 if (token != QDeclarativeJSGrammar::T_DOT)
1395 int startOffset = l.tokenOffset();
1396 int startLine = l.tokenStartLine();
1400 if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
1401 l.tokenStartLine() != startLine ||
1402 script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
1407 if (token != QDeclarativeJSGrammar::T_IDENTIFIER ||
1408 l.tokenStartLine() != startLine)
1411 QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
1412 int endOffset = l.tokenLength() + l.tokenOffset();
1415 if (l.tokenStartLine() == startLine)
1418 if (pragmaValue == library) {
1419 rv |= QDeclarativeScript::Object::ScriptBlock::Shared;
1420 replaceWithSpace(script, startOffset, endOffset - startOffset);
1428 #define CHECK_LINE if (l.tokenStartLine() != startLine) return rv;
1429 #define CHECK_TOKEN(t) if (token != QDeclarativeJSGrammar:: t) return rv;
1431 static const int uriTokens[] = {
1432 QDeclarativeJSGrammar::T_IDENTIFIER,
1433 QDeclarativeJSGrammar::T_PROPERTY,
1434 QDeclarativeJSGrammar::T_SIGNAL,
1435 QDeclarativeJSGrammar::T_READONLY,
1436 QDeclarativeJSGrammar::T_ON,
1437 QDeclarativeJSGrammar::T_BREAK,
1438 QDeclarativeJSGrammar::T_CASE,
1439 QDeclarativeJSGrammar::T_CATCH,
1440 QDeclarativeJSGrammar::T_CONTINUE,
1441 QDeclarativeJSGrammar::T_DEFAULT,
1442 QDeclarativeJSGrammar::T_DELETE,
1443 QDeclarativeJSGrammar::T_DO,
1444 QDeclarativeJSGrammar::T_ELSE,
1445 QDeclarativeJSGrammar::T_FALSE,
1446 QDeclarativeJSGrammar::T_FINALLY,
1447 QDeclarativeJSGrammar::T_FOR,
1448 QDeclarativeJSGrammar::T_FUNCTION,
1449 QDeclarativeJSGrammar::T_IF,
1450 QDeclarativeJSGrammar::T_IN,
1451 QDeclarativeJSGrammar::T_INSTANCEOF,
1452 QDeclarativeJSGrammar::T_NEW,
1453 QDeclarativeJSGrammar::T_NULL,
1454 QDeclarativeJSGrammar::T_RETURN,
1455 QDeclarativeJSGrammar::T_SWITCH,
1456 QDeclarativeJSGrammar::T_THIS,
1457 QDeclarativeJSGrammar::T_THROW,
1458 QDeclarativeJSGrammar::T_TRUE,
1459 QDeclarativeJSGrammar::T_TRY,
1460 QDeclarativeJSGrammar::T_TYPEOF,
1461 QDeclarativeJSGrammar::T_VAR,
1462 QDeclarativeJSGrammar::T_VOID,
1463 QDeclarativeJSGrammar::T_WHILE,
1464 QDeclarativeJSGrammar::T_CONST,
1465 QDeclarativeJSGrammar::T_DEBUGGER,
1466 QDeclarativeJSGrammar::T_RESERVED_WORD,
1467 QDeclarativeJSGrammar::T_WITH,
1469 QDeclarativeJSGrammar::EOF_SYMBOL
1471 static inline bool isUriToken(int token)
1473 const int *current = uriTokens;
1474 while (*current != QDeclarativeJSGrammar::EOF_SYMBOL) {
1475 if (*current == token)
1482 QDeclarativeScript::Parser::JavaScriptMetaData QDeclarativeScript::Parser::extractMetaData(QString &script)
1484 JavaScriptMetaData rv;
1486 QDeclarativeScript::Object::ScriptBlock::Pragmas &pragmas = rv.pragmas;
1488 const QString pragma(QLatin1String("pragma"));
1489 const QString js(QLatin1String(".js"));
1490 const QString library(QLatin1String("library"));
1492 QDeclarativeJS::Lexer l(0);
1493 l.setCode(script, 0);
1495 int token = l.lex();
1498 if (token != QDeclarativeJSGrammar::T_DOT)
1501 int startOffset = l.tokenOffset();
1502 int startLine = l.tokenStartLine();
1503 int startColumn = l.tokenStartColumn();
1509 if (token == QDeclarativeJSGrammar::T_IMPORT) {
1511 // .import <URI> <Version> as <Identifier>
1512 // .import <file.js> as <Identifier>
1518 if (token == QDeclarativeJSGrammar::T_STRING_LITERAL) {
1520 QString file = l.tokenText();
1522 if (!file.endsWith(js))
1532 CHECK_TOKEN(T_IDENTIFIER);
1535 int endOffset = l.tokenLength() + l.tokenOffset();
1537 QString importId = script.mid(l.tokenOffset(), l.tokenLength());
1539 if (!importId.at(0).isUpper())
1542 QDeclarativeScript::LocationSpan location =
1543 locationFromLexer(l, startLine, startColumn, startOffset);
1546 if (l.tokenStartLine() == startLine)
1549 replaceWithSpace(script, startOffset, endOffset - startOffset);
1552 import.type = Import::Script;
1554 import.qualifier = importId;
1555 import.location = location;
1557 rv.imports << import;
1564 if (!isUriToken(token))
1567 uri.append(l.tokenText());
1571 if (token != QDeclarativeJSGrammar::T_DOT)
1574 uri.append(QLatin1Char('.'));
1580 CHECK_TOKEN(T_NUMERIC_LITERAL);
1581 version = script.mid(l.tokenOffset(), l.tokenLength());
1590 CHECK_TOKEN(T_IDENTIFIER);
1593 int endOffset = l.tokenLength() + l.tokenOffset();
1595 QString importId = script.mid(l.tokenOffset(), l.tokenLength());
1597 if (!importId.at(0).isUpper())
1600 QDeclarativeScript::LocationSpan location =
1601 locationFromLexer(l, startLine, startColumn, startOffset);
1604 if (l.tokenStartLine() == startLine)
1607 replaceWithSpace(script, startOffset, endOffset - startOffset);
1610 import.type = Import::Library;
1612 import.version = version;
1613 import.qualifier = importId;
1614 import.location = location;
1616 rv.imports << import;
1619 } else if (token == QDeclarativeJSGrammar::T_IDENTIFIER &&
1620 script.mid(l.tokenOffset(), l.tokenLength()) == pragma) {
1624 CHECK_TOKEN(T_IDENTIFIER);
1627 QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
1628 int endOffset = l.tokenLength() + l.tokenOffset();
1630 if (pragmaValue == library) {
1631 pragmas |= QDeclarativeScript::Object::ScriptBlock::Shared;
1632 replaceWithSpace(script, startOffset, endOffset - startOffset);
1638 if (l.tokenStartLine() == startLine)
1648 void QDeclarativeScript::Parser::clear()
1651 qDeleteAll(_refTypes);
1663 QDeclarativeScript::TypeReference *QDeclarativeScript::Parser::findOrCreateType(const QString &name)
1665 TypeReference *type = 0;
1667 for (; i < _refTypes.size(); ++i) {
1668 if (_refTypes.at(i)->name == name) {
1669 type = _refTypes.at(i);
1674 type = new TypeReference(i, name);
1675 _refTypes.append(type);
1681 void QDeclarativeScript::Parser::setTree(QDeclarativeScript::Object *tree)