1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlcustomparser_p.h"
41
42#include <private/qv4compileddata_p.h>
43
44#include <QtCore/qdebug.h>
45
46QT_BEGIN_NAMESPACE
47
48/*!
49 \class QQmlCustomParser
50 \brief The QQmlCustomParser class allows you to add new arbitrary types to QML.
51 \internal
52
53 By subclassing QQmlCustomParser, you can add a parser for
54 building a particular type.
55
56 The subclass must implement compile() and setCustomData(), and register
57 itself in the meta type system by calling the macro:
58
59 \code
60 QML_REGISTER_CUSTOM_TYPE(Module, MajorVersion, MinorVersion, Name, TypeClass, ParserClass)
61 \endcode
62*/
63
64/*
65 \fn QByteArray QQmlCustomParser::compile(const QList<QQmlCustomParserProperty> & properties)
66
67 The custom parser processes \a properties, and returns
68 a QByteArray containing data meaningful only to the
69 custom parser; the type engine will pass this same data to
70 setCustomData() when making an instance of the data.
71
72 Errors must be reported via the error() functions.
73
74 The QByteArray may be cached between executions of the system, so
75 it must contain correctly-serialized data (not, for example,
76 pointers to stack objects).
77*/
78
79/*
80 \fn void QQmlCustomParser::setCustomData(QObject *object, const QByteArray &data)
81
82 This function sets \a object to have the properties defined
83 by \a data, which is a block of data previously returned by a call
84 to compile().
85
86 Errors should be reported using qmlWarning(object).
87
88 The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE.
89*/
90
91void QQmlCustomParser::clearErrors()
92{
93 exceptions.clear();
94}
95
96/*!
97 Reports an error with the given \a description.
98
99 An error is generated referring to the \a location in the source file.
100*/
101void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
102{
103 QQmlJS::DiagnosticMessage error;
104 error.line = location.line;
105 error.column = location.column;
106 error.message = description;
107
108 exceptions << error;
109}
110
111struct StaticQtMetaObject : public QObject
112{
113 static const QMetaObject *get()
114 { return &staticQtMetaObject; }
115};
116
117/*!
118 If \a script is a simple enumeration expression (eg. Text.AlignLeft),
119 returns the integer equivalent (eg. 1), and sets \a ok to true.
120
121 Otherwise sets \a ok to false.
122
123 A valid \a ok must be provided, or the function will assert.
124*/
125int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
126{
127 Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
128 *ok = false;
129
130 // we support one or two '.' in the enum phrase:
131 // * <TypeName>.<EnumValue>
132 // * <TypeName>.<ScopedEnumName>.<EnumValue>
133
134 int dot = script.indexOf('.');
135 if (dot == -1 || dot == script.length()-1)
136 return -1;
137
138 QString scope = QString::fromUtf8(script.left(dot));
139
140 if (scope != QLatin1String("Qt")) {
141 if (imports.isNull())
142 return -1;
143 QQmlType type;
144
145 if (imports.isT1()) {
146 imports.asT1()->resolveType(scope, &type, nullptr, nullptr, nullptr);
147 } else {
148 QQmlTypeNameCache::Result result = imports.asT2()->query(scope);
149 if (result.isValid())
150 type = result.type;
151 }
152
153 if (!type.isValid())
154 return -1;
155
156 int dot2 = script.indexOf('.', dot+1);
157 const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1;
158 QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
159 QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
160 if (!scopedEnumName.isEmpty())
161 return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok);
162 else
163 return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
164 }
165
166 QByteArray enumValue = script.mid(dot + 1);
167 const QMetaObject *mo = StaticQtMetaObject::get();
168 int i = mo->enumeratorCount();
169 while (i--) {
170 int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
171 if (*ok)
172 return v;
173 }
174 return -1;
175}
176
177/*!
178 Resolves \a name to a type, or 0 if it is not a type. This can be used
179 to type-check object nodes.
180*/
181const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
182{
183 if (!imports.isT1())
184 return nullptr;
185 QQmlType qmltype;
186 if (!imports.asT1()->resolveType(name, &qmltype, nullptr, nullptr, nullptr))
187 return nullptr;
188 return qmltype.metaObject();
189}
190
191QT_END_NAMESPACE
192