120bool QQmlDirParser::parse(
const QString &source)
122 quint16 lineNumber = 0;
123 bool firstLine =
true;
125 auto readImport = [&](
const QString *sections,
int sectionCount, Import::Flags flags) {
127 if (sectionCount == 2) {
128 import = Import(sections[1], QTypeRevision(), flags);
129 }
else if (sectionCount == 3) {
130 if (sections[2] == QLatin1String(
"auto")) {
131 import = Import(sections[1], QTypeRevision(), flags | Import::Auto);
133 const auto version = parseVersion(sections[2]);
134 if (version.isValid()) {
135 import = Import(sections[1], version, flags);
137 reportError(lineNumber, 0,
138 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
144 reportError(lineNumber, 0,
145 QStringLiteral(
"%1 requires 1 or 2 arguments, but %2 were provided")
146 .arg(sections[0]).arg(sectionCount - 1));
149 if (sections[0] == QStringLiteral(
"import"))
150 _imports.append(import);
152 _dependencies.append(import);
156 auto readPlugin = [&](
const QString *sections,
int sectionCount,
bool isOptional) {
157 if (sectionCount < 2 || sectionCount > 3) {
158 reportError(lineNumber, 0, QStringLiteral(
"plugin directive requires one or two "
159 "arguments, but %1 were provided")
160 .arg(sectionCount - 1));
164 const Plugin entry(sections[1], sections[2], isOptional);
165 _plugins.append(entry);
169 const QChar *ch = source.constData();
170 while (!ch->isNull()) {
173 bool invalidLine =
false;
174 const QChar *lineStart = ch;
177 if (*ch == QLatin1Char(
'\n')) {
185 int sectionCount = 0;
188 if (*ch == QLatin1Char(
'#')) {
193 if (sectionCount >= 4) {
194 reportError(lineNumber, ch - lineStart, QLatin1String(
"unexpected token"));
200 sections[sectionCount++] = (*ch == QLatin1Char(
'"'))
201 ? scanQuotedWord(ch, lineNumber, ch - lineStart)
205 }
while (*ch != QLatin1Char(
'\n') && !ch->isNull());
211 reportError(lineNumber, 0,
212 QStringLiteral(
"invalid qmldir directive contains too many tokens"));
214 }
else if (sectionCount == 0) {
217 }
else if (sections[0] == QLatin1String(
"module")) {
218 if (sectionCount != 2) {
219 reportError(lineNumber, 0,
220 QStringLiteral(
"module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1));
223 if (!_typeNamespace.isEmpty()) {
224 reportError(lineNumber, 0,
225 QStringLiteral(
"only one module identifier directive may be defined in a qmldir file"));
229 reportError(lineNumber, 0,
230 QStringLiteral(
"module identifier directive must be the first directive in a qmldir file"));
234 _typeNamespace = sections[1];
236 }
else if (sections[0] == QLatin1String(
"plugin")) {
237 if (!readPlugin(sections, sectionCount,
false))
239 }
else if (sections[0] == QLatin1String(
"optional")) {
240 if (sectionCount < 2) {
241 reportError(lineNumber, 0, QStringLiteral(
"optional directive requires further "
242 "arguments, but none were provided."));
246 if (sections[1] == QStringLiteral(
"plugin")) {
247 if (!readPlugin(sections + 1, sectionCount - 1,
true))
249 }
else if (sections[1] == QLatin1String(
"import")) {
250 if (!readImport(sections + 1, sectionCount - 1, Import::Optional))
253 reportError(lineNumber, 0, QStringLiteral(
"only import and plugin can be optional, "
254 "not %1.").arg(sections[1]));
257 }
else if (sections[0] == QLatin1String(
"default")) {
258 if (sectionCount < 2) {
259 reportError(lineNumber, 0,
260 QStringLiteral(
"default directive requires further "
261 "arguments, but none were provided."));
264 if (sections[1] == QLatin1String(
"import")) {
265 if (!readImport(sections + 1, sectionCount - 1,
266 Import::Flags({ Import::Optional, Import::OptionalDefault })))
269 reportError(lineNumber, 0,
270 QStringLiteral(
"only optional imports can have a default, "
274 }
else if (sections[0] == QLatin1String(
"classname")) {
275 if (sectionCount < 2) {
276 reportError(lineNumber, 0,
277 QStringLiteral(
"classname directive requires an argument, but %1 were provided").arg(sectionCount - 1));
282 _classNames.append(sections[1]);
284 }
else if (sections[0] == QLatin1String(
"internal")) {
285 if (sectionCount == 3) {
286 Component entry(sections[1], sections[2], QTypeRevision());
287 entry.internal =
true;
288 _components.insert(entry.typeName, entry);
289 }
else if (sectionCount == 4) {
290 const QTypeRevision version = parseVersion(sections[2]);
291 if (version.isValid()) {
292 Component entry(sections[1], sections[3], version);
293 entry.internal =
true;
294 _components.insert(entry.typeName, entry);
296 reportError(lineNumber, 0,
297 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
302 reportError(lineNumber, 0,
303 QStringLiteral(
"internal types require 2 or 3 arguments, "
304 "but %1 were provided").arg(sectionCount - 1));
307 }
else if (sections[0] == QLatin1String(
"singleton")) {
308 if (sectionCount < 3 || sectionCount > 4) {
309 reportError(lineNumber, 0,
310 QStringLiteral(
"singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
312 }
else if (sectionCount == 3) {
315 Component entry(sections[1], sections[2], QTypeRevision());
316 entry.singleton =
true;
317 _components.insert(entry.typeName, entry);
321 const QTypeRevision version = parseVersion(sections[2]);
322 if (version.isValid()) {
323 const QString &fileName = sections[3];
324 Component entry(sections[1], fileName, version);
325 entry.singleton =
true;
326 _components.insert(entry.typeName, entry);
328 reportError(lineNumber, 0, QStringLiteral(
"invalid version %1, expected <major>.<minor>").arg(sections[2]));
331 }
else if (sections[0] == QLatin1String(
"typeinfo")) {
332 if (sectionCount != 2) {
333 reportError(lineNumber, 0,
334 QStringLiteral(
"typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
337 _typeInfos.append(sections[1]);
338 }
else if (sections[0] == QLatin1String(
"designersupported")) {
339 if (sectionCount != 1)
340 reportError(lineNumber, 0, QStringLiteral(
"designersupported does not expect any argument"));
342 _designerSupported =
true;
343 }
else if (sections[0] == QLatin1String(
"static")) {
344 if (sectionCount != 1)
345 reportError(lineNumber, 0, QStringLiteral(
"static does not expect any argument"));
347 _isStaticModule =
true;
348 }
else if (sections[0] == QLatin1String(
"system")) {
349 if (sectionCount != 1)
350 reportError(lineNumber, 0, QStringLiteral(
"system does not expect any argument"));
352 _isSystemModule =
true;
353 }
else if (sections[0] == QLatin1String(
"import")
354 || sections[0] == QLatin1String(
"depends")) {
355 if (!readImport(sections, sectionCount, Import::Default))
357 }
else if (sections[0] == QLatin1String(
"prefer")) {
358 if (sectionCount < 2) {
359 reportError(lineNumber, 0,
360 QStringLiteral(
"prefer directive requires one argument, "
361 "but %1 were provided").arg(sectionCount - 1));
365 if (!_preferredPath.isEmpty()) {
366 reportError(lineNumber, 0, QStringLiteral(
367 "only one prefer directive may be defined in a qmldir file"));
371 if (!sections[1].endsWith(u'/')) {
373 reportError(lineNumber, 0, QStringLiteral(
374 "the preferred directory has to end with a '/'"));
378 _preferredPath = sections[1];
379 }
else if (sections[0] == QLatin1String(
"linktarget")) {
380 if (sectionCount < 2) {
381 reportError(lineNumber, 0,
382 QStringLiteral(
"linktarget directive requires an argument, "
383 "but %1 were provided")
384 .arg(sectionCount - 1));
388 if (!_linkTarget.isEmpty()) {
392 "only one linktarget directive may be defined in a qmldir file"));
396 _linkTarget = sections[1];
397 }
else if (sectionCount == 2) {
399 insertComponentOrScript(sections[0], sections[1], QTypeRevision());
400 }
else if (sectionCount == 3) {
401 const QTypeRevision version = parseVersion(sections[1]);
402 if (version.isValid()) {
403 insertComponentOrScript(sections[0], sections[2], version);
407 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
411 reportError(lineNumber, 0,
412 QStringLiteral(
"a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));