123bool QQmlDirParser::parse(
const QString &source)
125 quint16 lineNumber = 0;
126 bool firstLine =
true;
128 auto readImport = [&](
const QString *sections,
int sectionCount, Import::Flags flags) {
130 if (sectionCount == 2) {
131 import = Import(sections[1], QTypeRevision(), flags);
132 }
else if (sectionCount == 3) {
133 if (sections[2] == QLatin1String(
"auto")) {
134 import = Import(sections[1], QTypeRevision(), flags | Import::Auto);
136 const auto version = parseVersion(sections[2]);
137 if (version.isValid()) {
138 import = Import(sections[1], version, flags);
140 reportError(lineNumber, 0,
141 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
147 reportError(lineNumber, 0,
148 QStringLiteral(
"%1 requires 1 or 2 arguments, but %2 were provided")
149 .arg(sections[0]).arg(sectionCount - 1));
152 if (sections[0] == QStringLiteral(
"import"))
153 _imports.append(import);
155 _dependencies.append(import);
159 auto readPlugin = [&](
const QString *sections,
int sectionCount,
bool isOptional) {
160 if (sectionCount < 2 || sectionCount > 3) {
161 reportError(lineNumber, 0, QStringLiteral(
"plugin directive requires one or two "
162 "arguments, but %1 were provided")
163 .arg(sectionCount - 1));
167 const Plugin entry(sections[1], sections[2], isOptional);
168 _plugins.append(entry);
172 const QChar *ch = source.constData();
173 while (!ch->isNull()) {
176 bool invalidLine =
false;
177 const QChar *lineStart = ch;
180 if (*ch == QLatin1Char(
'\n')) {
188 int sectionCount = 0;
191 if (*ch == QLatin1Char(
'#')) {
196 if (sectionCount >= 4) {
197 reportError(lineNumber, ch - lineStart, QLatin1String(
"unexpected token"));
203 sections[sectionCount++] = (*ch == QLatin1Char(
'"'))
204 ? scanQuotedWord(ch, lineNumber, ch - lineStart)
208 }
while (*ch != QLatin1Char(
'\n') && !ch->isNull());
214 reportError(lineNumber, 0,
215 QStringLiteral(
"invalid qmldir directive contains too many tokens"));
217 }
else if (sectionCount == 0) {
220 }
else if (sections[0] == QLatin1String(
"module")) {
221 if (sectionCount != 2) {
222 reportError(lineNumber, 0,
223 QStringLiteral(
"module identifier directive requires one argument, but %1 were provided").arg(sectionCount - 1));
226 if (!_typeNamespace.isEmpty()) {
227 reportError(lineNumber, 0,
228 QStringLiteral(
"only one module identifier directive may be defined in a qmldir file"));
232 reportError(lineNumber, 0,
233 QStringLiteral(
"module identifier directive must be the first directive in a qmldir file"));
237 _typeNamespace = sections[1];
239 }
else if (sections[0] == QLatin1String(
"plugin")) {
240 if (!readPlugin(sections, sectionCount,
false))
242 }
else if (sections[0] == QLatin1String(
"optional")) {
243 if (sectionCount < 2) {
244 reportError(lineNumber, 0, QStringLiteral(
"optional directive requires further "
245 "arguments, but none were provided."));
249 if (sections[1] == QStringLiteral(
"plugin")) {
250 if (!readPlugin(sections + 1, sectionCount - 1,
true))
252 }
else if (sections[1] == QLatin1String(
"import")) {
253 if (!readImport(sections + 1, sectionCount - 1, Import::Optional))
256 reportError(lineNumber, 0, QStringLiteral(
"only import and plugin can be optional, "
257 "not %1.").arg(sections[1]));
260 }
else if (sections[0] == QLatin1String(
"default")) {
261 if (sectionCount < 2) {
262 reportError(lineNumber, 0,
263 QStringLiteral(
"default directive requires further "
264 "arguments, but none were provided."));
267 if (sections[1] == QLatin1String(
"import")) {
268 if (!readImport(sections + 1, sectionCount - 1,
269 Import::Flags({ Import::Optional, Import::OptionalDefault })))
272 reportError(lineNumber, 0,
273 QStringLiteral(
"only optional imports can have a default, "
277 }
else if (sections[0] == QLatin1String(
"classname")) {
278 if (sectionCount < 2) {
279 reportError(lineNumber, 0,
280 QStringLiteral(
"classname directive requires an argument, but %1 were provided").arg(sectionCount - 1));
285 _classNames.append(sections[1]);
287 }
else if (sections[0] == QLatin1String(
"internal")) {
288 if (sectionCount == 3) {
289 Component entry(sections[1], sections[2], QTypeRevision());
290 entry.internal =
true;
291 _components.insert(entry.typeName, entry);
292 }
else if (sectionCount == 4) {
293 const QTypeRevision version = parseVersion(sections[2]);
294 if (version.isValid()) {
295 Component entry(sections[1], sections[3], version);
296 entry.internal =
true;
297 _components.insert(entry.typeName, entry);
299 reportError(lineNumber, 0,
300 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
305 reportError(lineNumber, 0,
306 QStringLiteral(
"internal types require 2 or 3 arguments, "
307 "but %1 were provided").arg(sectionCount - 1));
310 }
else if (sections[0] == QLatin1String(
"singleton")) {
311 if (sectionCount < 3 || sectionCount > 4) {
312 reportError(lineNumber, 0,
313 QStringLiteral(
"singleton types require 2 or 3 arguments, but %1 were provided").arg(sectionCount - 1));
315 }
else if (sectionCount == 3) {
318 Component entry(sections[1], sections[2], QTypeRevision());
319 entry.singleton =
true;
320 _components.insert(entry.typeName, entry);
324 const QTypeRevision version = parseVersion(sections[2]);
325 if (version.isValid()) {
326 const QString &fileName = sections[3];
327 Component entry(sections[1], fileName, version);
328 entry.singleton =
true;
329 _components.insert(entry.typeName, entry);
331 reportError(lineNumber, 0, QStringLiteral(
"invalid version %1, expected <major>.<minor>").arg(sections[2]));
334 }
else if (sections[0] == QLatin1String(
"typeinfo")) {
335 if (sectionCount != 2) {
336 reportError(lineNumber, 0,
337 QStringLiteral(
"typeinfo requires 1 argument, but %1 were provided").arg(sectionCount - 1));
340 _typeInfos.append(sections[1]);
341 }
else if (sections[0] == QLatin1String(
"designersupported")) {
342 if (sectionCount != 1)
343 reportError(lineNumber, 0, QStringLiteral(
"designersupported does not expect any argument"));
345 _designerSupported =
true;
346 }
else if (sections[0] == QLatin1String(
"static")) {
347 if (sectionCount != 1)
348 reportError(lineNumber, 0, QStringLiteral(
"static does not expect any argument"));
350 _isStaticModule =
true;
351 }
else if (sections[0] == QLatin1String(
"system")) {
352 if (sectionCount != 1)
353 reportError(lineNumber, 0, QStringLiteral(
"system does not expect any argument"));
355 _isSystemModule =
true;
356 }
else if (sections[0] == QLatin1String(
"import")
357 || sections[0] == QLatin1String(
"depends")) {
358 if (!readImport(sections, sectionCount, Import::Default))
360 }
else if (sections[0] == QLatin1String(
"prefer")) {
361 if (sectionCount < 2) {
362 reportError(lineNumber, 0,
363 QStringLiteral(
"prefer directive requires one argument, "
364 "but %1 were provided").arg(sectionCount - 1));
368 if (!_preferredPath.isEmpty()) {
369 reportError(lineNumber, 0, QStringLiteral(
370 "only one prefer directive may be defined in a qmldir file"));
374 if (!sections[1].endsWith(u'/')) {
376 reportError(lineNumber, 0, QStringLiteral(
377 "the preferred directory has to end with a '/'"));
381 _preferredPath = sections[1];
382 }
else if (sections[0] == QLatin1String(
"linktarget")) {
383 if (sectionCount < 2) {
384 reportError(lineNumber, 0,
385 QStringLiteral(
"linktarget directive requires an argument, "
386 "but %1 were provided")
387 .arg(sectionCount - 1));
391 if (!_linkTarget.isEmpty()) {
395 "only one linktarget directive may be defined in a qmldir file"));
399 _linkTarget = sections[1];
400 }
else if (sectionCount == 2) {
402 insertComponentOrScript(sections[0], sections[1], QTypeRevision());
403 }
else if (sectionCount == 3) {
404 const QTypeRevision version = parseVersion(sections[1]);
405 if (version.isValid()) {
406 insertComponentOrScript(sections[0], sections[2], version);
410 QStringLiteral(
"invalid version %1, expected <major>.<minor>")
414 reportError(lineNumber, 0,
415 QStringLiteral(
"a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));