aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlscript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlscript.cpp')
-rw-r--r--src/qml/qml/qqmlscript.cpp1415
1 files changed, 19 insertions, 1396 deletions
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index 0618c90fa5..cf56d5701d 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -58,1359 +58,6 @@ QT_BEGIN_NAMESPACE
using namespace QQmlJS;
using namespace QQmlScript;
-//
-// Parser IR classes
-//
-QQmlScript::Object::Object()
-: type(-1), typeReference(0), idIndex(-1), metatype(0), synthCache(0),
- defaultProperty(0), parserStatusCast(-1), componentCompileState(0), nextAliasingObject(0),
- nextIdObject(0)
-{
-}
-
-QQmlScript::Object::~Object()
-{
- if (synthCache) synthCache->release();
-}
-
-void Object::setBindingBit(int b)
-{
- while (bindingBitmask.size() < 4 * (1 + b / 32))
- bindingBitmask.append(char(0));
-
- quint32 *bits = (quint32 *)bindingBitmask.data();
- bits[b / 32] |= (1 << (b % 32));
-}
-
-QQmlScript::Property *Object::getDefaultProperty()
-{
- if (!defaultProperty) {
- defaultProperty = pool()->New<Property>();
- defaultProperty->parent = this;
- }
- return defaultProperty;
-}
-
-void QQmlScript::Object::addValueProperty(Property *p)
-{
- valueProperties.append(p);
-}
-
-void QQmlScript::Object::addSignalProperty(Property *p)
-{
- signalProperties.append(p);
-}
-
-void QQmlScript::Object::addAttachedProperty(Property *p)
-{
- attachedProperties.append(p);
-}
-
-void QQmlScript::Object::addGroupedProperty(Property *p)
-{
- groupedProperties.append(p);
-}
-
-void QQmlScript::Object::addValueTypeProperty(Property *p)
-{
- valueTypeProperties.append(p);
-}
-
-void QQmlScript::Object::addScriptStringProperty(Property *p)
-{
- scriptStringProperties.append(p);
-}
-
-// This lookup is optimized for missing, and having to create a new property.
-Property *QQmlScript::Object::getProperty(const QHashedStringRef &name, bool create)
-{
- if (create) {
- quint32 h = name.hash();
- if (propertiesHashField.testAndSet(h)) {
- for (Property *p = properties.first(); p; p = properties.next(p)) {
- if (p->name() == name)
- return p;
- }
- }
-
- Property *property = pool()->New<Property>();
- property->parent = this;
- property->_name = name;
- property->isDefault = false;
- properties.prepend(property);
- return property;
- } else {
- for (Property *p = properties.first(); p; p = properties.next(p)) {
- if (p->name() == name)
- return p;
- }
- }
-
- return 0;
-}
-
-Property *QQmlScript::Object::getProperty(const QStringRef &name, bool create)
-{
- return getProperty(QHashedStringRef(name), create);
-}
-
-Property *QQmlScript::Object::getProperty(const QString &name, bool create)
-{
- for (Property *p = properties.first(); p; p = properties.next(p)) {
- if (p->name() == name)
- return p;
- }
-
- if (create) {
- Property *property = pool()->New<Property>();
- property->parent = this;
- property->_name = QStringRef(pool()->NewString(name));
- propertiesHashField.testAndSet(property->_name.hash());
- property->isDefault = false;
- properties.prepend(property);
- return property;
- } else {
- return 0;
- }
-}
-
-int QQmlScript::Object::aggregateDynamicSignalParameterCount() const
-{
- int sum = 0;
- for (DynamicSignal *s = dynamicSignals.first(); s; s = dynamicSignals.next(s))
- sum += s->parameterTypes.count() + 1; // +1 for return type
- return sum;
-}
-
-int QQmlScript::Object::aggregateDynamicSlotParameterCount() const
-{
- int sum = 0;
- for (DynamicSlot *s = dynamicSlots.first(); s; s = dynamicSlots.next(s))
- sum += s->parameterNames.count() + 1; // +1 for return type
- return sum;
-}
-
-QQmlScript::Object::DynamicProperty::DynamicProperty()
-: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0),
- nameIndex(-1)
-{
-}
-
-QQmlScript::Object::DynamicSignal::DynamicSignal()
-: nextSignal(0), nameIndex(-1)
-{
-}
-
-QQmlScript::Object::DynamicSlot::DynamicSlot()
-: funcDecl(0), nextSlot(0), nameIndex(-1)
-{
-}
-
-int QQmlScript::Object::DynamicSlot::parameterNamesLength() const
-{
- int rv = 0;
- for (int ii = 0; ii < parameterNames.count(); ++ii)
- rv += parameterNames.at(ii).length();
- return rv;
-}
-
-QQmlScript::Property::Property()
-: parent(0), type(0), index(-1), value(0), isDefault(true), isDeferred(false),
- isValueTypeSubProperty(false), isAlias(false), isReadOnlyDeclaration(false),
- scriptStringScope(-1), nextMainProperty(0), nextProperty(0)
-{
-}
-
-QQmlScript::Object *QQmlScript::Property::getValue(const LocationSpan &l)
-{
- if (!value) { value = pool()->New<Object>(); value->location = l; }
- return value;
-}
-
-void QQmlScript::Property::addValue(Value *v)
-{
- values.append(v);
-}
-
-void QQmlScript::Property::addOnValue(Value *v)
-{
- onValues.append(v);
-}
-
-bool QQmlScript::Property::isEmpty() const
-{
- return !value && values.isEmpty() && onValues.isEmpty();
-}
-
-QQmlScript::Value::Value()
-: type(Unknown), object(0), bindingReference(0), nextValue(0)
-{
-}
-
-QQmlScript::Variant::Variant()
-: t(Invalid)
-{
-}
-
-QQmlScript::Variant::Variant(const Variant &o)
-: t(o.t), d(o.d), asWritten(o.asWritten)
-{
-}
-
-QQmlScript::Variant::Variant(bool v)
-: t(Boolean), b(v)
-{
-}
-
-QQmlScript::Variant::Variant(double v, const QStringRef &asWritten)
-: t(Number), d(v), asWritten(asWritten)
-{
-}
-
-QQmlScript::Variant::Variant(QQmlJS::AST::StringLiteral *v)
-: t(String), l(v)
-{
-}
-
-QQmlScript::Variant::Variant(const QStringRef &asWritten, QQmlJS::AST::Node *n)
-: t(Script), n(n), asWritten(asWritten)
-{
-}
-
-QQmlScript::Variant &QQmlScript::Variant::operator=(const Variant &o)
-{
- t = o.t;
- d = o.d;
- asWritten = o.asWritten;
- return *this;
-}
-
-QQmlScript::Variant::Type QQmlScript::Variant::type() const
-{
- return t;
-}
-
-bool QQmlScript::Variant::asBoolean() const
-{
- return b;
-}
-
-QString QQmlScript::Variant::asString() const
-{
- if (t == String) {
- return l->value.toString();
- } else {
- return asWritten.toString();
- }
-}
-
-double QQmlScript::Variant::asNumber() const
-{
- return d;
-}
-
-//reverse of Lexer::singleEscape()
-QString escapedString(const QString &string)
-{
- QString tmp = QLatin1String("\"");
- for (int i = 0; i < string.length(); ++i) {
- const QChar &c = string.at(i);
- switch(c.unicode()) {
- case 0x08:
- tmp += QLatin1String("\\b");
- break;
- case 0x09:
- tmp += QLatin1String("\\t");
- break;
- case 0x0A:
- tmp += QLatin1String("\\n");
- break;
- case 0x0B:
- tmp += QLatin1String("\\v");
- break;
- case 0x0C:
- tmp += QLatin1String("\\f");
- break;
- case 0x0D:
- tmp += QLatin1String("\\r");
- break;
- case 0x22:
- tmp += QLatin1String("\\\"");
- break;
- case 0x27:
- tmp += QLatin1String("\\\'");
- break;
- case 0x5C:
- tmp += QLatin1String("\\\\");
- break;
- default:
- tmp += c;
- break;
- }
- }
- tmp += QLatin1Char('\"');
- return tmp;
-}
-
-QString QQmlScript::Variant::asScript() const
-{
- switch (type()) {
- default:
- case Invalid:
- return QString();
- case Boolean:
- return b?QLatin1String("true"):QLatin1String("false");
- case Number:
- if (asWritten.isEmpty())
- return QString::number(d);
- else
- return asWritten.toString();
- case String:
- return escapedString(asString());
- case Script:
- if (AST::IdentifierExpression *i = AST::cast<AST::IdentifierExpression *>(n)) {
- return i->name.toString();
- } else
- return asWritten.toString();
- }
-}
-
-QQmlJS::AST::Node *QQmlScript::Variant::asAST() const
-{
- if (type() == Script)
- return n;
- else
- return 0;
-}
-
-bool QQmlScript::Variant::isStringList() const
-{
- if (isString())
- return true;
-
- if (type() != Script || !n)
- return false;
-
- AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
- if (!array)
- return false;
-
- AST::ElementList *elements = array->elements;
-
- while (elements) {
-
- if (!AST::cast<AST::StringLiteral *>(elements->expression))
- return false;
-
- elements = elements->next;
- }
-
- return true;
-}
-
-QStringList QQmlScript::Variant::asStringList() const
-{
- QStringList rv;
- if (isString()) {
- rv << asString();
- return rv;
- }
-
- AST::ArrayLiteral *array = AST::cast<AST::ArrayLiteral *>(n);
- if (!array)
- return rv;
-
- AST::ElementList *elements = array->elements;
- while (elements) {
-
- AST::StringLiteral *string = AST::cast<AST::StringLiteral *>(elements->expression);
- if (!string)
- return QStringList();
- rv.append(string->value.toString());
-
- elements = elements->next;
- }
-
- return rv;
-}
-
-//
-// Actual parser classes
-//
-namespace {
-
-class ProcessAST: protected AST::Visitor
-{
- struct State {
- State() : object(0), property(0) {}
- State(QQmlScript::Object *o) : object(o), property(0) {}
- State(QQmlScript::Object *o, Property *p) : object(o), property(p) {}
-
- QQmlScript::Object *object;
- Property *property;
- };
-
- struct StateStack : public QStack<State>
- {
- void pushObject(QQmlScript::Object *obj)
- {
- push(State(obj));
- }
-
- void pushProperty(const QString &name, const LocationSpan &location)
- {
- const State &state = top();
- if (state.property) {
- State s(state.property->getValue(location),
- state.property->getValue(location)->getProperty(name));
- s.property->location = location;
- push(s);
- } else {
- State s(state.object, state.object->getProperty(name));
-
- s.property->location = location;
- push(s);
- }
- }
-
- void pushProperty(const QStringRef &name, const LocationSpan &location)
- {
- const State &state = top();
- if (state.property) {
- State s(state.property->getValue(location),
- state.property->getValue(location)->getProperty(name));
- s.property->location = location;
- push(s);
- } else {
- State s(state.object, state.object->getProperty(name));
-
- s.property->location = location;
- push(s);
- }
- }
- };
-
-public:
- ProcessAST(QQmlScript::Parser *parser);
- virtual ~ProcessAST();
-
- void operator()(const QString &code, AST::Node *node);
-
- static void extractVersion(QStringRef string, int *maj, int *min);
-
-protected:
-
- QQmlScript::Object *defineObjectBinding(AST::Node *node, AST::UiQualifiedId *propertyName, bool onAssignment,
- const QString &objectType,
- AST::SourceLocation typeLocation,
- LocationSpan location,
- AST::UiObjectInitializer *initializer = 0);
-
- QQmlScript::Variant getVariant(AST::Statement *stmt);
- QQmlScript::Variant getVariant(AST::ExpressionNode *expr);
-
- LocationSpan location(AST::SourceLocation start, AST::SourceLocation end);
- LocationSpan location(AST::UiQualifiedId *);
-
- using AST::Visitor::visit;
- using AST::Visitor::endVisit;
-
- virtual bool visit(AST::UiProgram *node);
- virtual bool visit(AST::UiImport *node);
- virtual bool visit(AST::UiPragma *node);
- virtual bool visit(AST::UiObjectDefinition *node);
- virtual bool visit(AST::UiPublicMember *node);
- virtual bool visit(AST::UiObjectBinding *node);
-
- virtual bool visit(AST::UiScriptBinding *node);
- virtual bool visit(AST::UiArrayBinding *node);
- virtual bool visit(AST::UiSourceElement *node);
-
- void accept(AST::Node *node);
-
- QString asString(AST::UiQualifiedId *node) const;
-
- const State state() const;
- QQmlScript::Object *currentObject() const;
- Property *currentProperty() const;
-
- QString textAt(const AST::SourceLocation &loc) const
- { return _contents->mid(loc.offset, loc.length); }
-
- QStringRef textRefAt(const AST::SourceLocation &loc) const
- { return QStringRef(_contents, loc.offset, loc.length); }
-
- QString textAt(const AST::SourceLocation &first,
- const AST::SourceLocation &last) const
- { return _contents->mid(first.offset, last.offset + last.length - first.offset); }
-
- QStringRef textRefAt(const AST::SourceLocation &first,
- const AST::SourceLocation &last) const
- { return QStringRef(_contents, first.offset, last.offset + last.length - first.offset); }
-
- QString asString(AST::ExpressionNode *expr)
- {
- if (! expr)
- return QString();
-
- return textAt(expr->firstSourceLocation(), expr->lastSourceLocation());
- }
-
- QStringRef asStringRef(AST::ExpressionNode *expr)
- {
- if (! expr)
- return QStringRef();
-
- return textRefAt(expr->firstSourceLocation(), expr->lastSourceLocation());
- }
-
- QString asString(AST::Statement *stmt)
- {
- if (! stmt)
- return QString();
-
- QString s = textAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
- s += QLatin1Char('\n');
- return s;
- }
-
- QStringRef asStringRef(AST::Statement *stmt)
- {
- if (! stmt)
- return QStringRef();
-
- return textRefAt(stmt->firstSourceLocation(), stmt->lastSourceLocation());
- }
-
-private:
- QQmlScript::Parser *_parser;
- StateStack _stateStack;
- const QString *_contents;
-};
-
-ProcessAST::ProcessAST(QQmlScript::Parser *parser)
- : _parser(parser)
-{
-}
-
-ProcessAST::~ProcessAST()
-{
-}
-
-void ProcessAST::operator()(const QString &code, AST::Node *node)
-{
- _contents = &code;
- accept(node);
-}
-
-void ProcessAST::accept(AST::Node *node)
-{
- AST::Node::acceptChild(node, this);
-}
-
-const ProcessAST::State ProcessAST::state() const
-{
- if (_stateStack.isEmpty())
- return State();
-
- return _stateStack.back();
-}
-
-QQmlScript::Object *ProcessAST::currentObject() const
-{
- return state().object;
-}
-
-Property *ProcessAST::currentProperty() const
-{
- return state().property;
-}
-
-void ProcessAST::extractVersion(QStringRef string, int *maj, int *min)
-{
- *maj = -1; *min = -1;
-
- if (!string.isEmpty()) {
-
- int dot = string.indexOf(QLatin1Char('.'));
-
- if (dot < 0) {
- *maj = string.toInt();
- *min = 0;
- } else {
- *maj = string.left(dot).toInt();
- *min = string.mid(dot + 1).toInt();
- }
- }
-}
-
-QString ProcessAST::asString(AST::UiQualifiedId *node) const
-{
- QString s;
-
- for (AST::UiQualifiedId *it = node; it; it = it->next) {
- s.append(it->name);
-
- if (it->next)
- s.append(QLatin1Char('.'));
- }
-
- return s;
-}
-
-QQmlScript::Object *
-ProcessAST::defineObjectBinding(AST::Node *node,
- AST::UiQualifiedId *propertyName,
- bool onAssignment,
- const QString &objectType,
- AST::SourceLocation typeLocation,
- LocationSpan location,
- AST::UiObjectInitializer *initializer)
-{
- int lastTypeDot = objectType.lastIndexOf(QLatin1Char('.'));
-
- // With no preceding qualification, first char is at (-1 + 1) == 0
- bool isType = !objectType.isEmpty() && objectType.at(lastTypeDot+1).isUpper();
-
- int propertyCount = 0;
- for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
- ++propertyCount;
- _stateStack.pushProperty(name->name,
- this->location(name));
- }
-
- if (!onAssignment && propertyCount && currentProperty() && !currentProperty()->values.isEmpty()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
- error.setLine(this->location(propertyName).start.line);
- error.setColumn(this->location(propertyName).start.column);
- _parser->_errors << error;
- return 0;
- }
-
- if (!isType) {
-
- // Is the identifier qualified by a namespace?
- int namespaceLength = 0;
- if (lastTypeDot > 0) {
- const QString qualifier(objectType.left(lastTypeDot));
-
- for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
- const QQmlScript::Import &import = _parser->_imports.at(ii);
- if (import.qualifier == qualifier) {
- // The qualifier is a namespace - expect a type here
- namespaceLength = qualifier.length() + 1;
- break;
- }
- }
- }
-
- if (propertyCount || !currentObject() || namespaceLength) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Expected type name"));
- error.setLine(typeLocation.startLine);
- error.setColumn(typeLocation.startColumn + namespaceLength);
- _parser->_errors << error;
- return 0;
- }
-
- LocationSpan loc = ProcessAST::location(typeLocation, typeLocation);
- if (propertyName)
- loc = ProcessAST::location(propertyName);
-
- _stateStack.pushProperty(objectType, loc);
- accept(initializer);
- _stateStack.pop();
-
- return 0;
-
- } else {
- // Class
-
- QQmlScript::Object *obj = _parser->_pool.New<QQmlScript::Object>();
-
- obj->type = _parser->findOrCreateTypeId(objectType, obj);
- obj->typeReference = _parser->_refTypes.at(obj->type);
- obj->location = location;
- obj->astNode = node;
-
- if (propertyCount) {
- Property *prop = currentProperty();
- QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
- v->object = obj;
- v->location = obj->location;
- if (onAssignment)
- prop->addOnValue(v);
- else
- prop->addValue(v);
-
- while (propertyCount--)
- _stateStack.pop();
-
- } else {
-
- if (! _parser->tree()) {
- _parser->setTree(obj);
- } else {
- const State state = _stateStack.top();
- QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
- v->object = obj;
- v->location = obj->location;
- if (state.property) {
- state.property->addValue(v);
- } else {
- Property *defaultProp = state.object->getDefaultProperty();
- if (defaultProp->location.start.line == 0) {
- defaultProp->location = v->location;
- defaultProp->location.end = defaultProp->location.start;
- defaultProp->location.range.length = 0;
- }
- defaultProp->addValue(v);
- }
- }
- }
-
- _stateStack.pushObject(obj);
- accept(initializer);
- _stateStack.pop();
-
- return obj;
- }
-}
-
-LocationSpan ProcessAST::location(AST::UiQualifiedId *id)
-{
- return location(id->identifierToken, id->identifierToken);
-}
-
-LocationSpan ProcessAST::location(AST::SourceLocation start, AST::SourceLocation end)
-{
- LocationSpan rv;
- rv.start.line = start.startLine;
- rv.start.column = start.startColumn;
- rv.end.line = end.startLine;
- rv.end.column = end.startColumn + end.length - 1;
- rv.range.offset = start.offset;
- rv.range.length = end.offset + end.length - start.offset;
- return rv;
-}
-
-// UiProgram: UiHeaderItemListOpt UiObjectMemberList ;
-bool ProcessAST::visit(AST::UiProgram *node)
-{
- accept(node->headers);
- accept(node->members->member);
- return false;
-}
-
-// UiImport: T_IMPORT T_STRING_LITERAL ;
-bool ProcessAST::visit(AST::UiImport *node)
-{
- QString uri;
- QQmlScript::Import import;
-
- if (!node->fileName.isNull()) {
- uri = node->fileName.toString();
-
- if (uri.endsWith(QLatin1String(".js"))) {
- import.type = QQmlScript::Import::Script;
- } else {
- import.type = QQmlScript::Import::File;
- }
- } else {
- import.type = QQmlScript::Import::Library;
- uri = asString(node->importUri);
- }
-
- AST::SourceLocation startLoc = node->importToken;
- AST::SourceLocation endLoc = node->semicolonToken;
-
- // Qualifier
- if (!node->importId.isNull()) {
- import.qualifier = node->importId.toString();
- if (!import.qualifier.at(0).isUpper()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Invalid import qualifier ID"));
- error.setLine(node->importIdToken.startLine);
- error.setColumn(node->importIdToken.startColumn);
- _parser->_errors << error;
- return false;
- }
- if (import.qualifier == QLatin1String("Qt")) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Reserved name \"Qt\" cannot be used as an qualifier"));
- error.setLine(node->importIdToken.startLine);
- error.setColumn(node->importIdToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- // Check for script qualifier clashes
- bool isScript = import.type == QQmlScript::Import::Script;
- for (int ii = 0; ii < _parser->_imports.count(); ++ii) {
- const QQmlScript::Import &other = _parser->_imports.at(ii);
- bool otherIsScript = other.type == QQmlScript::Import::Script;
-
- if ((isScript || otherIsScript) && import.qualifier == other.qualifier) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
- error.setLine(node->importIdToken.startLine);
- error.setColumn(node->importIdToken.startColumn);
- _parser->_errors << error;
- return false;
- }
- }
-
- } else if (import.type == QQmlScript::Import::Script) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Script import requires a qualifier"));
- error.setLine(node->fileNameToken.startLine);
- error.setColumn(node->fileNameToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- if (node->versionToken.isValid()) {
- extractVersion(textRefAt(node->versionToken), &import.majorVersion, &import.minorVersion);
- } else if (import.type == QQmlScript::Import::Library) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Library import requires a version"));
- error.setLine(node->importIdToken.startLine);
- error.setColumn(node->importIdToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
-
- import.location = location(startLoc, endLoc);
- import.uri = uri;
-
- _parser->_imports << import;
-
- return false;
-}
-
-bool ProcessAST::visit(AST::UiPragma *node)
-{
- QQmlScript::Pragma pragma;
-
- // For now the only valid pragma is Singleton, so lets validate the input
- if (!node->pragmaType->name.isNull())
- {
- if (QLatin1String("Singleton") == node->pragmaType->name)
- {
- pragma.type = QQmlScript::Pragma::Singleton;
- } else {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
- error.setLine(node->pragmaToken.startLine);
- error.setColumn(node->pragmaToken.startColumn);
- _parser->_errors << error;
- return false;
- }
- } else {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Pragma requires a valid qualifier"));
- error.setLine(node->pragmaToken.startLine);
- error.setColumn(node->pragmaToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- AST::SourceLocation startLoc = node->pragmaToken;
- AST::SourceLocation endLoc = node->semicolonToken;
- pragma.location = location(startLoc, endLoc);
- _parser->_pragmas << pragma;
-
- return false;
-}
-
-bool ProcessAST::visit(AST::UiPublicMember *node)
-{
- static const struct TypeNameToType {
- const char *name;
- size_t nameLength;
- Object::DynamicProperty::Type type;
- } propTypeNameToTypes[] = {
- { "int", strlen("int"), Object::DynamicProperty::Int },
- { "bool", strlen("bool"), Object::DynamicProperty::Bool },
- { "double", strlen("double"), Object::DynamicProperty::Real },
- { "real", strlen("real"), Object::DynamicProperty::Real },
- { "string", strlen("string"), Object::DynamicProperty::String },
- { "url", strlen("url"), Object::DynamicProperty::Url },
- { "color", strlen("color"), Object::DynamicProperty::Color },
- // Internally QTime, QDate and QDateTime are all supported.
- // To be more consistent with JavaScript we expose only
- // QDateTime as it matches closely with the Date JS type.
- // We also call it "date" to match.
- // { "time", strlen("time"), Object::DynamicProperty::Time },
- // { "date", strlen("date"), Object::DynamicProperty::Date },
- { "date", strlen("date"), Object::DynamicProperty::DateTime },
- { "rect", strlen("rect"), Object::DynamicProperty::Rect },
- { "point", strlen("point"), Object::DynamicProperty::Point },
- { "size", strlen("size"), Object::DynamicProperty::Size },
- { "font", strlen("font"), Object::DynamicProperty::Font },
- { "vector2d", strlen("vector2d"), Object::DynamicProperty::Vector2D },
- { "vector3d", strlen("vector3d"), Object::DynamicProperty::Vector3D },
- { "vector4d", strlen("vector4d"), Object::DynamicProperty::Vector4D },
- { "quaternion", strlen("quaternion"), Object::DynamicProperty::Quaternion },
- { "matrix4x4", strlen("matrix4x4"), Object::DynamicProperty::Matrix4x4 },
- { "variant", strlen("variant"), Object::DynamicProperty::Variant },
- { "var", strlen("var"), Object::DynamicProperty::Var }
- };
- static const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) /
- sizeof(propTypeNameToTypes[0]);
-
- if(node->type == AST::UiPublicMember::Signal) {
- Object::DynamicSignal *signal = _parser->_pool.New<Object::DynamicSignal>();
- signal->name = node->name;
-
- AST::UiParameterList *p = node->parameters;
- int paramLength = 0;
- while (p) { paramLength++; p = p->next; }
- p = node->parameters;
-
- if (paramLength) {
- signal->parameterTypes = _parser->_pool.NewRawList<Object::DynamicProperty::Type>(paramLength);
- signal->parameterTypeNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength);
- signal->parameterNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength);
- }
-
- int index = 0;
- while (p) {
- const QStringRef &memberType = p->type;
-
- if (memberType.isEmpty()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type"));
- error.setLine(node->typeToken.startLine);
- error.setColumn(node->typeToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- const TypeNameToType *type = 0;
- for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) {
- const TypeNameToType *t = propTypeNameToTypes + typeIndex;
- if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) {
- type = t;
- break;
- }
- }
-
- if (!type) {
- if (memberType.at(0).isUpper()) {
- // Must be a QML object type.
- // Lazily determine type during compilation.
- signal->parameterTypes[index] = Object::DynamicProperty::Custom;
- signal->parameterTypeNames[index] = QHashedStringRef(p->type);
- } else {
- QQmlError error;
- QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: ");
- errStr.append(memberType.toString());
- error.setDescription(errStr);
- error.setLine(node->typeToken.startLine);
- error.setColumn(node->typeToken.startColumn);
- _parser->_errors << error;
- return false;
- }
- } else {
- // the parameter is a known basic type
- signal->parameterTypes[index] = type->type;
- }
-
- signal->parameterNames[index] = QHashedStringRef(p->name);
- p = p->next;
- index++;
- }
-
- signal->location = location(node->typeToken, node->semicolonToken);
- _stateStack.top().object->dynamicSignals.append(signal);
- } else {
- const QStringRef &memberType = node->memberType;
- const QStringRef &name = node->name;
-
- bool typeFound = false;
- Object::DynamicProperty::Type type;
-
- if ((unsigned)memberType.length() == strlen("alias") &&
- QHashedString::compare(memberType.constData(), "alias", int(strlen("alias")))) {
- type = Object::DynamicProperty::Alias;
- typeFound = true;
- }
-
- for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
- const TypeNameToType *t = propTypeNameToTypes + ii;
- if (t->nameLength == size_t(memberType.length()) &&
- QHashedString::compare(memberType.constData(), t->name, int(t->nameLength))) {
- type = t->type;
- typeFound = true;
- }
- }
-
- if (!typeFound && memberType.at(0).isUpper()) {
- const QStringRef &typeModifier = node->typeModifier;
-
- if (typeModifier.isEmpty()) {
- type = Object::DynamicProperty::Custom;
- } else if ((unsigned)typeModifier.length() == strlen("list") &&
- QHashedString::compare(typeModifier.constData(), "list", int(strlen("list")))) {
- type = Object::DynamicProperty::CustomList;
- } else {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
- error.setLine(node->typeModifierToken.startLine);
- error.setColumn(node->typeModifierToken.startColumn);
- _parser->_errors << error;
- return false;
- }
- typeFound = true;
- } else if (!node->typeModifier.isNull()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
- error.setLine(node->typeModifierToken.startLine);
- error.setColumn(node->typeModifierToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- if(!typeFound) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Expected property type"));
- error.setLine(node->typeToken.startLine);
- error.setColumn(node->typeToken.startColumn);
- _parser->_errors << error;
- return false;
- }
-
- Object::DynamicProperty *property = _parser->_pool.New<Object::DynamicProperty>();
- property->isDefaultProperty = node->isDefaultMember;
- property->isReadOnly = node->isReadonlyMember;
- property->type = type;
- property->nameLocation.line = node->identifierToken.startLine;
- property->nameLocation.column = node->identifierToken.startColumn;
- if (type >= Object::DynamicProperty::Custom) {
- // This forces the type to be added to the resolved types list
- _parser->findOrCreateTypeId(memberType.toString(), _stateStack.top().object);
- property->customType = memberType;
- }
-
- property->name = QHashedStringRef(name);
- property->location = location(node->firstSourceLocation(),
- node->lastSourceLocation());
-
- if (node->statement) { // default value
- property->defaultValue = _parser->_pool.New<Property>();
- property->defaultValue->parent = _stateStack.top().object;
- property->defaultValue->location =
- location(node->statement->firstSourceLocation(),
- node->statement->lastSourceLocation());
- QQmlScript::Value *value = _parser->_pool.New<QQmlScript::Value>();
- value->location = location(node->statement->firstSourceLocation(),
- node->statement->lastSourceLocation());
- value->value = getVariant(node->statement);
- property->defaultValue->values.append(value);
- }
-
- _stateStack.top().object->dynamicProperties.append(property);
-
- // process QML-like initializers (e.g. property Object o: Object {})
- accept(node->binding);
- }
-
- return false;
-}
-
-
-// UiObjectMember: UiQualifiedId UiObjectInitializer ;
-bool ProcessAST::visit(AST::UiObjectDefinition *node)
-{
- LocationSpan l = location(node->firstSourceLocation(),
- node->lastSourceLocation());
-
- const QString objectType = asString(node->qualifiedTypeNameId);
- const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
-
- defineObjectBinding(node, /*propertyName = */ 0, false, objectType,
- typeLocation, l, node->initializer);
-
- return false;
-}
-
-
-// UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
-bool ProcessAST::visit(AST::UiObjectBinding *node)
-{
- LocationSpan l = location(node->qualifiedTypeNameId->identifierToken,
- node->initializer->rbraceToken);
-
- const QString objectType = asString(node->qualifiedTypeNameId);
- const AST::SourceLocation typeLocation = node->qualifiedTypeNameId->identifierToken;
-
- defineObjectBinding(node, node->qualifiedId, node->hasOnToken, objectType,
- typeLocation, l, node->initializer);
-
- return false;
-}
-
-QQmlScript::Variant ProcessAST::getVariant(AST::Statement *stmt)
-{
- if (stmt) {
- if (AST::ExpressionStatement *exprStmt = AST::cast<AST::ExpressionStatement *>(stmt))
- return getVariant(exprStmt->expression);
-
- return QQmlScript::Variant(asStringRef(stmt), stmt);
- }
-
- return QQmlScript::Variant();
-}
-
-QQmlScript::Variant ProcessAST::getVariant(AST::ExpressionNode *expr)
-{
- if (AST::StringLiteral *lit = AST::cast<AST::StringLiteral *>(expr)) {
- return QQmlScript::Variant(lit);
- } else if (expr->kind == AST::Node::Kind_TrueLiteral) {
- return QQmlScript::Variant(true);
- } else if (expr->kind == AST::Node::Kind_FalseLiteral) {
- return QQmlScript::Variant(false);
- } else if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(expr)) {
- return QQmlScript::Variant(lit->value, asStringRef(expr));
- } else {
-
- if (AST::UnaryMinusExpression *unaryMinus = AST::cast<AST::UnaryMinusExpression *>(expr)) {
- if (AST::NumericLiteral *lit = AST::cast<AST::NumericLiteral *>(unaryMinus->expression)) {
- return QQmlScript::Variant(-lit->value, asStringRef(expr));
- }
- }
-
- return QQmlScript::Variant(asStringRef(expr), expr);
- }
-}
-
-
-// UiObjectMember: UiQualifiedId T_COLON Statement ;
-bool ProcessAST::visit(AST::UiScriptBinding *node)
-{
- int propertyCount = 0;
- AST::UiQualifiedId *propertyName = node->qualifiedId;
- for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
- ++propertyCount;
- _stateStack.pushProperty(name->name,
- location(name));
- }
-
- Property *prop = currentProperty();
-
- if (!prop->values.isEmpty()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
- error.setLine(this->location(propertyName).start.line);
- error.setColumn(this->location(propertyName).start.column);
- _parser->_errors << error;
- return 0;
- }
-
- QQmlScript::Variant primitive;
-
- if (AST::ExpressionStatement *stmt = AST::cast<AST::ExpressionStatement *>(node->statement)) {
- primitive = getVariant(stmt->expression);
- } else { // do binding
- primitive = QQmlScript::Variant(asStringRef(node->statement), node->statement);
- }
-
- prop->location.range.length = prop->location.range.offset + prop->location.range.length - node->qualifiedId->identifierToken.offset;
- prop->location.range.offset = node->qualifiedId->identifierToken.offset;
- QQmlScript::Value *v = _parser->_pool.New<QQmlScript::Value>();
- v->value = primitive;
- v->location = location(node->statement->firstSourceLocation(),
- node->statement->lastSourceLocation());
-
- prop->addValue(v);
-
- while (propertyCount--)
- _stateStack.pop();
-
- return false;
-}
-
-// UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
-bool ProcessAST::visit(AST::UiArrayBinding *node)
-{
- int propertyCount = 0;
- AST::UiQualifiedId *propertyName = node->qualifiedId;
- for (AST::UiQualifiedId *name = propertyName; name; name = name->next){
- ++propertyCount;
- _stateStack.pushProperty(name->name,
- location(name));
- }
-
- Property* prop = currentProperty();
-
- if (!prop->values.isEmpty()) {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","Property value set multiple times"));
- error.setLine(this->location(propertyName).start.line);
- error.setColumn(this->location(propertyName).start.column);
- _parser->_errors << error;
- return false;
- }
-
- accept(node->members);
-
- // For the DOM, store the position of the T_LBRACKET upto the T_RBRACKET as the range:
- prop->listValueRange.offset = node->lbracketToken.offset;
- prop->listValueRange.length = node->rbracketToken.offset + node->rbracketToken.length - node->lbracketToken.offset;
-
- while (propertyCount--)
- _stateStack.pop();
-
- return false;
-}
-
-bool ProcessAST::visit(AST::UiSourceElement *node)
-{
- QQmlScript::Object *obj = currentObject();
-
- if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) {
-
- Object::DynamicSlot *slot = _parser->_pool.New<Object::DynamicSlot>();
- slot->location = location(funDecl->identifierToken, funDecl->lastSourceLocation());
-
- AST::FormalParameterList *f = funDecl->formals;
- while (f) {
- slot->parameterNames << f->name.toUtf8();
- f = f->next;
- }
-
- AST::SourceLocation loc = funDecl->rparenToken;
- loc.offset = loc.end();
- loc.startColumn += 1;
- slot->name = funDecl->name;
- slot->funcDecl = funDecl;
- obj->dynamicSlots.append(slot);
-
- } else {
- QQmlError error;
- error.setDescription(QCoreApplication::translate("QQmlParser","JavaScript declaration outside Script element"));
- error.setLine(node->firstSourceLocation().startLine);
- error.setColumn(node->firstSourceLocation().startColumn);
- _parser->_errors << error;
- }
- return false;
-}
-
-} // end of anonymous namespace
-
-
-QQmlScript::Parser::Parser()
-: root(0), _qmlRoot(0), data(0)
-{
-
-}
-
-QQmlScript::Parser::~Parser()
-{
- clear();
-}
-
-namespace QQmlScript {
-class ParserJsASTData
-{
-public:
- ParserJsASTData(const QString &filename)
- : filename(filename) {}
-
- QString filename;
- Engine engine;
-};
-}
-
-QByteArray QQmlScript::Parser::preparseData() const
-{
- return QByteArray();
-}
-
-bool QQmlScript::Parser::parse(const QString &qmlcode, const QByteArray & /* preparseData */,
- const QUrl &url, const QString &urlString)
-{
- clear();
-
- if (urlString.isEmpty()) {
- _scriptFile = url.toString();
- } else {
- // Q_ASSERT(urlString == url.toString());
- _scriptFile = urlString;
- }
-
- QString *code = _pool.NewString(qmlcode);
-
- data = new QQmlScript::ParserJsASTData(_scriptFile);
-
- Lexer lexer(&data->engine);
- lexer.setCode(*code, /*line = */ 1);
-
- QQmlJS::Parser parser(&data->engine);
-
- if (! parser.parse() || !parser.diagnosticMessages().isEmpty()) {
-
- // Extract errors from the parser
- foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) {
-
- if (m.isWarning()) {
- qWarning("%s:%d : %s", qPrintable(_scriptFile), m.loc.startLine, qPrintable(m.message));
- continue;
- }
-
- QQmlError error;
- error.setUrl(url);
- error.setDescription(m.message);
- error.setLine(m.loc.startLine);
- error.setColumn(m.loc.startColumn);
- _errors << error;
-
- }
- }
-
- if (_errors.isEmpty()) {
- ProcessAST process(this);
- process(*code, parser.ast());
-
- // Set the url for process errors
- for(int ii = 0; ii < _errors.count(); ++ii)
- _errors[ii].setUrl(url);
- }
-
- _qmlRoot = parser.ast();
-
- return _errors.isEmpty();
-}
-
-QList<QQmlScript::TypeReference*> QQmlScript::Parser::referencedTypes() const
-{
- return _refTypes;
-}
-
-QQmlScript::Object *QQmlScript::Parser::tree() const
-{
- return root;
-}
-
-QList<QQmlScript::Import> QQmlScript::Parser::imports() const
-{
- return _imports;
-}
-
-QList<QQmlScript::Pragma> QQmlScript::Parser::pragmas() const
-{
- return _pragmas;
-}
-
-QList<QQmlError> QQmlScript::Parser::errors() const
-{
- return _errors;
-}
-
static void replaceWithSpace(QString &str, int idx, int n)
{
QChar *data = str.data() + idx;
@@ -1540,6 +187,24 @@ static inline bool isUriToken(int token)
return false;
}
+static void extractVersion(QStringRef string, int *maj, int *min)
+{
+ *maj = -1; *min = -1;
+
+ if (!string.isEmpty()) {
+
+ int dot = string.indexOf(QLatin1Char('.'));
+
+ if (dot < 0) {
+ *maj = string.toInt();
+ *min = 0;
+ } else {
+ *maj = string.left(dot).toInt();
+ *min = string.mid(dot + 1).toInt();
+ }
+ }
+}
+
QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QString &script, QQmlError *error)
{
Q_ASSERT(error);
@@ -1670,7 +335,7 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
}
int vmaj, vmin;
- ProcessAST::extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()),
+ extractVersion(QStringRef(&script, l.tokenOffset(), l.tokenLength()),
&vmaj, &vmin);
bool invalidImport = false;
@@ -1749,46 +414,4 @@ QQmlScript::Parser::JavaScriptMetaData QQmlScript::Parser::extractMetaData(QStri
return rv;
}
-void QQmlScript::Parser::clear()
-{
- _pragmas.clear();
- _imports.clear();
- _refTypes.clear();
- _errors.clear();
-
- if (data) {
- delete data;
- data = 0;
- }
-
- _pool.clear();
- _qmlRoot = 0;
-}
-
-int QQmlScript::Parser::findOrCreateTypeId(const QString &name, Object *object)
-{
- for (int ii = 0; ii < _refTypes.size(); ++ii) {
- if (_refTypes.at(ii)->name == name)
- return ii;
- }
-
- TypeReference *type = _pool.New<TypeReference>();
- type->name = name;
- type->firstUse = object;
- _refTypes.append(type);
- return _refTypes.size() - 1;
-}
-
-void QQmlScript::Parser::setTree(QQmlScript::Object *tree)
-{
- Q_ASSERT(! root);
-
- root = tree;
-}
-
-Engine *QQmlScript::Parser::jsEngine() const
-{
- return data ? &data->engine : 0;
-}
-
QT_END_NAMESPACE