mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 481126 - Walk QML Types AST
Added several classes that can be used to aggregate all of the information from within a .qmltypes file as defined by http://doc.qt.io/qt-5/qtqml-modules-qmldir.html#writing-a-qmltypes-file Change-Id: Ia36c3bb1a4a0254c4125733d6faabbb5a4606133 Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
This commit is contained in:
parent
c68dc46f54
commit
0027b29aba
21 changed files with 1254 additions and 95 deletions
|
@ -615,7 +615,8 @@
|
|||
throw new Error("QML only supports ECMA Script Language Specification 5 or older");
|
||||
}
|
||||
|
||||
if (this.options.mode === "qml" || this.options.mode === "qmltypes") {
|
||||
// Disabled 'qmltypes' mode for now since the normal parser can't parse it anyway
|
||||
if (this.options.mode === "qml") {
|
||||
// Force strict mode
|
||||
this.strict = true;
|
||||
|
||||
|
|
|
@ -55,18 +55,6 @@ var stats, modes = {
|
|||
}
|
||||
}
|
||||
},
|
||||
"Normal QMLTypes": {
|
||||
config: {
|
||||
parse: acorn.parse,
|
||||
options: {
|
||||
mode: "qmltypes"
|
||||
},
|
||||
filter: function (test) {
|
||||
var opts = test.options || {};
|
||||
return opts.normal !== false && opts.qmltypes !== false;
|
||||
}
|
||||
}
|
||||
},
|
||||
"Loose QMLTypes": {
|
||||
config: {
|
||||
parse: acorn.parse_dammit,
|
||||
|
|
|
@ -34,11 +34,14 @@ import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode;
|
|||
@SuppressWarnings("nls")
|
||||
public class QMLAnalyzer implements IQMLAnalyzer {
|
||||
|
||||
private QMLModuleResolver moduleResolver;
|
||||
private ScriptEngine engine;
|
||||
private Invocable invoke;
|
||||
private Object tern;
|
||||
|
||||
@Override
|
||||
public void load() throws ScriptException, IOException, NoSuchMethodException {
|
||||
moduleResolver = new QMLModuleResolver(this);
|
||||
engine = new ScriptEngineManager().getEngineByName("nashorn");
|
||||
invoke = (Invocable) engine;
|
||||
|
||||
|
@ -88,6 +91,7 @@ public class QMLAnalyzer implements IQMLAnalyzer {
|
|||
return fixPathString(path.normalize().toString());
|
||||
};
|
||||
options.put("resolveDirectory", invoke.invokeFunction("resolveDirectory", resolveDirectory));
|
||||
options.put("resolveModule", invoke.invokeFunction("resolveModule", moduleResolver));
|
||||
|
||||
synchronized (this) {
|
||||
tern = invoke.invokeFunction("newTernServer", options);
|
||||
|
@ -203,19 +207,13 @@ public class QMLAnalyzer implements IQMLAnalyzer {
|
|||
public IQmlASTNode parseString(String text, String mode, boolean locations, boolean ranges)
|
||||
throws NoSuchMethodException, ScriptException {
|
||||
waitUntilLoaded();
|
||||
Bindings query = engine.createBindings();
|
||||
query.put("type", "parseString");
|
||||
query.put("text", text);
|
||||
Bindings options = engine.createBindings();
|
||||
options.put("mode", mode);
|
||||
options.put("locations", locations);
|
||||
options.put("ranges", ranges);
|
||||
query.put("options", options);
|
||||
Bindings request = engine.createBindings();
|
||||
request.put("query", query);
|
||||
|
||||
ASTCallback callback = new ASTCallback();
|
||||
invoke.invokeMethod(tern, "request", request, invoke.invokeFunction("requestCallback", callback));
|
||||
invoke.invokeMethod(tern, "parseString", text, options, invoke.invokeFunction("requestCallback", callback));
|
||||
return callback.getAST();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*******************************************************************************
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.eclipse.cdt.internal.qt.core.qmltypes.QMLModelBuilder;
|
||||
import org.eclipse.cdt.internal.qt.core.qmltypes.QMLModuleInfo;
|
||||
import org.eclipse.cdt.qt.core.IQtInstall;
|
||||
import org.eclipse.cdt.qt.core.IQtInstallManager;
|
||||
import org.eclipse.cdt.qt.core.qmldir.QMLDirectoryInfo;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode;
|
||||
|
||||
public class QMLModuleResolver {
|
||||
private final QMLAnalyzer analyzer;
|
||||
private final IQtInstallManager manager;
|
||||
private final QMLModelBuilder builder;
|
||||
|
||||
public QMLModuleResolver(QMLAnalyzer analyzer) {
|
||||
this.analyzer = analyzer;
|
||||
this.manager = Activator.getService(IQtInstallManager.class);
|
||||
this.builder = new QMLModelBuilder();
|
||||
}
|
||||
|
||||
// TODO: determine exactly how to give this to Tern. For now we'll just return the reference to the QMLModuleInfo
|
||||
// that we found
|
||||
public QMLModuleInfo resolveModule(String module) throws NoSuchMethodException, ScriptException {
|
||||
QMLModuleInfo info = builder.getModule(module);
|
||||
if (info == null) {
|
||||
Path path = getModulePath(module);
|
||||
if (path != null) {
|
||||
File qmldir = path.resolve("qmldir").normalize().toFile(); //$NON-NLS-1$
|
||||
try {
|
||||
String types = getQmlTypesFile(qmldir);
|
||||
File qmlTypes = path.resolve(types).toFile();
|
||||
String typeContents = fileToString(qmlTypes);
|
||||
IQmlASTNode ast = analyzer.parseString(typeContents, "qmltypes", false, false); //$NON-NLS-1$
|
||||
info = builder.addModule(module, ast);
|
||||
} catch (IOException e) {
|
||||
Activator.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
private String fileToString(File file) throws IOException {
|
||||
try (InputStream stream = new FileInputStream(file)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int read = -1;
|
||||
while ((read = stream.read()) != -1) {
|
||||
sb.append((char) read);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String getQmlTypesFile(File qmldir) throws IOException {
|
||||
try (InputStream stream = new FileInputStream(qmldir)) {
|
||||
QMLDirectoryInfo info = new QMLDirectoryInfo(stream);
|
||||
return info.getTypesFileName();
|
||||
}
|
||||
}
|
||||
|
||||
private Path getModulePath(String module) {
|
||||
if (module != null) {
|
||||
for (IQtInstall install : manager.getInstalls()) {
|
||||
Path qmlPath = install.getQmlPath();
|
||||
Path modPath = null;
|
||||
if (module.equals("QtQuick")) { //$NON-NLS-1$
|
||||
modPath = qmlPath.resolve("QtQuick.2").normalize(); //$NON-NLS-1$
|
||||
} else {
|
||||
modPath = qmlPath;
|
||||
for (String part : module.split("\\.")) { //$NON-NLS-1$
|
||||
modPath = modPath.resolve(part).normalize();
|
||||
}
|
||||
}
|
||||
if (modPath.toFile().exists()) {
|
||||
return modPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -150,11 +150,20 @@ public class QmlASTNodeHandler implements InvocationHandler {
|
|||
methodResults.put(mName, handleObject(node.get(pName), method.getReturnType()));
|
||||
}
|
||||
}
|
||||
return methodResults.get(method.getName());
|
||||
return methodResults.get(mName);
|
||||
}
|
||||
|
||||
private Object handleObject(Object value, Class<?> expectedType) throws Throwable {
|
||||
if (expectedType.isAssignableFrom(ISourceLocation.class)) {
|
||||
if (expectedType.isArray()) {
|
||||
Object arr = Array.newInstance(expectedType.getComponentType(), ((Bindings) value).size());
|
||||
int ctr = 0;
|
||||
for (Object obj : ((Bindings) value).values()) {
|
||||
Array.set(arr, ctr++, handleObject(obj, expectedType.getComponentType()));
|
||||
}
|
||||
return arr;
|
||||
} else if (expectedType.equals(Object.class)) {
|
||||
return value;
|
||||
} else if (expectedType.isAssignableFrom(ISourceLocation.class)) {
|
||||
// ISourceLocation doesn't correspond to an AST Node and needs to be created manually from
|
||||
// the given Bindings.
|
||||
if (value instanceof Bindings) {
|
||||
|
@ -170,13 +179,6 @@ public class QmlASTNodeHandler implements InvocationHandler {
|
|||
return loc;
|
||||
}
|
||||
return new SourceLocation();
|
||||
} else if (expectedType.isArray()) {
|
||||
Object arr = Array.newInstance(expectedType.getComponentType(), ((Bindings) value).size());
|
||||
int ctr = 0;
|
||||
for (Object obj : ((Bindings) value).values()) {
|
||||
Array.set(arr, ctr++, handleObject(obj, expectedType.getComponentType()));
|
||||
}
|
||||
return arr;
|
||||
} else if (expectedType.isAssignableFrom(List.class)) {
|
||||
if (value instanceof Bindings) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
|
|
|
@ -40,6 +40,11 @@ public class QtInstall implements IQtInstall {
|
|||
return qmakePath.resolve("../lib"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getQmlPath() {
|
||||
return qmakePath.resolve("../../qml"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public static String getSpec(String qmakePath) throws IOException {
|
||||
Process proc = new ProcessBuilder(qmakePath, "-query", "QMAKE_XSPEC").start(); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
|
||||
public class QMLComponentInfo {
|
||||
static final String IDENTIFIER = "Component"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
|
||||
static final String PROPERTY_PROTOTYPE = "prototype"; //$NON-NLS-1$
|
||||
static final String PROPERTY_DEF_PROPERTY = "defaultProperty"; //$NON-NLS-1$
|
||||
static final String PROPERTY_ATTACHED_TYPE = "attachedType"; //$NON-NLS-1$
|
||||
static final String PROPERTY_EXPORTS = "exports"; //$NON-NLS-1$
|
||||
static final String PROPERTY_EXPORT_REVISIONS = "exportMetaObjectRevisions"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private String prototype;
|
||||
private String defaultProperty;
|
||||
private String attachedType;
|
||||
private Integer[] exportMetaObjectRevisions;
|
||||
private List<QMLExportInfo> exportList = new ArrayList<>();
|
||||
private List<QMLPropertyInfo> propertyList = new ArrayList<>();
|
||||
private List<QMLMethodInfo> methodList = new ArrayList<>();
|
||||
private List<QMLSignalInfo> signalList = new ArrayList<>();
|
||||
private List<QMLEnumInfo> enumList = new ArrayList<>();
|
||||
|
||||
protected QMLComponentInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER);
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (member instanceof IQmlPropertyBinding) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_PROTOTYPE:
|
||||
this.prototype = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_DEF_PROPERTY:
|
||||
this.defaultProperty = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_ATTACHED_TYPE:
|
||||
this.attachedType = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_EXPORTS:
|
||||
String[] exports = builder.getStringArrayBinding(prop);
|
||||
for (String exp : exports) {
|
||||
this.exportList.add(new QMLExportInfo(builder, exp));
|
||||
}
|
||||
break;
|
||||
case PROPERTY_EXPORT_REVISIONS:
|
||||
this.exportMetaObjectRevisions = builder.getIntegerArrayBinding(prop);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else if (member instanceof IQmlObjectDefinition) {
|
||||
IQmlObjectDefinition object = (IQmlObjectDefinition) member;
|
||||
switch (object.getIdentifier().getName()) {
|
||||
case QMLPropertyInfo.IDENTIFIER:
|
||||
this.propertyList.add(new QMLPropertyInfo(builder, object));
|
||||
break;
|
||||
case QMLMethodInfo.IDENTIFIER:
|
||||
this.methodList.add(new QMLMethodInfo(builder, object));
|
||||
break;
|
||||
case QMLSignalInfo.IDENTIFIER:
|
||||
this.signalList.add(new QMLSignalInfo(builder, object));
|
||||
break;
|
||||
case QMLEnumInfo.IDENTIFIER:
|
||||
this.enumList.add(new QMLEnumInfo(builder, object));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
builder.unexpectedNode(member);
|
||||
}
|
||||
}
|
||||
exportList = Collections.unmodifiableList(exportList);
|
||||
propertyList = Collections.unmodifiableList(propertyList);
|
||||
methodList = Collections.unmodifiableList(methodList);
|
||||
signalList = Collections.unmodifiableList(signalList);
|
||||
enumList = Collections.unmodifiableList(enumList);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getPrototype() {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
public String getDefaultProperty() {
|
||||
return defaultProperty;
|
||||
}
|
||||
|
||||
public String getAttachedType() {
|
||||
return attachedType;
|
||||
}
|
||||
|
||||
public List<QMLExportInfo> getExports() {
|
||||
return exportList;
|
||||
}
|
||||
|
||||
public Integer[] getExportMetaObjectRevisions() {
|
||||
return Arrays.copyOf(exportMetaObjectRevisions, exportMetaObjectRevisions.length);
|
||||
}
|
||||
|
||||
public List<QMLPropertyInfo> getProperties() {
|
||||
return propertyList;
|
||||
}
|
||||
|
||||
public List<QMLMethodInfo> getMethods() {
|
||||
return methodList;
|
||||
}
|
||||
|
||||
public List<QMLSignalInfo> getSignals() {
|
||||
return signalList;
|
||||
}
|
||||
|
||||
public List<QMLEnumInfo> getEnums() {
|
||||
return enumList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IJSObjectExpression;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IJSProperty;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlScriptBinding;
|
||||
import org.eclipse.cdt.qt.core.qmljs.QMLExpressionEvaluator;
|
||||
import org.eclipse.cdt.qt.core.qmljs.QMLExpressionEvaluator.InvalidExpressionException;
|
||||
|
||||
public class QMLEnumInfo {
|
||||
public static class EnumConst {
|
||||
private final String identifier;
|
||||
private final int value;
|
||||
|
||||
private EnumConst(String ident, int val) {
|
||||
this.identifier = ident;
|
||||
this.value = val;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static final String IDENTIFIER = "Enum"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
|
||||
static final String PROPERTY_VALUE = "values"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private List<EnumConst> constantList = new ArrayList<>();
|
||||
|
||||
QMLEnumInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (builder.ensureNode(member, IQmlPropertyBinding.class)) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_VALUE:
|
||||
if (builder.ensureNode(prop.getBinding(), IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding binding = ((IQmlScriptBinding) prop.getBinding());
|
||||
if (builder.ensureNode(binding.getScript(), IJSObjectExpression.class)) {
|
||||
IJSObjectExpression objExpr = (IJSObjectExpression) binding.getScript();
|
||||
for (IJSProperty property : objExpr.getProperties()) {
|
||||
Object value;
|
||||
try {
|
||||
value = QMLExpressionEvaluator.evaluateConstExpr(property.getValue());
|
||||
if (value instanceof Number) {
|
||||
constantList.add(new EnumConst(property.getType(), ((Number) value).intValue()));
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
builder.handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
constantList = Collections.unmodifiableList(constantList);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<EnumConst> getConstants() {
|
||||
return constantList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
public class QMLExportInfo {
|
||||
private String type;
|
||||
private String version;
|
||||
|
||||
QMLExportInfo(QMLModelBuilder builder, String export) {
|
||||
String[] info = export.split("\\h+"); //$NON-NLS-1$
|
||||
switch (info.length) {
|
||||
case 2:
|
||||
this.type = info[0];
|
||||
this.version = info[1];
|
||||
break;
|
||||
case 1:
|
||||
this.type = info[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
|
||||
public class QMLMethodInfo {
|
||||
static final String IDENTIFIER = "Method"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$ s
|
||||
static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
|
||||
static final String PROPERTY_REVISION = "revision"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private int revision;
|
||||
private List<QMLParameterInfo> parameterList = new ArrayList<>();
|
||||
|
||||
QMLMethodInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (member instanceof IQmlPropertyBinding) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_TYPE:
|
||||
this.type = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_REVISION:
|
||||
this.revision = builder.getIntegerBinding(prop);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else if (member instanceof IQmlObjectDefinition) {
|
||||
this.parameterList.add(new QMLParameterInfo(builder, (IQmlObjectDefinition) member));
|
||||
} else {
|
||||
builder.unexpectedNode(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.internal.qt.core.Activator;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IJSArrayExpression;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IJSExpression;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlASTNode;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlBinding;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlProgram;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlQualifiedID;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlRootObject;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlScriptBinding;
|
||||
import org.eclipse.cdt.qt.core.qmljs.QMLExpressionEvaluator;
|
||||
import org.eclipse.cdt.qt.core.qmljs.QMLExpressionEvaluator.InvalidExpressionException;
|
||||
|
||||
public class QMLModelBuilder {
|
||||
|
||||
private final Map<String, QMLModuleInfo> moduleMap = new HashMap<>();
|
||||
|
||||
public QMLModelBuilder() {
|
||||
}
|
||||
|
||||
public QMLModuleInfo addModule(String module, IQmlASTNode ast) {
|
||||
QMLModuleInfo info = moduleMap.get(module);
|
||||
if (!moduleMap.containsKey(module)) {
|
||||
if (ensureNode(ast, IQmlProgram.class)) {
|
||||
IQmlRootObject obj = ((IQmlProgram) ast).getRootObject();
|
||||
if (ensureNode(obj, IQmlRootObject.class)) {
|
||||
info = new QMLModuleInfo(this, obj);
|
||||
moduleMap.put(module, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public QMLModuleInfo getModule(String module) {
|
||||
return moduleMap.get(module);
|
||||
}
|
||||
|
||||
public boolean hasModule(String module) {
|
||||
return moduleMap.get(module) != null;
|
||||
}
|
||||
|
||||
boolean ensureIdentifier(IQmlQualifiedID actual, String expected) {
|
||||
if (!actual.getName().equals(expected)) {
|
||||
Activator.log("[QmlTypes] Unexpected node identifier: expected '" + expected + "', but was '" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ actual.getName() + "'"); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean ensureNode(IQmlASTNode actual, Class<? extends IQmlASTNode> expected) {
|
||||
if (!expected.isInstance(actual)) {
|
||||
Activator.log("[QmlTypes] Expected node '" + expected + "', but was '" + actual.getClass().getInterfaces()[0] + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean ensureValue(Object actual, Class<?> expected) {
|
||||
if (!expected.isInstance(actual)) {
|
||||
Activator.log("[QmlTypes] Unexpected value: expected '" + expected + "', but was '" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ actual.getClass().getInterfaces()[0] + "'"); //$NON-NLS-1$
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unexpectedNode(IQmlASTNode node) {
|
||||
Activator.log("[QmlTypes] Unexpected node '" + node.getClass().getInterfaces()[0] + "'"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
String getStringBinding(IQmlPropertyBinding prop) {
|
||||
IQmlBinding b = prop.getBinding();
|
||||
if (ensureNode(b, IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding sb = (IQmlScriptBinding) b;
|
||||
if (ensureNode(sb.getScript(), IJSExpression.class)) {
|
||||
try {
|
||||
Object value = QMLExpressionEvaluator.evaluateConstExpr((IJSExpression) sb.getScript());
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] getStringArrayBinding(IQmlPropertyBinding prop) {
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
IQmlBinding b = prop.getBinding();
|
||||
if (ensureNode(b, IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding sb = (IQmlScriptBinding) b;
|
||||
if (ensureNode(sb.getScript(), IJSArrayExpression.class)) {
|
||||
IJSArrayExpression arrExpr = (IJSArrayExpression) sb.getScript();
|
||||
for (IJSExpression expr : arrExpr.getElements()) {
|
||||
try {
|
||||
Object value = QMLExpressionEvaluator.evaluateConstExpr(expr);
|
||||
if (value instanceof String) {
|
||||
result.add((String) value);
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray(new String[result.size()]);
|
||||
}
|
||||
|
||||
public Integer[] getIntegerArrayBinding(IQmlPropertyBinding prop) {
|
||||
ArrayList<Integer> result = new ArrayList<>();
|
||||
IQmlBinding b = prop.getBinding();
|
||||
if (ensureNode(b, IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding sb = (IQmlScriptBinding) b;
|
||||
if (ensureNode(sb.getScript(), IJSArrayExpression.class)) {
|
||||
IJSArrayExpression arrExpr = (IJSArrayExpression) sb.getScript();
|
||||
for (IJSExpression expr : arrExpr.getElements()) {
|
||||
try {
|
||||
Object value = QMLExpressionEvaluator.evaluateConstExpr(expr);
|
||||
if (value instanceof Number) {
|
||||
result.add(((Number) value).intValue());
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray(new Integer[result.size()]);
|
||||
}
|
||||
|
||||
boolean getBooleanBinding(IQmlPropertyBinding prop) {
|
||||
IQmlBinding b = prop.getBinding();
|
||||
if (ensureNode(b, IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding sb = (IQmlScriptBinding) b;
|
||||
if (ensureNode(sb.getScript(), IJSExpression.class)) {
|
||||
try {
|
||||
Object value = QMLExpressionEvaluator.evaluateConstExpr((IJSExpression) sb.getScript());
|
||||
if (value instanceof Number) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Integer getIntegerBinding(IQmlPropertyBinding prop) {
|
||||
IQmlBinding b = prop.getBinding();
|
||||
if (ensureNode(b, IQmlScriptBinding.class)) {
|
||||
IQmlScriptBinding sb = (IQmlScriptBinding) b;
|
||||
if (ensureNode(sb.getScript(), IJSExpression.class)) {
|
||||
try {
|
||||
Object value = QMLExpressionEvaluator.evaluateConstExpr((IJSExpression) sb.getScript());
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
} catch (InvalidExpressionException e) {
|
||||
handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void handleException(Throwable t) {
|
||||
Activator.log("[QmlTypes] " + t.getMessage()); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
}
|
|
@ -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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlRootObject;
|
||||
|
||||
public class QMLModuleInfo {
|
||||
static final String IDENTIFIER = "Module"; //$NON-NLS-1$
|
||||
|
||||
private List<QMLComponentInfo> componentsList = new ArrayList<>();
|
||||
|
||||
QMLModuleInfo(QMLModelBuilder builder, IQmlRootObject obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (builder.ensureNode(member, IQmlObjectDefinition.class)) {
|
||||
componentsList.add(new QMLComponentInfo(builder, (IQmlObjectDefinition) member));
|
||||
}
|
||||
}
|
||||
}
|
||||
componentsList = Collections.unmodifiableList(componentsList);
|
||||
}
|
||||
|
||||
public List<QMLComponentInfo> getComponents() {
|
||||
return componentsList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
|
||||
public class QMLParameterInfo {
|
||||
static final String IDENTIFIER = "Parameter"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
|
||||
static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
QMLParameterInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (builder.ensureNode(member, IQmlPropertyBinding.class)) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_TYPE:
|
||||
this.type = builder.getStringBinding(prop);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
|
||||
public class QMLPropertyInfo {
|
||||
static final String IDENTIFIER = "Property"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$
|
||||
static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
|
||||
static final String PROPERTY_READONLY = "isReadonly"; //$NON-NLS-1$
|
||||
static final String PROPERTY_POINTER = "isPointer"; //$NON-NLS-1$
|
||||
static final String PROPERTY_LIST = "isList"; //$NON-NLS-1$
|
||||
static final String PROPERTY_REVISION = "revision"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private boolean readonly = false;
|
||||
private boolean pointer = false;
|
||||
private boolean list = false;
|
||||
private int revision;
|
||||
|
||||
QMLPropertyInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (builder.ensureNode(member, IQmlPropertyBinding.class)) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_TYPE:
|
||||
this.type = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_READONLY:
|
||||
this.readonly = builder.getBooleanBinding(prop);
|
||||
break;
|
||||
case PROPERTY_POINTER:
|
||||
this.pointer = builder.getBooleanBinding(prop);
|
||||
break;
|
||||
case PROPERTY_LIST:
|
||||
this.list = builder.getBooleanBinding(prop);
|
||||
break;
|
||||
case PROPERTY_REVISION:
|
||||
this.revision = builder.getIntegerBinding(prop);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public boolean isReadonly() {
|
||||
return readonly;
|
||||
}
|
||||
|
||||
public boolean isPointer() {
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public boolean isList() {
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmltypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectDefinition;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlObjectMember;
|
||||
import org.eclipse.cdt.qt.core.qmljs.IQmlPropertyBinding;
|
||||
|
||||
public class QMLSignalInfo {
|
||||
static final String IDENTIFIER = "Signal"; //$NON-NLS-1$
|
||||
|
||||
static final String PROPERTY_NAME = "name"; //$NON-NLS-1$ s
|
||||
static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
|
||||
static final String PROPERTY_REVISION = "revision"; //$NON-NLS-1$
|
||||
|
||||
private String name;
|
||||
private String type;
|
||||
private Integer revision;
|
||||
private List<QMLParameterInfo> parameterList = new ArrayList<>();
|
||||
|
||||
QMLSignalInfo(QMLModelBuilder builder, IQmlObjectDefinition obj) {
|
||||
if (builder.ensureIdentifier(obj.getIdentifier(), IDENTIFIER)) {
|
||||
for (IQmlObjectMember member : obj.getBody().getMembers()) {
|
||||
if (member instanceof IQmlPropertyBinding) {
|
||||
IQmlPropertyBinding prop = (IQmlPropertyBinding) member;
|
||||
switch (prop.getIdentifier().getName()) {
|
||||
case PROPERTY_NAME:
|
||||
this.name = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_TYPE:
|
||||
this.type = builder.getStringBinding(prop);
|
||||
break;
|
||||
case PROPERTY_REVISION:
|
||||
this.revision = builder.getIntegerBinding(prop);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else if (member instanceof IQmlObjectDefinition) {
|
||||
this.parameterList.add(new QMLParameterInfo(builder, (IQmlObjectDefinition) member));
|
||||
} else {
|
||||
builder.unexpectedNode(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getRevision() {
|
||||
return revision;
|
||||
}
|
||||
}
|
|
@ -25,4 +25,6 @@ public interface IQtInstall {
|
|||
|
||||
Path getLibPath();
|
||||
|
||||
Path getQmlPath();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*******************************************************************************
|
||||
* 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.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.eclipse.cdt.internal.qt.core.Activator;
|
||||
|
||||
public class QMLDirectoryInfo {
|
||||
public static class Module {
|
||||
private final String name;
|
||||
private final String initialVersion;
|
||||
|
||||
public Module(String name, String ver) {
|
||||
this.name = name;
|
||||
this.initialVersion = ver;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getInitialVersion() {
|
||||
return initialVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Plugin {
|
||||
private final String name;
|
||||
private final Path path;
|
||||
|
||||
private Plugin(String name, String path) {
|
||||
this.name = name;
|
||||
Path p = null;
|
||||
if (path != null) {
|
||||
try {
|
||||
p = Paths.get(path);
|
||||
} catch (InvalidPathException e) {
|
||||
Activator.log(e);
|
||||
}
|
||||
}
|
||||
this.path = p;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Path getRelativePath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResourceFile {
|
||||
private final String name;
|
||||
private final boolean internal;
|
||||
private final boolean singleton;
|
||||
private final String initialVersion;
|
||||
|
||||
private ResourceFile(String name, String ver, boolean internal, boolean singleton) {
|
||||
this.name = name;
|
||||
this.initialVersion = ver;
|
||||
this.internal = internal;
|
||||
this.singleton = singleton;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getInitialVersion() {
|
||||
return initialVersion;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
public boolean isInternal() {
|
||||
return internal;
|
||||
}
|
||||
}
|
||||
|
||||
private String moduleIdentifier;
|
||||
private Plugin plugin;
|
||||
private String classname;
|
||||
private String typeInfo;
|
||||
private final Collection<Module> depends;
|
||||
private final Collection<ResourceFile> resources;
|
||||
private boolean designersupported;
|
||||
|
||||
public QMLDirectoryInfo(InputStream input) {
|
||||
this.depends = new LinkedList<>();
|
||||
this.resources = new LinkedList<>();
|
||||
|
||||
IQDirAST ast = new QMLDirectoryParser().parse(input);
|
||||
for (IQDirCommand c : ast.getCommands()) {
|
||||
if (c instanceof IQDirModuleCommand) {
|
||||
if (moduleIdentifier == null) {
|
||||
moduleIdentifier = ((IQDirModuleCommand) c).getModuleIdentifier().getText();
|
||||
}
|
||||
} else if (c instanceof IQDirPluginCommand) {
|
||||
if (plugin == null) {
|
||||
IQDirPluginCommand pc = (IQDirPluginCommand) c;
|
||||
plugin = new Plugin(pc.getName().getText(), pc.getPath() != null ? pc.getPath().getText() : null);
|
||||
}
|
||||
} else if (c instanceof IQDirTypeInfoCommand) {
|
||||
if (typeInfo == null) {
|
||||
typeInfo = ((IQDirTypeInfoCommand) c).getFile().getText();
|
||||
}
|
||||
} else if (c instanceof IQDirResourceCommand) {
|
||||
IQDirResourceCommand rc = (IQDirResourceCommand) c;
|
||||
resources.add(new ResourceFile(rc.getFile().getText(),
|
||||
rc.getInitialVersion().getVersionString(),
|
||||
false, false));
|
||||
} else if (c instanceof IQDirInternalCommand) {
|
||||
IQDirInternalCommand rc = (IQDirInternalCommand) c;
|
||||
resources.add(new ResourceFile(rc.getFile().getText(),
|
||||
null, true, false));
|
||||
} else if (c instanceof IQDirSingletonCommand) {
|
||||
IQDirSingletonCommand rc = (IQDirSingletonCommand) c;
|
||||
resources.add(new ResourceFile(rc.getFile().getText(),
|
||||
rc.getInitialVersion().getVersionString(),
|
||||
false, true));
|
||||
} else if (c instanceof IQDirDependsCommand) {
|
||||
IQDirDependsCommand dc = (IQDirDependsCommand) c;
|
||||
depends.add(new Module(dc.getModuleIdentifier().getText(),
|
||||
dc.getInitialVersion().getVersionString()));
|
||||
} else if (c instanceof IQDirClassnameCommand) {
|
||||
if (classname == null) {
|
||||
classname = ((IQDirClassnameCommand) c).getIdentifier().getText();
|
||||
}
|
||||
} else if (c instanceof IQDirDesignerSupportedCommand) {
|
||||
designersupported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getModuleIdentifier() {
|
||||
return moduleIdentifier;
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public String getClassname() {
|
||||
return classname;
|
||||
}
|
||||
|
||||
public String getTypesFileName() {
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
public Collection<Module> getDependentModules() {
|
||||
return Collections.unmodifiableCollection(depends);
|
||||
}
|
||||
|
||||
public Collection<ResourceFile> getResources() {
|
||||
return Collections.unmodifiableCollection(resources);
|
||||
}
|
||||
|
||||
public boolean isDesignersupported() {
|
||||
return designersupported;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*******************************************************************************
|
||||
* 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.qmljs;
|
||||
|
||||
public final class QMLExpressionEvaluator {
|
||||
private QMLExpressionEvaluator() {
|
||||
}
|
||||
|
||||
public static class InvalidExpressionException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 4803923632666457229L;
|
||||
|
||||
private IJSExpression offendingExpression;
|
||||
|
||||
public InvalidExpressionException(String msg, IJSExpression expr) {
|
||||
super(msg);
|
||||
this.offendingExpression = expr;
|
||||
}
|
||||
|
||||
public IJSExpression getOffendingExpression() {
|
||||
return offendingExpression;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given {@link IJSExpression} as a constant expression and returns the result. At the moment this only supports
|
||||
* very simple expressions involving unary operators and literals alone. Support for more complex expressions will be added as
|
||||
* needed.
|
||||
*
|
||||
* @param expr
|
||||
* the expression to be evaluated
|
||||
*
|
||||
* @throws InvalidExpressionException
|
||||
* if the given expression can't be reduced to a single constant
|
||||
*/
|
||||
public static Object evaluateConstExpr(IJSExpression expr) throws InvalidExpressionException {
|
||||
if (expr instanceof IJSLiteral) {
|
||||
return ((IJSLiteral) expr).getValue();
|
||||
} else if (expr instanceof IJSUnaryExpression) {
|
||||
IJSUnaryExpression unary = (IJSUnaryExpression) expr;
|
||||
Object arg = evaluateConstExpr(unary.getArgument());
|
||||
switch (unary.getOperator()) {
|
||||
case Plus:
|
||||
return unaryPlus(arg, unary.getArgument());
|
||||
case Negation:
|
||||
return unaryNegate(arg, unary.getArgument());
|
||||
case BitwiseNot:
|
||||
return unaryBitwiseNot(arg, unary.getArgument());
|
||||
case Not:
|
||||
return unaryNot(arg, unary.getArgument());
|
||||
default:
|
||||
}
|
||||
}
|
||||
throw new InvalidExpressionException("Cannot reduce '" + expr + "' to a constant", expr); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
private static Object unaryPlus(Object object, IJSExpression expr) throws InvalidExpressionException {
|
||||
if (object instanceof Byte) {
|
||||
return +((Byte) object);
|
||||
} else if (object instanceof Short) {
|
||||
return +((Short) object);
|
||||
} else if (object instanceof Integer) {
|
||||
return +((Integer) object);
|
||||
} else if (object instanceof Long) {
|
||||
return +((Long) object);
|
||||
} else if (object instanceof Float) {
|
||||
return +((Float) object);
|
||||
} else if (object instanceof Double) {
|
||||
return +((Double) object);
|
||||
}
|
||||
throw new InvalidExpressionException("Cannot perform unary plus operation on a non-number", expr); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private static Object unaryNegate(Object object, IJSExpression expr) throws InvalidExpressionException {
|
||||
if (object instanceof Byte) {
|
||||
return -((Byte) object);
|
||||
} else if (object instanceof Short) {
|
||||
return -((Short) object);
|
||||
} else if (object instanceof Integer) {
|
||||
return -((Integer) object);
|
||||
} else if (object instanceof Long) {
|
||||
return -((Long) object);
|
||||
} else if (object instanceof Float) {
|
||||
return -((Float) object);
|
||||
} else if (object instanceof Double) {
|
||||
return -((Double) object);
|
||||
}
|
||||
throw new InvalidExpressionException("Cannot perform unary negation operation on a non-number", expr); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private static Object unaryBitwiseNot(Object object, IJSExpression expr) throws InvalidExpressionException {
|
||||
if (object instanceof Byte) {
|
||||
return ~((Byte) object);
|
||||
} else if (object instanceof Short) {
|
||||
return ~((Short) object);
|
||||
} else if (object instanceof Integer) {
|
||||
return ~((Integer) object);
|
||||
} else if (object instanceof Long) {
|
||||
return ~((Long) object);
|
||||
} else if (object instanceof Float || object instanceof Double) {
|
||||
return ~((Number) object).longValue();
|
||||
}
|
||||
throw new InvalidExpressionException("Cannot perform binary not operation on a non-number", expr); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private static Object unaryNot(Object object, IJSExpression expr) throws InvalidExpressionException {
|
||||
if (object instanceof Boolean) {
|
||||
return !((Boolean) object);
|
||||
}
|
||||
throw new InvalidExpressionException("Cannot perform unary not operation on a non-boolean", expr); //$NON-NLS-1$
|
||||
}
|
||||
}
|
|
@ -8,6 +8,12 @@ function resolveDirectory(obj) {
|
|||
};
|
||||
}
|
||||
|
||||
function resolveModule(obj) {
|
||||
return function (module) {
|
||||
return obj.resolveModule(module);
|
||||
};
|
||||
}
|
||||
|
||||
function requestCallback(obj) {
|
||||
return function (err, data) {
|
||||
obj.callback(err, data);
|
||||
|
|
|
@ -65,6 +65,12 @@
|
|||
}
|
||||
return path;
|
||||
},
|
||||
resolveModule: function (module) {
|
||||
var impl = this.server.options.resolveModule;
|
||||
if (impl) {
|
||||
return impl(module);
|
||||
}
|
||||
},
|
||||
updateDirectoryImportList: function () {
|
||||
if (!this.imports) {
|
||||
this.imports = {};
|
||||
|
@ -961,35 +967,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a parse query is made to the server.
|
||||
*/
|
||||
function parse(srv, query, file) {
|
||||
var ast = null;
|
||||
if (query.file) {
|
||||
// Get the file's AST. It should have been parsed already by the server.
|
||||
ast = file.ast;
|
||||
} else {
|
||||
// Parse the file manually and get the AST.
|
||||
var options = {
|
||||
directSourceFile: file,
|
||||
allowReturnOutsideFunction: true,
|
||||
allowImportExportEverywhere: true,
|
||||
ecmaVersion: srv.options.ecmaVersion
|
||||
};
|
||||
for (var opt in query.options) {
|
||||
options[opt] = query.options[opt];
|
||||
}
|
||||
query.text = query.text || "";
|
||||
var text = srv.signalReturnFirst("preParse", query.text, options) || query.text;
|
||||
ast = infer.parse(text, options);
|
||||
srv.signal("postParse", ast, text);
|
||||
}
|
||||
return {
|
||||
ast: ast
|
||||
};
|
||||
}
|
||||
|
||||
// Register the QML plugin in Tern
|
||||
tern.registerPlugin("qml", function (server) {
|
||||
// First we want to replace the top-level defs array with our own and save the
|
||||
|
@ -1003,19 +980,41 @@
|
|||
if (this.cx) this.reset();
|
||||
};
|
||||
|
||||
// Create a method on the server object that parses a string. We can't make this
|
||||
// a query due to the fact that tern always does its infer processing on every
|
||||
// query regardless of its contents.
|
||||
server.parseString = function (text, options, callback) {
|
||||
try {
|
||||
var opts = {
|
||||
allowReturnOutsideFunction: true,
|
||||
allowImportExportEverywhere: true,
|
||||
ecmaVersion: this.options.ecmaVersion
|
||||
};
|
||||
for (var opt in options) {
|
||||
opts[opt] = options[opt];
|
||||
}
|
||||
text = this.signalReturnFirst("preParse", text, opts) || text;
|
||||
var ast = infer.parse(text, opts);
|
||||
callback(null, {
|
||||
ast: ast
|
||||
});
|
||||
this.signal("postParse", ast, text);
|
||||
} catch (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
};
|
||||
|
||||
// Create the QML Import Handler
|
||||
qmlImportHandler = exports.importHandler = new ImportHandler(server);
|
||||
|
||||
// Define the 'parseFile' and 'parseString' query types. The reason we need
|
||||
// two separate queries for these is that Tern will not allow us to resolve
|
||||
// a file without 'takesFile' being true. However, if we set 'takesFile' to
|
||||
// true, Tern will not allow a null file in the query.
|
||||
// Define the 'parseFile' query type.
|
||||
tern.defineQueryType("parseFile", {
|
||||
takesFile: true,
|
||||
run: parse
|
||||
});
|
||||
tern.defineQueryType("parseString", {
|
||||
run: parse
|
||||
run: function (srv, query, file) {
|
||||
return {
|
||||
ast: file.ast
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Hook into server signals
|
||||
|
|
|
@ -61,12 +61,7 @@ test("{Parse given file}", function (server, callback, name) {
|
|||
});
|
||||
|
||||
test("{Parse empty text}", function (server, callback, name) {
|
||||
server.request({
|
||||
query: {
|
||||
type: "parseString",
|
||||
text: ""
|
||||
}
|
||||
}, function (err, resp) {
|
||||
server.parseString("", null, function (err, resp) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
@ -80,12 +75,7 @@ test("{Parse empty text}", function (server, callback, name) {
|
|||
});
|
||||
|
||||
test("{Parse text no mode}", function (server, callback, name) {
|
||||
server.request({
|
||||
query: {
|
||||
type: "parseString",
|
||||
text: "import QtQuick 2.0\nModule {\n\tComponent {\n\t}\n}"
|
||||
}
|
||||
}, function (err, resp) {
|
||||
server.parseString("import QtQuick 2.0\nModule {\n\tComponent {\n\t}\n}", null, function (err, resp) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
@ -99,14 +89,8 @@ test("{Parse text no mode}", function (server, callback, name) {
|
|||
});
|
||||
|
||||
test("{Parse text (mode: qmltypes)}", function (server, callback, name) {
|
||||
server.request({
|
||||
query: {
|
||||
type: "parseString",
|
||||
text: "QtObject {\n\tobj: {\n\t\tprop1: 1,\n\t\tprop2: 2\n\t}\n}",
|
||||
options: {
|
||||
server.parseString("QtObject {\n\tobj: {\n\t\tprop1: 1,\n\t\tprop2: 2\n\t}\n}", {
|
||||
mode: "qmltypes"
|
||||
}
|
||||
}
|
||||
}, function (err, resp) {
|
||||
if (err) {
|
||||
throw err;
|
||||
|
@ -121,15 +105,9 @@ test("{Parse text (mode: qmltypes)}", function (server, callback, name) {
|
|||
});
|
||||
|
||||
test("{Parse text with locations}", function (server, callback, name) {
|
||||
server.request({
|
||||
query: {
|
||||
type: "parseString",
|
||||
text: "var w = 3",
|
||||
options: {
|
||||
server.parseString("var w = 3", {
|
||||
mode: "js",
|
||||
locations: true
|
||||
}
|
||||
}
|
||||
}, function (err, resp) {
|
||||
if (err) {
|
||||
throw err;
|
||||
|
|
Loading…
Add table
Reference in a new issue