From 1d36f36ef8ad75c676ed1ddc2e2d6a2e2dffa1a7 Mon Sep 17 00:00:00 2001 From: Matthew Bastien Date: Wed, 9 Dec 2015 14:57:25 -0500 Subject: [PATCH] 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 --- .../qt/core/tests/QMLDirectoryLexerTests.java | 287 ++++++++++++ .../core/tests/QMLDirectoryParserTests.java | 308 +++++++++++++ .../META-INF/MANIFEST.MF | 6 +- .../internal/qt/core/location/Position.java | 38 ++ .../qt/core/location/SourceLocation.java | 58 +++ .../cdt/internal/qt/core/qmldir/QDirAST.java | 36 ++ .../internal/qt/core/qmldir/QDirASTNode.java | 55 +++ .../qt/core/qmldir/QDirClassnameCommand.java | 28 ++ .../qt/core/qmldir/QDirCommentCommand.java | 28 ++ .../qt/core/qmldir/QDirDependsCommand.java | 38 ++ .../qmldir/QDirDesignerSupportedCommand.java | 16 + .../qt/core/qmldir/QDirInternalCommand.java | 38 ++ .../qt/core/qmldir/QDirModuleCommand.java | 27 ++ .../qt/core/qmldir/QDirPluginCommand.java | 38 ++ .../qt/core/qmldir/QDirResourceCommand.java | 47 ++ .../qt/core/qmldir/QDirSingletonCommand.java | 48 ++ .../qt/core/qmldir/QDirSyntaxError.java | 40 ++ .../qt/core/qmldir/QDirTypeInfoCommand.java | 28 ++ .../internal/qt/core/qmldir/QDirVersion.java | 28 ++ .../cdt/internal/qt/core/qmldir/QDirWord.java | 28 ++ .../cdt/qt/core/location/IPosition.java | 30 ++ .../cdt/qt/core/location/ISourceLocation.java | 38 ++ .../eclipse/cdt/qt/core/qmldir/IQDirAST.java | 26 ++ .../cdt/qt/core/qmldir/IQDirASTNode.java | 41 ++ .../qt/core/qmldir/IQDirClassnameCommand.java | 25 ++ .../cdt/qt/core/qmldir/IQDirCommand.java | 19 + .../qt/core/qmldir/IQDirCommentCommand.java | 25 ++ .../qt/core/qmldir/IQDirDependsCommand.java | 32 ++ .../qmldir/IQDirDesignerSupportedCommand.java | 19 + .../qt/core/qmldir/IQDirInternalCommand.java | 32 ++ .../qt/core/qmldir/IQDirModuleCommand.java | 25 ++ .../qt/core/qmldir/IQDirPluginCommand.java | 32 ++ .../qt/core/qmldir/IQDirResourceCommand.java | 39 ++ .../qt/core/qmldir/IQDirSingletonCommand.java | 39 ++ .../cdt/qt/core/qmldir/IQDirSyntaxError.java | 43 ++ .../qt/core/qmldir/IQDirTypeInfoCommand.java | 25 ++ .../cdt/qt/core/qmldir/IQDirVersion.java | 23 + .../eclipse/cdt/qt/core/qmldir/IQDirWord.java | 27 ++ .../cdt/qt/core/qmldir/QMLDirectoryLexer.java | 252 +++++++++++ .../qt/core/qmldir/QMLDirectoryParser.java | 423 ++++++++++++++++++ 40 files changed, 2434 insertions(+), 1 deletion(-) create mode 100644 qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryLexerTests.java create mode 100644 qt/org.eclipse.cdt.qt.core.tests/src/org/eclipse/cdt/qt/core/tests/QMLDirectoryParserTests.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/Position.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/location/SourceLocation.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirAST.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirASTNode.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirClassnameCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirCommentCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDependsCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirDesignerSupportedCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirInternalCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirModuleCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirPluginCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirResourceCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSingletonCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirSyntaxError.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirTypeInfoCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirVersion.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/internal/qt/core/qmldir/QDirWord.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/IPosition.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/location/ISourceLocation.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirAST.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirASTNode.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirClassnameCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirCommentCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDependsCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirDesignerSupportedCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirInternalCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirModuleCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirPluginCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirResourceCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSingletonCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirSyntaxError.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirTypeInfoCommand.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirVersion.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/IQDirWord.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryLexer.java create mode 100644 qt/org.eclipse.cdt.qt.core/src/org/eclipse/cdt/qt/core/qmldir/QMLDirectoryParser.java 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 commands; + + public QDirAST() { + commands = new ArrayList<>(); + } + + public void addCommand(IQDirCommand command) { + commands.add(command); + } + + @Override + public List 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 IPosition + * + * @return the line number + */ + public int getLine(); + + /** + * Gets the zero-indexed column indicated by this IPosition + * + * @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 ISourceLocation + * + * @return the source or null if not available + */ + public String getSource(); + + /** + * Gets the zero-indexed offset indicating the start of this ISourceLocation + * + * @return the start offset + */ + public IPosition getStart(); + + /** + * Gets the zero-indexed offset indicating the end of this ISourceLocation + * + * @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 IQDirAST represents. + * + * @return the list of all commands in the qmldir file + */ + public List 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 Module Definition qmldir Files + */ +public interface IQDirClassnameCommand extends IQDirCommand { + /** + * Gets the IQDirWord 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 Module Definition qmldir Files + */ +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 Module Definition qmldir Files + */ +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 Module Definition qmldir Files + */ +public interface IQDirDependsCommand extends IQDirCommand { + /** + * Gets the IQDirWord representing the module identifier that this qmldir module depends on. + * + * @return the module identifier + */ + public IQDirWord getModuleIdentifier(); + + /** + * Gets the IQDirVersion 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 Module Definition qmldir Files + */ +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 Module Definition qmldir Files + */ +public interface IQDirInternalCommand extends IQDirCommand { + /** + * Gets the IQDirWord representing the type name of the internal type. + * + * @return the type names + */ + public IQDirWord getTypeName(); + + /** + * Gets the IQDirWord 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 Module Definition qmldir Files + */ +public interface IQDirModuleCommand extends IQDirCommand { + /** + * Gets the IQDirWord 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 Module Definition qmldir Files + */ +public interface IQDirPluginCommand extends IQDirCommand { + /** + * Gets the IQDirWord representing the name of the plugin. + * + * @return the plugin name + */ + public IQDirWord getName(); + + /** + * Gets the IQDirWord representing the path to the plugin if it was given. + * + * @return the path to the plugin or null 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 Module Definition qmldir Files + */ +public interface IQDirResourceCommand extends IQDirCommand { + /** + * Gets the IQDirWord representing the identifier of the resource. + * + * @return the identifier of the resource + */ + public IQDirWord getResourceIdentifier(); + + /** + * Gets the IQDirVersion representing the initial version of the resource. + * + * @return the initial version + */ + public IQDirVersion getInitialVersion(); + + /** + * Gets the IQDirWord 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 Module Definition qmldir Files + */ +public interface IQDirSingletonCommand extends IQDirCommand { + /** + * Gets the IQDirWord representing the type name of the singleton type. + * + * @return the type name + */ + public IQDirWord getTypeName(); + + /** + * Gets the IQDirVersion representing the initial version of the singleton type. + * + * @return the initial version + */ + public IQDirVersion getInitialVersion(); + + /** + * Gets the IQDirWord 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 + * getSyntaxError.getOffendingToken(). + * + * @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 + * getSyntaxError.getIncompleteNode(). + * + * @return the incomplete node or null 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 Module Definition qmldir Files + */ +public interface IQDirTypeInfoCommand extends IQDirCommand { + /** + * Gets the IQDirWord 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 <MajorVersion>.<MinorVersion> + */ +public interface IQDirVersion extends IQDirASTNode { + /** + * Gets the String value of this version. The result will always be of the form "<MajorVersion>.<MinorVersion>" + * + * @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.
+ *
+ * Note: 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 InputStream representing a qmldir file into a stream of tokens through successive calls to + * nextToken. This lexer uses regular expressions to match its 16 valid token types: + *
    + *
  • COMMENT: A single line comment that begins with '#' + *
  • MODULE: Keyword 'module' + *
  • TYPEINFO: The keyword 'typeinfo' + *
  • SINGLETON: The keyword 'singleton' + *
  • INTERNAL: The keyword 'internal' + *
  • PLUGIN: The keyword 'plugin' + *
  • CLASSNAME: The keyword 'classname' + *
  • DEPENDS: The keyword 'depends' + *
  • DESIGNERSUPPORTED: The keyword 'designersupported' + *
  • WORD: A group of characters that form an identifier, filename, or path + *
  • DECIMAL: A number of the form [0-9]+ '.' [0-9]+ + *
  • INTEGER: An integer of the form [0-9]+ + *
  • WHITESPACE: A group of whitespace characters (not including newlines) + *
  • COMMAND_END: A newline character + *
  • UNKNOWN: A group of characters that does not match any of the preceding tokens + *
  • EOF: End of File + *
+ */ +public class QMLDirectoryLexer { + /** + * A single matched token returned by a QMLDirectoryLexer. A Token stores information on how it was + * matched including the type of token, the exact text that was matched, and its position in the InputStream . + */ + 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 InputStream 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 InputStream + */ + public ISourceLocation getLocation() { + return location; + } + + /** + * Gets the zero-indexed offset indicating the start of this token in the InputStream. + * + * @return the token's start offset + */ + public int getStart() { + return start; + } + + /** + * Gets the zero-indexed offset indicating the end of this token in the InputStream. + * + * @return the token's end offset + */ + public int getEnd() { + return end; + } + } + + /** + * An Enumeration encompassing the 16 possible types of tokens returned by a QMLDirectoryLexer. + * + * @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 QMLDirectoryLexer without initializing any of the its internal state. A call to + * setInput is necessary to fully initialize the lexer before any calls to nextToken. + */ + public QMLDirectoryLexer() { + } + + /** + * Prepares for lexical analysis by giving the lexer an InputStream 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 InputStream given by setInput. This is a helper method to + * skip whitespace that is equivalent to QMLDirectoryLexer.nextToken(true). + * + * @return the next token in the InputStream + * @throws IllegalArgumentException + * if setInput has not been called + */ + public Token nextToken() throws IllegalArgumentException { + return nextToken(true); + } + + /** + * Retrieves the next valid token from the InputStream given by setInput. This method has the ability + * to skip over whitespace tokens by setting skipWhitespace to true. + * + * @param skipWhitespace + * whether or not the lexer should skip whitespace tokens + * @return the next token in the InputStream + * @throws IllegalArgumentException + * if setInput 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 InputStream 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 QMLDirectoryParser 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 QMLDirectoryParser 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 SyntaxError. + * + * @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 null if not available + */ + public IQDirASTNode getIncompleteNode() { + return incompleteNode; + } + } + + private final QMLDirectoryLexer lexer; + private final Stack workingNodes; + private Token tok; + + /** + * Initializes a new QMLDirectoryParser capable of parsing an InputStream and returning an AST. + */ + public QMLDirectoryParser() { + this.lexer = new QMLDirectoryLexer(); + this.workingNodes = new Stack<>(); + } + + /** + * Parses the given InputStream into an Abstract Syntax Tree. This is a helper method equivalent to + * parse(input, true). 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 InputStream into an Abstract Syntax Tree. If tolerateErrors is true, + * 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 false 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(); + } +}