Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/qt
diff options
context:
space:
mode:
authorMatthew Bastien2015-12-09 19:57:25 +0000
committerMatthew Bastien2015-12-09 19:58:22 +0000
commit1d36f36ef8ad75c676ed1ddc2e2d6a2e2dffa1a7 (patch)
tree5cf99758f7ffa936dd065ab0d638b7156bfaf102 /qt
parentc5d03dddb627745957ca2eb90af3cc72719f79eb (diff)
downloadorg.eclipse.cdt-1d36f36ef8ad75c676ed1ddc2e2d6a2e2dffa1a7.tar.gz
org.eclipse.cdt-1d36f36ef8ad75c676ed1ddc2e2d6a2e2dffa1a7.tar.xz
org.eclipse.cdt-1d36f36ef8ad75c676ed1ddc2e2d6a2e2dffa1a7.zip
Bug 481126 - QML Directory File Parsing
Added a new parser that is able to construct an AST for a given qmldir file. Added tests to ensure the parser works for standard qmldir files. Change-Id: I292aace3cdec8b4a544033f80812df965fef50b8 Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
Diffstat (limited to 'qt')
-rw-r--r--qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryLexerTests.java287
-rw-r--r--qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryParserTests.java308
-rw-r--r--qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF6
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/Position.java38
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/SourceLocation.java58
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirAST.java36
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirASTNode.java55
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirClassnameCommand.java28
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirCommentCommand.java28
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDependsCommand.java38
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDesignerSupportedCommand.java16
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirInternalCommand.java38
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirModuleCommand.java27
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirPluginCommand.java38
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirResourceCommand.java47
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSingletonCommand.java48
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSyntaxError.java40
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirTypeInfoCommand.java28
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirVersion.java28
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirWord.java28
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/IPosition.java30
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/ISourceLocation.java38
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirAST.java26
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirASTNode.java41
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirClassnameCommand.java25
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommand.java19
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommentCommand.java25
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDependsCommand.java32
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDesignerSupportedCommand.java19
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirInternalCommand.java32
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirModuleCommand.java25
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirPluginCommand.java32
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirResourceCommand.java39
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSingletonCommand.java39
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSyntaxError.java43
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirTypeInfoCommand.java25
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirVersion.java23
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirWord.java27
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryLexer.java252
-rw-r--r--qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryParser.java423
40 files changed, 2434 insertions, 1 deletions
diff --git a/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryLexerTests.java b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryLexerTests.java
new file mode 100644
index 00000000000..316430fa4d8
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryLexerTests.java
@@ -0,0 +1,287 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.tests;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.eclipse.cdt.internal.qt.core.location.Position;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.Token;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.TokenType;
+import org.junit.Test;
+
+@SuppressWarnings("nls")
+public class QMLDirectoryLexerTests {
+ private void assertToken(TokenType type, String text, int start, int end, Position locStart, Position locEnd, Token actual) {
+ // Check token type and text
+ assertEquals("Unexpected token type", type, actual.getType());
+ assertEquals("Unexpected token text", text, actual.getText());
+
+ // Check position offsets
+ assertEquals("Unexpected start position", start, actual.getStart());
+ assertEquals("Unexpected end position", end, actual.getEnd());
+
+ // Check SourceLocation start
+ assertEquals("Unexpected location start line", locStart.getLine(), actual.getLocation().getStart().getLine());
+ assertEquals("Unexpected location start column", locStart.getColumn(), actual.getLocation().getStart().getColumn());
+
+ // Check SourceLocation end
+ assertEquals("Unexpected location end line", locEnd.getLine(), actual.getLocation().getEnd().getLine());
+ assertEquals("Unexpected location end column", locEnd.getColumn(), actual.getLocation().getEnd().getColumn());
+ }
+
+ private InputStream createInputStream(String s) {
+ return new ByteArrayInputStream(s.getBytes());
+ }
+
+ @Test
+ public void testCommentToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(new ByteArrayInputStream("# This is a comment".getBytes()));
+ assertToken(TokenType.COMMENT,
+ "# This is a comment",
+ 0, 19,
+ new Position(1, 0), new Position(1, 19),
+ lexer.nextToken(false));
+ }
+
+ @Test
+ public void testMultipleCommentTokens() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("# This is a comment\n# This is another comment\n"));
+ assertToken(TokenType.COMMENT,
+ "# This is a comment",
+ 0, 19,
+ new Position(1, 0), new Position(1, 19),
+ lexer.nextToken(false));
+ assertEquals(TokenType.COMMAND_END, lexer.nextToken(false).getType());
+ assertToken(TokenType.COMMENT,
+ "# This is another comment",
+ 20, 45,
+ new Position(2, 0), new Position(2, 25),
+ lexer.nextToken(false));
+ assertEquals(TokenType.COMMAND_END, lexer.nextToken(false).getType());
+ assertEquals(TokenType.EOF, lexer.nextToken(false).getType());
+ }
+
+ @Test
+ public void testModuleToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("module"));
+ assertToken(TokenType.MODULE,
+ "module",
+ 0, 6,
+ new Position(1, 0), new Position(1, 6),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testTypeInfoToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("typeinfo"));
+ assertToken(TokenType.TYPEINFO,
+ "typeinfo",
+ 0, 8,
+ new Position(1, 0), new Position(1, 8),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testSingletonToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("singleton"));
+ assertToken(TokenType.SINGLETON,
+ "singleton",
+ 0, 9,
+ new Position(1, 0), new Position(1, 9),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testInternalToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("internal"));
+ assertToken(TokenType.INTERNAL,
+ "internal",
+ 0, 8,
+ new Position(1, 0), new Position(1, 8),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testPluginToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("plugin"));
+ assertToken(TokenType.PLUGIN,
+ "plugin",
+ 0, 6,
+ new Position(1, 0), new Position(1, 6),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testClassnameToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("classname"));
+ assertToken(TokenType.CLASSNAME,
+ "classname",
+ 0, 9,
+ new Position(1, 0), new Position(1, 9),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testDependsToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("depends"));
+ assertToken(TokenType.DEPENDS,
+ "depends",
+ 0, 7,
+ new Position(1, 0), new Position(1, 7),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testDesignerSupportedToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("designersupported"));
+ assertToken(TokenType.DESIGNERSUPPORTED,
+ "designersupported",
+ 0, 17,
+ new Position(1, 0), new Position(1, 17),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWordToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("QtQuick.Control"));
+ assertToken(TokenType.WORD,
+ "QtQuick.Control",
+ 0, 15,
+ new Position(1, 0), new Position(1, 15),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWordTokenContainsKeyword() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("plugins.test"));
+ assertToken(TokenType.WORD,
+ "plugins.test",
+ 0, 12,
+ new Position(1, 0), new Position(1, 12),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWordTokenAsRelativePath() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("./test/something/"));
+ assertToken(TokenType.WORD,
+ "./test/something/",
+ 0, 17,
+ new Position(1, 0), new Position(1, 17),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWordTokenAsAbsoluteWindowsPath() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("C:\\Users\\someone\\test\\something\\"));
+ assertToken(TokenType.WORD,
+ "C:\\Users\\someone\\test\\something\\",
+ 0, 32,
+ new Position(1, 0), new Position(1, 32),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWordTokenAsAbsoluteUnixPath() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("/usr/local/test/something/"));
+ assertToken(TokenType.WORD,
+ "/usr/local/test/something/",
+ 0, 26,
+ new Position(1, 0), new Position(1, 26),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testDecimalToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("2.3"));
+ assertToken(TokenType.DECIMAL,
+ "2.3",
+ 0, 3,
+ new Position(1, 0), new Position(1, 3),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testIntegerToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("3"));
+ assertToken(TokenType.INTEGER,
+ "3",
+ 0, 1,
+ new Position(1, 0), new Position(1, 1),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testWhitespaceToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream(" \t\n"));
+ assertToken(TokenType.WHITESPACE,
+ " \t",
+ 0, 2,
+ new Position(1, 0), new Position(1, 2),
+ lexer.nextToken(false));
+ }
+
+ @Test
+ public void testCommandEndToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("\n"));
+ assertToken(TokenType.COMMAND_END,
+ "\\n",
+ 0, 1,
+ new Position(1, 0), new Position(1, 1),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testEOFToken() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream(""));
+ assertToken(TokenType.EOF,
+ "",
+ 0, 0,
+ new Position(1, 0), new Position(1, 0),
+ lexer.nextToken());
+ }
+
+ @Test
+ public void testEOFTokenAfterCommand() {
+ QMLDirectoryLexer lexer = new QMLDirectoryLexer();
+ lexer.setInput(createInputStream("\n"));
+ lexer.nextToken();
+ assertToken(TokenType.EOF,
+ "",
+ 1, 1,
+ new Position(2, 0), new Position(2, 0),
+ lexer.nextToken());
+ }
+}
diff --git a/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryParserTests.java b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryParserTests.java
new file mode 100644
index 00000000000..74333f01e29
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryParserTests.java
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.tests;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.eclipse.cdt.internal.qt.core.location.Position;
+import org.eclipse.cdt.qt.core.location.IPosition;
+import org.eclipse.cdt.qt.core.qmldir.IQDirAST;
+import org.eclipse.cdt.qt.core.qmldir.IQDirASTNode;
+import org.eclipse.cdt.qt.core.qmldir.IQDirClassnameCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirCommentCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirDependsCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirDesignerSupportedCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirInternalCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirModuleCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirPluginCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirResourceCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirSingletonCommand;
+import org.eclipse.cdt.qt.core.qmldir.IQDirSyntaxError;
+import org.eclipse.cdt.qt.core.qmldir.IQDirTypeInfoCommand;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryParser;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryParser.SyntaxError;
+import org.junit.Test;
+
+@SuppressWarnings("nls")
+public class QMLDirectoryParserTests {
+
+ public void assertLocation(int start, int end, IPosition locStart, IPosition locEnd, IQDirASTNode node) {
+ // Check position offsets
+ assertEquals("Unexpected start position", start, node.getStart());
+ assertEquals("Unexpected end position", end, node.getEnd());
+
+ // Check SourceLocation start
+ assertEquals("Unexpected location start line", locStart.getLine(), node.getLocation().getStart().getLine());
+ assertEquals("Unexpected location start column", locStart.getColumn(), node.getLocation().getStart().getColumn());
+ }
+
+ private InputStream createInputStream(String s) {
+ return new ByteArrayInputStream(s.getBytes());
+ }
+
+ @Test
+ public void testModuleCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("module QtQuick.Controls\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirModuleCommand.class));
+ IQDirModuleCommand mod = (IQDirModuleCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected qualified ID", "QtQuick.Controls", mod.getModuleIdentifier().getText());
+ assertLocation(0, 24, new Position(1, 0), new Position(1, 24), mod);
+ }
+
+ @Test
+ public void testModuleNoIdentifier() {
+ try {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ parser.parse(createInputStream("module\n"), false);
+ fail("Parser did not throw SyntaxError");
+ } catch (SyntaxError e) {
+ assertEquals("Unexpected token '\\n' (1:6)", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSingletonCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("singleton Singleton 2.3 Singleton.qml\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirSingletonCommand.class));
+ IQDirSingletonCommand singleton = (IQDirSingletonCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected type name", "Singleton", singleton.getTypeName().getText());
+ assertEquals("Unexpected initial version", "2.3", singleton.getInitialVersion().getVersionString());
+ assertEquals("Unexpected file name", "Singleton.qml", singleton.getFile().getText());
+ assertLocation(0, 38, new Position(1, 0), new Position(1, 38), singleton);
+ }
+
+ @Test
+ public void testInvalidVersionNumber() {
+ try {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ parser.parse(createInputStream("singleton Singleton 2 Singleton.qml\n"), false);
+ fail("Parser did not throw SyntaxError");
+ } catch (SyntaxError e) {
+ assertEquals("Unexpected token '2' (1:20)", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testInternalCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("internal MyPrivateType MyPrivateType.qml\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirInternalCommand.class));
+ IQDirInternalCommand internal = (IQDirInternalCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected type name", "MyPrivateType", internal.getTypeName().getText());
+ assertEquals("Unexpected file name", "MyPrivateType.qml", internal.getFile().getText());
+ assertLocation(0, 41, new Position(1, 0), new Position(1, 41), internal);
+ }
+
+ @Test
+ public void testResourceCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("MyScript 1.0 MyScript.qml\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirResourceCommand.class));
+ IQDirResourceCommand resource = (IQDirResourceCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected type name", "MyScript", resource.getResourceIdentifier().getText());
+ assertEquals("Unexpected initial version", "1.0", resource.getInitialVersion().getVersionString());
+ assertEquals("Unexpected file name", "MyScript.qml", resource.getFile().getText());
+ assertLocation(0, 26, new Position(1, 0), new Position(1, 26), resource);
+ }
+
+ @Test
+ public void testPluginCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("plugin MyPluginLibrary\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirPluginCommand.class));
+ IQDirPluginCommand plugin = (IQDirPluginCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected identifier", "MyPluginLibrary", plugin.getName().getText());
+ assertEquals("Unexpected path", null, plugin.getPath());
+ assertLocation(0, 23, new Position(1, 0), new Position(1, 23), plugin);
+ }
+
+ @Test
+ public void testPluginCommandWithPath() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("plugin MyPluginLibrary ./lib/\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirPluginCommand.class));
+ IQDirPluginCommand plugin = (IQDirPluginCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected identifier", "MyPluginLibrary", plugin.getName().getText());
+ assertEquals("Unexpected path", "./lib/", plugin.getPath().getText());
+ assertLocation(0, 30, new Position(1, 0), new Position(1, 30), plugin);
+ }
+
+ @Test
+ public void testClassnameCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("classname MyClass\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirClassnameCommand.class));
+ IQDirClassnameCommand classname = (IQDirClassnameCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected class name", "MyClass", classname.getIdentifier().getText());
+ assertLocation(0, 18, new Position(1, 0), new Position(1, 18), classname);
+ }
+
+ @Test
+ public void testTypeInfoCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("typeinfo mymodule.qmltypes\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirTypeInfoCommand.class));
+ IQDirTypeInfoCommand typeinfo = (IQDirTypeInfoCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected file name", "mymodule.qmltypes", typeinfo.getFile().getText());
+ assertLocation(0, 27, new Position(1, 0), new Position(1, 27), typeinfo);
+ }
+
+ @Test
+ public void testDependsCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("depends MyOtherModule 1.0\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirDependsCommand.class));
+ IQDirDependsCommand depends = (IQDirDependsCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected module identifier", "MyOtherModule", depends.getModuleIdentifier().getText());
+ assertEquals("Unexpected initial version", "1.0", depends.getInitialVersion().getVersionString());
+ assertLocation(0, 26, new Position(1, 0), new Position(1, 26), depends);
+ }
+
+ @Test
+ public void testDesignerSupportedCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("designersupported\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirDesignerSupportedCommand.class));
+ assertLocation(0, 18, new Position(1, 0), new Position(1, 18), ast.getCommands().get(0));
+ }
+
+ @Test
+ public void testCommentCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("# This is a comment command\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirCommentCommand.class));
+ IQDirCommentCommand comment = (IQDirCommentCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected text", "# This is a comment command", comment.getText());
+ }
+
+ @Test
+ public void testSyntaxErrorCommand() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("classname"));
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirSyntaxError.class));
+ IQDirSyntaxError err = (IQDirSyntaxError) ast.getCommands().get(0);
+ assertEquals("Unexpected message", "Unexpected token 'EOF' (1:9)", err.getSyntaxError().getMessage());
+ assertLocation(0, 9, new Position(1, 0), new Position(1, 9), err);
+ }
+
+ @Test
+ public void testSyntaxErrorCommandIncludesWholeLine() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("classname class extra\n"));
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirSyntaxError.class));
+ IQDirSyntaxError err = (IQDirSyntaxError) ast.getCommands().get(0);
+ assertEquals("Unexpected message", "Expected token '\\n' or 'EOF', but saw 'extra' (1:16)",
+ err.getSyntaxError().getMessage());
+ assertLocation(0, 22, new Position(1, 0), new Position(1, 22), err);
+ }
+
+ @Test
+ public void testExampleQMLDirFile() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("module QtQuick\n" +
+ "plugin qtquick2plugin\n" +
+ "classname QtQuick2Plugin\n" +
+ "typeinfo plugins.qmltypes\n" +
+ "designersupported\n"));
+
+ assertEquals("Unexpected command list size", 5, ast.getCommands().size());
+ // Module Command (index 0)
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirModuleCommand.class));
+ IQDirModuleCommand mod = (IQDirModuleCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected module qualified ID", "QtQuick", mod.getModuleIdentifier().getText());
+ // Plugin Command (index 1)
+ assertThat("Unexpected command", ast.getCommands().get(1), instanceOf(IQDirPluginCommand.class));
+ IQDirPluginCommand plugin = (IQDirPluginCommand) ast.getCommands().get(1);
+ assertEquals("Unexpected plugin identifier", "qtquick2plugin", plugin.getName().getText());
+ assertEquals("Unexpected plugin path", null, plugin.getPath());
+ // Classname Command (index 2)
+ assertThat("Unexpected command", ast.getCommands().get(2), instanceOf(IQDirClassnameCommand.class));
+ IQDirClassnameCommand classname = (IQDirClassnameCommand) ast.getCommands().get(2);
+ assertEquals("Unexpected class name", "QtQuick2Plugin", classname.getIdentifier().getText());
+ // Type Info Command (index 3)
+ assertThat("Unexpected command", ast.getCommands().get(3), instanceOf(IQDirTypeInfoCommand.class));
+ IQDirTypeInfoCommand typeinfo = (IQDirTypeInfoCommand) ast.getCommands().get(3);
+ assertEquals("Unexpected type info file name", "plugins.qmltypes", typeinfo.getFile().getText());
+ // Designer Supported Command (index 4)
+ assertThat("Unexpected command", ast.getCommands().get(4), instanceOf(IQDirDesignerSupportedCommand.class));
+ }
+
+ @Test
+ public void testExampleQMLDirFileWithError() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+ IQDirAST ast = parser.parse(createInputStream("module QtQuick\n" +
+ "plugin qtquick2plugin\n" +
+ "classnames QtQuick2Plugin\n" +
+ "typeinfo plugins.qmltypes\n" +
+ "designersupported\n"));
+
+ assertEquals("Unexpected command list size", 5, ast.getCommands().size());
+ // Module Command (index 0)
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirModuleCommand.class));
+ IQDirModuleCommand mod = (IQDirModuleCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected module qualified ID", "QtQuick", mod.getModuleIdentifier().getText());
+ // Plugin Command (index 1)
+ assertThat("Unexpected command", ast.getCommands().get(1), instanceOf(IQDirPluginCommand.class));
+ IQDirPluginCommand plugin = (IQDirPluginCommand) ast.getCommands().get(1);
+ assertEquals("Unexpected plugin identifier", "qtquick2plugin", plugin.getName().getText());
+ assertEquals("Unexpected plugin path", null, plugin.getPath());
+ // Syntax Error Command (index 2)
+ assertThat("Unexpected command", ast.getCommands().get(2), instanceOf(IQDirSyntaxError.class));
+ IQDirSyntaxError err = (IQDirSyntaxError) ast.getCommands().get(2);
+ assertEquals("Unexpected error message", "Unexpected token 'QtQuick2Plugin' (3:11)", err.getSyntaxError().getMessage());
+ // Type Info Command (index 3)
+ assertThat("Unexpected command", ast.getCommands().get(3), instanceOf(IQDirTypeInfoCommand.class));
+ IQDirTypeInfoCommand typeinfo = (IQDirTypeInfoCommand) ast.getCommands().get(3);
+ assertEquals("Unexpected type info file name", "plugins.qmltypes", typeinfo.getFile().getText());
+ // Designer Supported Command (index 4)
+ assertThat("Unexpected command", ast.getCommands().get(4), instanceOf(IQDirDesignerSupportedCommand.class));
+ }
+
+ @Test
+ public void testParseTwoDifferentStreams() {
+ QMLDirectoryParser parser = new QMLDirectoryParser();
+
+ // Parse module QtQuick.Controls
+ IQDirAST ast = parser.parse(createInputStream("module QtQuick.Controls\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirModuleCommand.class));
+ IQDirModuleCommand mod = (IQDirModuleCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected qualified ID", "QtQuick.Controls", mod.getModuleIdentifier().getText());
+ assertLocation(0, 24, new Position(1, 0), new Position(1, 24), mod);
+
+ // Parse a second module MyModule
+ ast = parser.parse(createInputStream("module MyModule\n"), false);
+ assertEquals("Unexpected command list size", 1, ast.getCommands().size());
+ assertThat("Unexpected command", ast.getCommands().get(0), instanceOf(IQDirModuleCommand.class));
+ mod = (IQDirModuleCommand) ast.getCommands().get(0);
+ assertEquals("Unexpected qualified ID", "MyModule", mod.getModuleIdentifier().getText());
+ assertLocation(0, 16, new Position(1, 0), new Position(1, 16), mod);
+ }
+}
diff --git a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF
index eea77498c89..1ed5ff29d85 100644
--- a/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF
+++ b/qt/org.eclipse.cdt.qt.core/META-INF/MANIFEST.MF
@@ -25,6 +25,10 @@ Bundle-Localization: plugin
Export-Package: org.eclipse.cdt.internal.qt.core;x-friends:="org.eclipse.cdt.qt.ui,org.eclipse.cdt.qt.ui.tests",
org.eclipse.cdt.internal.qt.core.build;x-friends:="org.eclipse.cdt.qt.ui",
org.eclipse.cdt.internal.qt.core.index;x-friends:="org.eclipse.cdt.qt.ui.tests",
+ org.eclipse.cdt.internal.qt.core.location;x-friends:="org.eclipse.cdt.qt.core.tests",
org.eclipse.cdt.internal.qt.core.parser;x-friends:="org.eclipse.cdt.qt.ui",
org.eclipse.cdt.internal.qt.core.project;x-friends:="org.eclipse.cdt.qt.ui",
- org.eclipse.cdt.qt.core
+ org.eclipse.cdt.internal.qt.core.qmldir;x-friends:="org.eclipse.cdt.qt.core.tests",
+ org.eclipse.cdt.qt.core;x-friends:="org.eclipse.cdt.qt.core.tests",
+ org.eclipse.cdt.qt.core.location,
+ org.eclipse.cdt.qt.core.qmldir
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/Position.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/Position.java
new file mode 100644
index 00000000000..1ec2df36bb8
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/Position.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.location;
+
+import org.eclipse.cdt.qt.core.location.IPosition;
+
+public class Position implements IPosition {
+ private final int line;
+ private final int column;
+
+ public Position(int line, int column) {
+ this.line = line;
+ this.column = column;
+ }
+
+ @Override
+ public int getLine() {
+ return line;
+ }
+
+ @Override
+ public int getColumn() {
+ return column;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + line + ":" + column + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/SourceLocation.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/SourceLocation.java
new file mode 100644
index 00000000000..d1a702a7720
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/SourceLocation.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.location;
+
+import org.eclipse.cdt.qt.core.location.IPosition;
+import org.eclipse.cdt.qt.core.location.ISourceLocation;
+
+public class SourceLocation implements ISourceLocation {
+ private String source;
+ private IPosition start;
+ private IPosition end;
+
+ public SourceLocation() {
+ this(null, null, null);
+ }
+
+ public SourceLocation(String source, IPosition start, IPosition end) {
+ this.source = source;
+ this.start = start;
+ this.end = end;
+ }
+
+ public void setSource(String value) {
+ this.source = value;
+ }
+
+ @Override
+ public String getSource() {
+ return source;
+ }
+
+ public void setStart(IPosition value) {
+ this.start = value;
+ }
+
+ @Override
+ public IPosition getStart() {
+ return start;
+ }
+
+ public void setEnd(IPosition value) {
+ this.end = value;
+ }
+
+ @Override
+ public IPosition getEnd() {
+ return end;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirAST.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirAST.java
new file mode 100644
index 00000000000..78f0f3e62eb
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirAST.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirAST;
+import org.eclipse.cdt.qt.core.qmldir.IQDirCommand;
+
+public class QDirAST extends QDirASTNode implements IQDirAST {
+ private final List<IQDirCommand> commands;
+
+ public QDirAST() {
+ commands = new ArrayList<>();
+ }
+
+ public void addCommand(IQDirCommand command) {
+ commands.add(command);
+ }
+
+ @Override
+ public List<IQDirCommand> getCommands() {
+ return Collections.unmodifiableList(commands);
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirASTNode.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirASTNode.java
new file mode 100644
index 00000000000..a3fd9322755
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirASTNode.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.internal.qt.core.location.SourceLocation;
+import org.eclipse.cdt.qt.core.qmldir.IQDirASTNode;
+
+public class QDirASTNode implements IQDirASTNode {
+
+ private SourceLocation location;
+ private int start;
+ private int end;
+
+ public QDirASTNode() {
+ this.location = new SourceLocation();
+ this.start = -1;
+ this.end = -1;
+ }
+
+ public void setLocation(SourceLocation value) {
+ this.location = value;
+ }
+
+ @Override
+ public SourceLocation getLocation() {
+ return location;
+ }
+
+ public void setStart(int value) {
+ this.start = value;
+ }
+
+ @Override
+ public int getStart() {
+ return start;
+ }
+
+ public void setEnd(int value) {
+ this.end = value;
+ }
+
+ @Override
+ public int getEnd() {
+ return end;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirClassnameCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirClassnameCommand.java
new file mode 100644
index 00000000000..6963f345416
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirClassnameCommand.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirClassnameCommand;
+
+public class QDirClassnameCommand extends QDirASTNode implements IQDirClassnameCommand {
+
+ private QDirWord ident;
+
+ public void setIdentifier(QDirWord value) {
+ this.ident = value;
+ }
+
+ @Override
+ public QDirWord getIdentifier() {
+ return ident;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirCommentCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirCommentCommand.java
new file mode 100644
index 00000000000..40505866bb0
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirCommentCommand.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirCommentCommand;
+
+public class QDirCommentCommand extends QDirASTNode implements IQDirCommentCommand {
+
+ private String text;
+
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ @Override
+ public String getText() {
+ return text;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDependsCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDependsCommand.java
new file mode 100644
index 00000000000..45639004a4f
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDependsCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirDependsCommand;
+
+public class QDirDependsCommand extends QDirASTNode implements IQDirDependsCommand {
+
+ private QDirWord moduleName;
+ private QDirVersion version;
+
+ public void setModuleIdentifier(QDirWord value) {
+ this.moduleName = value;
+ }
+
+ @Override
+ public QDirWord getModuleIdentifier() {
+ return moduleName;
+ }
+
+ public void setInitialVersion(QDirVersion value) {
+ this.version = value;
+ }
+
+ @Override
+ public QDirVersion getInitialVersion() {
+ return version;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDesignerSupportedCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDesignerSupportedCommand.java
new file mode 100644
index 00000000000..9b7583a437c
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDesignerSupportedCommand.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirDesignerSupportedCommand;
+
+public class QDirDesignerSupportedCommand extends QDirASTNode implements IQDirDesignerSupportedCommand {
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirInternalCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirInternalCommand.java
new file mode 100644
index 00000000000..b437e8dc708
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirInternalCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirInternalCommand;
+
+public class QDirInternalCommand extends QDirASTNode implements IQDirInternalCommand {
+
+ private QDirWord typeName;
+ private QDirWord file;
+
+ public void setTypeName(QDirWord value) {
+ this.typeName = value;
+ }
+
+ @Override
+ public QDirWord getTypeName() {
+ return typeName;
+ }
+
+ public void setFile(QDirWord value) {
+ this.file = value;
+ }
+
+ @Override
+ public QDirWord getFile() {
+ return file;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirModuleCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirModuleCommand.java
new file mode 100644
index 00000000000..cea1f44b25b
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirModuleCommand.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirModuleCommand;
+
+public class QDirModuleCommand extends QDirASTNode implements IQDirModuleCommand {
+ private QDirWord identifier;
+
+ public void setModuleIdentifier(QDirWord value) {
+ this.identifier = value;
+ }
+
+ @Override
+ public QDirWord getModuleIdentifier() {
+ return identifier;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirPluginCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirPluginCommand.java
new file mode 100644
index 00000000000..61fbb2fbdbe
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirPluginCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirPluginCommand;
+
+public class QDirPluginCommand extends QDirASTNode implements IQDirPluginCommand {
+
+ private QDirWord qid;
+ private QDirWord path;
+
+ public void setName(QDirWord value) {
+ this.qid = value;
+ }
+
+ @Override
+ public QDirWord getName() {
+ return qid;
+ }
+
+ public void setPath(QDirWord value) {
+ this.path = value;
+ }
+
+ @Override
+ public QDirWord getPath() {
+ return path;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirResourceCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirResourceCommand.java
new file mode 100644
index 00000000000..7c9b8541a80
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirResourceCommand.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirResourceCommand;
+
+public class QDirResourceCommand extends QDirASTNode implements IQDirResourceCommand {
+ private QDirWord typeName;
+ private QDirVersion version;
+ private QDirWord file;
+
+ public void setResourceIdentifier(QDirWord value) {
+ this.typeName = value;
+ }
+
+ @Override
+ public QDirWord getResourceIdentifier() {
+ return typeName;
+ }
+
+ public void setInitialVersion(QDirVersion value) {
+ this.version = value;
+ }
+
+ @Override
+ public QDirVersion getInitialVersion() {
+ return version;
+ }
+
+ public void setFile(QDirWord value) {
+ this.file = value;
+ }
+
+ @Override
+ public QDirWord getFile() {
+ return file;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSingletonCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSingletonCommand.java
new file mode 100644
index 00000000000..03208f0afd6
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSingletonCommand.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirSingletonCommand;
+
+public class QDirSingletonCommand extends QDirASTNode implements IQDirSingletonCommand {
+
+ private QDirWord typeName;
+ private QDirVersion version;
+ private QDirWord file;
+
+ public void setTypeName(QDirWord value) {
+ this.typeName = value;
+ }
+
+ @Override
+ public QDirWord getTypeName() {
+ return typeName;
+ }
+
+ public void setInitialVersion(QDirVersion value) {
+ this.version = value;
+ }
+
+ @Override
+ public QDirVersion getInitialVersion() {
+ return version;
+ }
+
+ public void setFile(QDirWord value) {
+ this.file = value;
+ }
+
+ @Override
+ public QDirWord getFile() {
+ return file;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSyntaxError.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSyntaxError.java
new file mode 100644
index 00000000000..a66b968ddb3
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSyntaxError.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirASTNode;
+import org.eclipse.cdt.qt.core.qmldir.IQDirSyntaxError;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.Token;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryParser.SyntaxError;
+
+public class QDirSyntaxError extends QDirASTNode implements IQDirSyntaxError {
+ private SyntaxError exception;
+
+ public QDirSyntaxError(SyntaxError exception) {
+ this.exception = exception;
+ }
+
+ @Override
+ public Token getOffendingToken() {
+ return this.exception.getOffendingToken();
+ }
+
+ @Override
+ public IQDirASTNode getIncompleteNode() {
+ return this.exception.getIncompleteNode();
+ }
+
+ @Override
+ public SyntaxError getSyntaxError() {
+ return this.exception;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirTypeInfoCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirTypeInfoCommand.java
new file mode 100644
index 00000000000..9b2f00e1a9b
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirTypeInfoCommand.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirTypeInfoCommand;
+
+public class QDirTypeInfoCommand extends QDirASTNode implements IQDirTypeInfoCommand {
+
+ private QDirWord file;
+
+ public void setFile(QDirWord value) {
+ this.file = value;
+ }
+
+ @Override
+ public QDirWord getFile() {
+ return file;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirVersion.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirVersion.java
new file mode 100644
index 00000000000..4a3c3dabe3a
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirVersion.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirVersion;
+
+public class QDirVersion extends QDirASTNode implements IQDirVersion {
+
+ private String version;
+
+ public void setVersionString(String value) {
+ this.version = value;
+ }
+
+ @Override
+ public String getVersionString() {
+ return version;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirWord.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirWord.java
new file mode 100644
index 00000000000..89aac96b739
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirWord.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.IQDirWord;
+
+public class QDirWord extends QDirASTNode implements IQDirWord {
+
+ private String text;
+
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ @Override
+ public String getText() {
+ return text;
+ }
+
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/IPosition.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/IPosition.java
new file mode 100644
index 00000000000..e4f98f7df53
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/IPosition.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.location;
+
+/**
+ * Stores a line/offset pair as integers.
+ */
+public interface IPosition {
+ /**
+ * Gets the one-indexed line number indicated by this <code>IPosition</code>
+ *
+ * @return the line number
+ */
+ public int getLine();
+
+ /**
+ * Gets the zero-indexed column indicated by this <code>IPosition</code>
+ *
+ * @return the column
+ */
+ public int getColumn();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/ISourceLocation.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/ISourceLocation.java
new file mode 100644
index 00000000000..98383ff1c19
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/ISourceLocation.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.location;
+
+/**
+ * Represents a location in a source file. Uses the {@link IPosition} interface to store the start and end locations as a
+ * line/offset pair.
+ */
+public interface ISourceLocation {
+ /**
+ * Gets the String representing the source of this <code>ISourceLocation</code>
+ *
+ * @return the source or <code>null</code> if not available
+ */
+ public String getSource();
+
+ /**
+ * Gets the zero-indexed offset indicating the start of this <code>ISourceLocation</code>
+ *
+ * @return the start offset
+ */
+ public IPosition getStart();
+
+ /**
+ * Gets the zero-indexed offset indicating the end of this <code>ISourceLocation</code>
+ *
+ * @return the end offset
+ */
+ public IPosition getEnd();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirAST.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirAST.java
new file mode 100644
index 00000000000..314614a2333
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirAST.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+import java.util.List;
+
+/**
+ * The main entry point into the qmldir AST. This interface contains a list of Commands specified within the qmldir file that it
+ * represents.
+ */
+public interface IQDirAST extends IQDirASTNode {
+ /**
+ * Gets the list of commands in the qmldir file that this <code>IQDirAST</code> represents.
+ *
+ * @return the list of all commands in the qmldir file
+ */
+ public List<IQDirCommand> getCommands();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirASTNode.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirASTNode.java
new file mode 100644
index 00000000000..2dd877e6b1f
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirASTNode.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.location.ISourceLocation;
+
+/**
+ * The base type for all qmldir AST nodes. Contains methods for retrieving a node's positional information.
+ */
+public interface IQDirASTNode {
+ /**
+ * Gets a more detailed description of this node's location than {@link IQDirASTNode#getStart()} and
+ * {@link IQDirASTNode#getStart()}. This method allows the retrieval of line and column information in order to make output for
+ * syntax errors and the like more human-readable.
+ *
+ * @return the {@link ISourceLocation} representing this node's location in the source
+ */
+ public ISourceLocation getLocation();
+
+ /**
+ * Gets the zero-indexed offset indicating the start of this node in the source.
+ *
+ * @return the node's start offset
+ */
+ public int getStart();
+
+ /**
+ * Gets the zero-indexed offset indicating the end of this node in the source.
+ *
+ * @return the node's end offset
+ */
+ public int getEnd();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirClassnameCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirClassnameCommand.java
new file mode 100644
index 00000000000..13ce512dea8
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirClassnameCommand.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Classname Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirClassnameCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the identifier for the classname.
+ *
+ * @return the identifier for the classname
+ */
+ public IQDirWord getIdentifier();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommand.java
new file mode 100644
index 00000000000..7a785aed919
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommand.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * The base interface for all qmldir AST nodes that function as commands.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirCommand extends IQDirASTNode {
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommentCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommentCommand.java
new file mode 100644
index 00000000000..cec1c25531f
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommentCommand.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Comment Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirCommentCommand extends IQDirCommand {
+ /**
+ * Gets the String representation of this comment as it appears in the qmldir file.
+ *
+ * @return the String representation of this comment
+ */
+ public String getText();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDependsCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDependsCommand.java
new file mode 100644
index 00000000000..0e6fbcc6bcd
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDependsCommand.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Depends Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirDependsCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the module identifier that this qmldir module depends on.
+ *
+ * @return the module identifier
+ */
+ public IQDirWord getModuleIdentifier();
+
+ /**
+ * Gets the <code>IQDirVersion</code> representing the initial version of the module that this qmldir module depends on.
+ *
+ * @return the initial version
+ */
+ public IQDirVersion getInitialVersion();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDesignerSupportedCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDesignerSupportedCommand.java
new file mode 100644
index 00000000000..1619501ac44
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDesignerSupportedCommand.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Designer Supported Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirDesignerSupportedCommand extends IQDirCommand {
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirInternalCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirInternalCommand.java
new file mode 100644
index 00000000000..0af6388e6b7
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirInternalCommand.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing an Internal Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirInternalCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the type name of the internal type.
+ *
+ * @return the type names
+ */
+ public IQDirWord getTypeName();
+
+ /**
+ * Gets the <code>IQDirWord</code> representing the filename of the internal type.
+ *
+ * @return the filename
+ */
+ public IQDirWord getFile();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirModuleCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirModuleCommand.java
new file mode 100644
index 00000000000..6ad218e970a
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirModuleCommand.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Module Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirModuleCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the identifier for the module.
+ *
+ * @return the identifier for the module
+ */
+ public IQDirWord getModuleIdentifier();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirPluginCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirPluginCommand.java
new file mode 100644
index 00000000000..bd1c4279cb6
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirPluginCommand.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Plugin Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirPluginCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the name of the plugin.
+ *
+ * @return the plugin name
+ */
+ public IQDirWord getName();
+
+ /**
+ * Gets the <code>IQDirWord</code> representing the path to the plugin if it was given.
+ *
+ * @return the path to the plugin or <code>null</code> if not available
+ */
+ public IQDirWord getPath();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirResourceCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirResourceCommand.java
new file mode 100644
index 00000000000..d92838d2da4
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirResourceCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Resource Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirResourceCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the identifier of the resource.
+ *
+ * @return the identifier of the resource
+ */
+ public IQDirWord getResourceIdentifier();
+
+ /**
+ * Gets the <code>IQDirVersion</code> representing the initial version of the resource.
+ *
+ * @return the initial version
+ */
+ public IQDirVersion getInitialVersion();
+
+ /**
+ * Gets the <code>IQDirWord</code> representing the filename of the resource.
+ *
+ * @return the filename
+ */
+ public IQDirWord getFile();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSingletonCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSingletonCommand.java
new file mode 100644
index 00000000000..7d5547cf4ae
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSingletonCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Singleton Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirSingletonCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the type name of the singleton type.
+ *
+ * @return the type name
+ */
+ public IQDirWord getTypeName();
+
+ /**
+ * Gets the <code>IQDirVersion</code> representing the initial version of the singleton type.
+ *
+ * @return the initial version
+ */
+ public IQDirVersion getInitialVersion();
+
+ /**
+ * Gets the <code>IQDirWord</code> representing the filename of the singleton type.
+ *
+ * @return the filename
+ */
+ public IQDirWord getFile();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSyntaxError.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSyntaxError.java
new file mode 100644
index 00000000000..142a125f95c
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSyntaxError.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.Token;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryParser.SyntaxError;
+
+/**
+ * An AST Node representing a syntax error in a qmldir file. Due to the fact that the qmldir file is so simple, a syntax error will
+ * only occur at the command level while the parser jumps to the next line to recover.
+ */
+public interface IQDirSyntaxError extends IQDirCommand {
+ /**
+ * Gets the token that caused the parser to fail. This is a helper method equivalent to
+ * <code>getSyntaxError.getOffendingToken()</code>.
+ *
+ * @return the offending token.
+ */
+ public Token getOffendingToken();
+
+ /**
+ * Gets the node that the parser was working on before it failed (if available). This is a helper method equivalent to
+ * <code>getSyntaxError.getIncompleteNode()</code>.
+ *
+ * @return the incomplete node or <code>null</code> if not available
+ */
+ public IQDirASTNode getIncompleteNode();
+
+ /**
+ * Gets the syntax error that occurred.
+ *
+ * @return the syntax error
+ */
+ public SyntaxError getSyntaxError();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirTypeInfoCommand.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirTypeInfoCommand.java
new file mode 100644
index 00000000000..943690d8a98
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirTypeInfoCommand.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a Type Info Command in a qmldir file.
+ *
+ * @see <a href="http://doc.qt.io/qt-5/qtqml-modules-qmldir.html">Module Definition qmldir Files</a>
+ */
+public interface IQDirTypeInfoCommand extends IQDirCommand {
+ /**
+ * Gets the <code>IQDirWord</code> representing the filename of the type info file.
+ *
+ * @return the filename of the type info file
+ */
+ public IQDirWord getFile();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirVersion.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirVersion.java
new file mode 100644
index 00000000000..f8f715277d3
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirVersion.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a version String of the form &ltMajorVersion&gt.&ltMinorVersion&gt
+ */
+public interface IQDirVersion extends IQDirASTNode {
+ /**
+ * Gets the String value of this version. The result will always be of the form "&ltMajorVersion&gt.&ltMinorVersion&gt"
+ *
+ * @return a string value of this version
+ */
+ public String getVersionString();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirWord.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirWord.java
new file mode 100644
index 00000000000..2afa6e005ce
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirWord.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+/**
+ * An AST Node representing a set of characters that does not contain whitespace and does not start with a digit. This encompasses
+ * the syntax for Identifiers, Qualified IDs, Paths, and File Names all in one parser rule.
+ */
+public interface IQDirWord extends IQDirASTNode {
+ /**
+ * Gets the String representing this word as it appears in the qmldir file.<br>
+ * <br>
+ * <b>Note:</b> The text is not modified or validated in any way when it is parsed. It is necessary for the caller to perform
+ * semantic validation of the returned value to ensure it represents a valid identifier, filename, or path.
+ *
+ * @return a string representing this word
+ */
+ public String getText();
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryLexer.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryLexer.java
new file mode 100644
index 00000000000..0e0756e718b
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryLexer.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+import java.io.InputStream;
+import java.util.Scanner;
+import java.util.regex.MatchResult;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.internal.qt.core.location.Position;
+import org.eclipse.cdt.internal.qt.core.location.SourceLocation;
+import org.eclipse.cdt.qt.core.location.ISourceLocation;
+
+/**
+ * Converts an <code>InputStream</code> representing a qmldir file into a stream of tokens through successive calls to
+ * <code>nextToken</code>. This lexer uses regular expressions to match its 16 valid token types:
+ * <ul>
+ * <li><b>COMMENT</b>: A single line comment that begins with '#'
+ * <li><b>MODULE</b>: Keyword 'module'
+ * <li><b>TYPEINFO</b>: The keyword 'typeinfo'
+ * <li><b>SINGLETON</b>: The keyword 'singleton'
+ * <li><b>INTERNAL</b>: The keyword 'internal'
+ * <li><b>PLUGIN</b>: The keyword 'plugin'
+ * <li><b>CLASSNAME</b>: The keyword 'classname'
+ * <li><b>DEPENDS</b>: The keyword 'depends'
+ * <li><b>DESIGNERSUPPORTED</b>: The keyword 'designersupported'
+ * <li><b>WORD</b>: A group of characters that form an identifier, filename, or path
+ * <li><b>DECIMAL</b>: A number of the form [0-9]+ '.' [0-9]+
+ * <li><b>INTEGER</b>: An integer of the form [0-9]+
+ * <li><b>WHITESPACE</b>: A group of whitespace characters (not including newlines)
+ * <li><b>COMMAND_END</b>: A newline character
+ * <li><b>UNKNOWN</b>: A group of characters that does not match any of the preceding tokens
+ * <li><b>EOF</b>: End of File
+ * </ul>
+ */
+public class QMLDirectoryLexer {
+ /**
+ * A single matched token returned by a <code>QMLDirectoryLexer</code>. A <code>Token</code> stores information on how it was
+ * matched including the type of token, the exact text that was matched, and its position in the <code>InputStream</code> .
+ */
+ public static class Token {
+ private final TokenType tokType;
+ private final String raw;
+ private final ISourceLocation location;
+ private final int start;
+ private final int end;
+
+ private Token(TokenType type, MatchResult match, int line, int lineStart) {
+ this(type, match.group(), match.start(), match.end(), line, lineStart);
+ }
+
+ private Token(TokenType type, String raw, int start, int end, int line, int lineStart) {
+ this.tokType = type;
+ raw = raw.replaceAll("\n", "\\\\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ raw = raw.replaceAll("\r", "\\\\r"); //$NON-NLS-1$ //$NON-NLS-2$
+ this.raw = raw;
+ this.start = start;
+ this.end = end;
+ this.location = new SourceLocation(null,
+ new Position(line, start - lineStart),
+ new Position(line, end - lineStart));
+ }
+
+ /**
+ * Get the type of token that was matched.
+ *
+ * @return the type of token
+ */
+ public TokenType getType() {
+ return tokType;
+ }
+
+ /**
+ * Gets the raw text that this token was matched with.
+ *
+ * @return a String representing the matched text
+ */
+ public String getText() {
+ return raw;
+ }
+
+ /**
+ * Gets a more detailed description of this token's location in the <code>InputStream</code> than {@link Token#getStart()}
+ * and {@link Token#getEnd()}. This method allows the retrieval of line and column information in order to make output for
+ * syntax errors and the like more human-readable.
+ *
+ * @return the {@link ISourceLocation} representing this token's location in the <code>InputStream</code>
+ */
+ public ISourceLocation getLocation() {
+ return location;
+ }
+
+ /**
+ * Gets the zero-indexed offset indicating the start of this token in the <code>InputStream</code>.
+ *
+ * @return the token's start offset
+ */
+ public int getStart() {
+ return start;
+ }
+
+ /**
+ * Gets the zero-indexed offset indicating the end of this token in the <code>InputStream</code>.
+ *
+ * @return the token's end offset
+ */
+ public int getEnd() {
+ return end;
+ }
+ }
+
+ /**
+ * An Enumeration encompassing the 16 possible types of tokens returned by a <code>QMLDirectoryLexer</code>.
+ *
+ * @see org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer
+ */
+ public static enum TokenType {
+ COMMENT("#.*$"), //$NON-NLS-1$
+ MODULE("module(?=\\s|$)"), //$NON-NLS-1$
+ TYPEINFO("typeinfo(?=\\s|$)"), //$NON-NLS-1$
+ SINGLETON("singleton(?=\\s|$)"), //$NON-NLS-1$
+ INTERNAL("internal(?=\\s|$)"), //$NON-NLS-1$
+ PLUGIN("plugin(?=\\s|$)"), //$NON-NLS-1$
+ CLASSNAME("classname(?=\\s|$)"), //$NON-NLS-1$
+ DEPENDS("depends(?=\\s|$)"), //$NON-NLS-1$
+ DESIGNERSUPPORTED("designersupported(?=\\s|$)"), //$NON-NLS-1$
+ WORD("[^0-9\\s][^\\s]*"), //$NON-NLS-1$
+ DECIMAL("[0-9]+\\.[0-9]+"), //$NON-NLS-1$
+ INTEGER("[0-9]+"), //$NON-NLS-1$
+ WHITESPACE("\\h+"), //$NON-NLS-1$
+ COMMAND_END("(?:\r\n)|\n"), //$NON-NLS-1$
+ UNKNOWN(".+"), //$NON-NLS-1$
+ EOF(null);
+
+ private static Pattern pattern;
+
+ private static Pattern patternForAllTerminals() {
+ if (pattern == null) {
+ String regex = ""; //$NON-NLS-1$
+ TokenType[] tokens = TokenType.values();
+ for (int i = 0; i < TokenType.values().length; i++) {
+ TokenType tok = tokens[i];
+ if (tok.regex != null) {
+ if (i != 0) {
+ regex += "|"; //$NON-NLS-1$
+ }
+ regex += "(" + tok.regex + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ pattern = Pattern.compile(regex, Pattern.MULTILINE);
+ }
+ return pattern;
+ }
+
+ private final String regex;
+
+ private TokenType(String regex) {
+ this.regex = regex;
+ }
+ }
+
+ private Scanner input;
+ private MatchResult lastMatch;
+ private int currentLine;
+ private int currentLineStart;
+
+ /**
+ * Creates a new <code>QMLDirectoryLexer</code> without initializing any of the its internal state. A call to
+ * <code>setInput</code> is necessary to fully initialize the lexer before any calls to <code>nextToken</code>.
+ */
+ public QMLDirectoryLexer() {
+ }
+
+ /**
+ * Prepares for lexical analysis by giving the lexer an <code>InputStream</code> to retrieve text from.
+ *
+ * @param input
+ * the input to perform lexical analysis on
+ */
+ public void setInput(InputStream input) {
+ this.input = new Scanner(input);
+ this.lastMatch = null;
+ this.currentLine = 1;
+ this.currentLineStart = 0;
+ }
+
+ /**
+ * Retrieves the next valid token from the <code>InputStream</code> given by <code>setInput</code>. This is a helper method to
+ * skip whitespace that is equivalent to <code>QMLDirectoryLexer.nextToken(true)</code>.
+ *
+ * @return the next token in the <code>InputStream</code>
+ * @throws IllegalArgumentException
+ * if <code>setInput</code> has not been called
+ */
+ public Token nextToken() throws IllegalArgumentException {
+ return nextToken(true);
+ }
+
+ /**
+ * Retrieves the next valid token from the <code>InputStream</code> given by <code>setInput</code>. This method has the ability
+ * to skip over whitespace tokens by setting <code>skipWhitespace</code> to <code>true</code>.
+ *
+ * @param skipWhitespace
+ * whether or not the lexer should skip whitespace tokens
+ * @return the next token in the <code>InputStream</code>
+ * @throws IllegalArgumentException
+ * if <code>setInput</code> has not been called
+ */
+ public Token nextToken(boolean skipWhitespace) throws IllegalArgumentException {
+ if (input == null) {
+ throw new IllegalArgumentException("Input cannot be null"); //$NON-NLS-1$
+ }
+ if (input.findWithinHorizon(TokenType.patternForAllTerminals(), 0) == null) {
+ if (lastMatch != null) {
+ return new Token(TokenType.EOF, "", lastMatch.end(), lastMatch.end(), currentLine, currentLineStart); //$NON-NLS-1$
+ } else {
+ return new Token(TokenType.EOF, "", 0, 0, 1, 0); //$NON-NLS-1$
+ }
+ } else {
+ int groupNo = 1;
+ for (TokenType t : TokenType.values()) {
+ if (t.regex != null) {
+ if (input.match().start(groupNo) != -1) {
+ lastMatch = input.match();
+ Token next = null;
+ if (!(t.equals(TokenType.WHITESPACE) && skipWhitespace)) {
+ next = new Token(t, input.match(), currentLine, currentLineStart);
+ } else {
+ next = nextToken(skipWhitespace);
+ }
+ if (t.equals(TokenType.COMMAND_END)) {
+ // Advance the line number information
+ currentLine++;
+ currentLineStart = input.match().end();
+ }
+ return next;
+ }
+ groupNo++;
+ }
+ }
+ return new Token(TokenType.UNKNOWN, input.match(), currentLine, currentLineStart);
+ }
+ }
+}
diff --git a/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryParser.java b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryParser.java
new file mode 100644
index 00000000000..5af75b43669
--- /dev/null
+++ b/qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryParser.java
@@ -0,0 +1,423 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.qt.core.qmldir;
+
+import java.io.InputStream;
+import java.util.Stack;
+
+import org.eclipse.cdt.internal.qt.core.location.SourceLocation;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirAST;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirASTNode;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirClassnameCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirCommentCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirDependsCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirDesignerSupportedCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirInternalCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirModuleCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirPluginCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirResourceCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirSingletonCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirSyntaxError;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirTypeInfoCommand;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirVersion;
+import org.eclipse.cdt.internal.qt.core.qmldir.QDirWord;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.Token;
+import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryLexer.TokenType;
+
+/**
+ * Converts an <code>InputStream</code> representing a qmldir file into an Abstract Syntax Tree. Uses the {@link QMLDirectoryLexer}
+ * under the hood to match tokens which it then uses to construct the AST. Also, a <code>QMLDirectoryParser</code> has the ability
+ * to skip over syntax errors and include them in its AST rather than returning upon the first error.
+ */
+public class QMLDirectoryParser {
+ /**
+ * An exception thrown when a <code>QMLDirectoryParser</code> encounters a syntax error. This class stores information on the
+ * offending token as well as the node the parser was working on before it failed (if available).
+ */
+ public static class SyntaxError extends RuntimeException {
+ private static final long serialVersionUID = 6608815552297970623L;
+
+ private final IQDirASTNode incompleteNode;
+ private final Token offendingToken;
+
+ /**
+ * Creates a new <code>SyntaxError</code>.
+ *
+ * @param node
+ * the incomplete working node
+ * @param token
+ * the offending token
+ * @param message
+ * the message to display
+ */
+ public SyntaxError(IQDirASTNode node, Token token, String message) {
+ super(message);
+ this.incompleteNode = node;
+ this.offendingToken = token;
+ }
+
+ /**
+ * Gets the token that caused the parser to fail.
+ *
+ * @return the offending token
+ */
+ public Token getOffendingToken() {
+ return offendingToken;
+ }
+
+ /**
+ * Gets the last node that the parser was working on before it failed or null if that information isn't present.
+ *
+ * @return the incomplete node or <code>null</code> if not available
+ */
+ public IQDirASTNode getIncompleteNode() {
+ return incompleteNode;
+ }
+ }
+
+ private final QMLDirectoryLexer lexer;
+ private final Stack<QDirASTNode> workingNodes;
+ private Token tok;
+
+ /**
+ * Initializes a new <code>QMLDirectoryParser</code> capable of parsing an <code>InputStream</code> and returning an AST.
+ */
+ public QMLDirectoryParser() {
+ this.lexer = new QMLDirectoryLexer();
+ this.workingNodes = new Stack<>();
+ }
+
+ /**
+ * Parses the given <code>InputStream</code> into an Abstract Syntax Tree. This is a helper method equivalent to
+ * <code>parse(input, true)</code>. That is, the parser will attempt to recover once it hits an error and include an
+ * {@link IQDirSyntaxError} node in the AST.
+ *
+ * @param input
+ * the input to parse
+ * @return the Abstract Syntax Tree representing the input
+ * @see QMLDirectoryParser#parse(InputStream, boolean)
+ */
+ public IQDirAST parse(InputStream input) {
+ return parse(input, true);
+ }
+
+ /**
+ * Parses the given <code>InputStream</code> into an Abstract Syntax Tree. If <code>tolerateErrors</code> is <code>true</code>,
+ * any syntax errors will be included in the AST as a separate {@link IQDirSyntaxErrorCommand}. The parser will then attempt to
+ * recover by jumping to the next line and continue parsing. A value of </code>false</code> tells the parser to throw a
+ * {@link SyntaxError} on the first problem it encounters.
+ *
+ * @param input
+ * the input to parse
+ * @param tolerateErrors
+ * whether or not the parser should be error tolerant
+ * @return the Abstract Syntax Tree representing the input
+ */
+ public IQDirAST parse(InputStream input, boolean tolerateErrors) {
+ // Clear out any leftover state
+ this.lexer.setInput(input);
+ this.workingNodes.clear();
+
+ QDirAST ast = new QDirAST();
+ nextToken();
+ while (tok.getType() != TokenType.EOF) {
+ try {
+ switch (tok.getType()) {
+ case MODULE:
+ ast.addCommand(parseModuleCommand());
+ break;
+ case SINGLETON:
+ ast.addCommand(parseSingletonCommand());
+ break;
+ case INTERNAL:
+ ast.addCommand(parseInternalCommand());
+ break;
+ case WORD:
+ ast.addCommand(parseResourceCommand());
+ break;
+ case PLUGIN:
+ ast.addCommand(parsePluginCommand());
+ break;
+ case CLASSNAME:
+ ast.addCommand(parseClassnameCommand());
+ break;
+ case TYPEINFO:
+ ast.addCommand(parseTypeInfoCommand());
+ break;
+ case DEPENDS:
+ ast.addCommand(parseDependsCommand());
+ break;
+ case DESIGNERSUPPORTED:
+ ast.addCommand(parseDesignerSupportedCommand());
+ break;
+ case COMMENT:
+ ast.addCommand(parseCommentCommand());
+ break;
+ case COMMAND_END:
+ // This is just an empty line that should be ignored
+ nextToken();
+ break;
+ default:
+ throw unexpectedToken();
+ }
+ } catch (SyntaxError e) {
+ if (!tolerateErrors) {
+ throw e;
+ }
+ // Add the syntax error to the AST and jump to the next line
+ QDirSyntaxError errNode = new QDirSyntaxError(e);
+ markStart(errNode);
+ IQDirASTNode node = e.getIncompleteNode();
+ if (node != null) {
+ errNode.setLocation((SourceLocation) node.getLocation());
+ errNode.setStart(node.getStart());
+ errNode.setEnd(node.getEnd());
+ }
+ while (!eat(TokenType.COMMAND_END) && !eat(TokenType.EOF)) {
+ nextToken();
+ }
+ markEnd();
+ ast.addCommand(errNode);
+ }
+ }
+ return ast;
+ }
+
+ private void nextToken() {
+ nextToken(true);
+ }
+
+ private void nextToken(boolean skipWhitespace) {
+ tok = lexer.nextToken(skipWhitespace);
+ }
+
+ private void markStart(QDirASTNode node) {
+ workingNodes.push(node);
+ node.setStart(tok.getStart());
+ node.setLocation(new SourceLocation());
+ node.getLocation().setStart(tok.getLocation().getStart());
+ }
+
+ private void markEnd() {
+ QDirASTNode node = workingNodes.pop();
+ node.setEnd(tok.getEnd());
+ node.getLocation().setEnd(tok.getLocation().getEnd());
+ }
+
+ private boolean eat(TokenType type) {
+ if (tok.getType() == type) {
+ nextToken();
+ return true;
+ }
+ return false;
+ }
+
+ private SyntaxError syntaxError(String message) {
+ return new SyntaxError(workingNodes.peek(), tok, message + " " + tok.getLocation().getStart().toString()); //$NON-NLS-1$
+ }
+
+ private SyntaxError unexpectedToken() {
+ String tokenText = tok.getText();
+ if (tok.getType() == TokenType.EOF) {
+ tokenText = "EOF"; //$NON-NLS-1$
+ }
+ return syntaxError("Unexpected token '" + tokenText + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private void expect(TokenType type) {
+ if (tok.getType() != type) {
+ throw unexpectedToken();
+ }
+ nextToken();
+ }
+
+ private void expectCommandEnd() {
+ // Allow EOF to be substituted for COMMAND_END
+ if (tok.getType() == TokenType.EOF) {
+ nextToken();
+ return;
+ }
+ if (tok.getType() != TokenType.COMMAND_END) {
+ throw syntaxError("Expected token '\\n' or 'EOF', but saw '" + tok.getText() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ nextToken();
+ }
+
+ private QDirModuleCommand parseModuleCommand() {
+ QDirModuleCommand node = new QDirModuleCommand();
+ markStart(node);
+ expect(TokenType.MODULE);
+ if (tok.getType() == TokenType.WORD) {
+ node.setModuleIdentifier(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirSingletonCommand parseSingletonCommand() {
+ QDirSingletonCommand node = new QDirSingletonCommand();
+ markStart(node);
+ expect(TokenType.SINGLETON);
+ if (tok.getType() == TokenType.WORD) {
+ node.setTypeName(parseWord());
+ if (tok.getType() == TokenType.DECIMAL) {
+ node.setInitialVersion(parseVersion());
+ if (tok.getType() == TokenType.WORD) {
+ node.setFile(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ }
+ }
+ throw unexpectedToken();
+ };
+
+ private QDirInternalCommand parseInternalCommand() {
+ QDirInternalCommand node = new QDirInternalCommand();
+ markStart(node);
+ expect(TokenType.INTERNAL);
+ if (tok.getType() == TokenType.WORD) {
+ node.setTypeName(parseWord());
+ if (tok.getType() == TokenType.WORD) {
+ node.setFile(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirResourceCommand parseResourceCommand() {
+ QDirResourceCommand node = new QDirResourceCommand();
+ markStart(node);
+ if (tok.getType() == TokenType.WORD) {
+ node.setResourceIdentifier(parseWord());
+ if (tok.getType() == TokenType.DECIMAL) {
+ node.setInitialVersion(parseVersion());
+ if (tok.getType() == TokenType.WORD) {
+ node.setFile(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ }
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirPluginCommand parsePluginCommand() {
+ QDirPluginCommand node = new QDirPluginCommand();
+ markStart(node);
+ expect(TokenType.PLUGIN);
+ if (tok.getType() == TokenType.WORD) {
+ node.setName(parseWord());
+ if (tok.getType() == TokenType.WORD) {
+ node.setPath(parseWord());
+ }
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirClassnameCommand parseClassnameCommand() {
+ QDirClassnameCommand node = new QDirClassnameCommand();
+ markStart(node);
+ expect(TokenType.CLASSNAME);
+ if (tok.getType() == TokenType.WORD) {
+ node.setIdentifier(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirTypeInfoCommand parseTypeInfoCommand() {
+ QDirTypeInfoCommand node = new QDirTypeInfoCommand();
+ markStart(node);
+ expect(TokenType.TYPEINFO);
+ if (tok.getType() == TokenType.WORD) {
+ node.setFile(parseWord());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirDependsCommand parseDependsCommand() {
+ QDirDependsCommand node = new QDirDependsCommand();
+ markStart(node);
+ expect(TokenType.DEPENDS);
+ if (tok.getType() == TokenType.WORD) {
+ node.setModuleIdentifier(parseWord());
+ if (tok.getType() == TokenType.DECIMAL) {
+ node.setInitialVersion(parseVersion());
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirDesignerSupportedCommand parseDesignerSupportedCommand() {
+ QDirDesignerSupportedCommand node = new QDirDesignerSupportedCommand();
+ markStart(node);
+ expect(TokenType.DESIGNERSUPPORTED);
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+
+ private QDirCommentCommand parseCommentCommand() {
+ QDirCommentCommand node = new QDirCommentCommand();
+ markStart(node);
+ if (tok.getType() == TokenType.COMMENT) {
+ node.setText(tok.getText());
+ nextToken();
+ expectCommandEnd();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirVersion parseVersion() {
+ QDirVersion node = new QDirVersion();
+ markStart(node);
+ if (tok.getType() == TokenType.DECIMAL) {
+ node.setVersionString(tok.getText());
+ nextToken();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+
+ private QDirWord parseWord() {
+ QDirWord node = new QDirWord();
+ markStart(node);
+ if (tok.getType() == TokenType.WORD) {
+ node.setText(tok.getText());
+ nextToken();
+ markEnd();
+ return node;
+ }
+ throw unexpectedToken();
+ }
+}

Back to the top