QmlJS: Support module apis defined by QML modules.

Change-Id: I18ec9daf8088f7db5ff2da11da14b539f501bab3
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
Christian Kamm
2011-10-12 08:36:02 +02:00
parent 55420e2b70
commit 0b75a66407
7 changed files with 147 additions and 29 deletions

View File

@@ -128,6 +128,14 @@ private:
friend class Snapshot;
};
class QMLJS_EXPORT ModuleApiInfo
{
public:
QString uri;
LanguageUtils::ComponentVersion version;
QString cppName;
};
class QMLJS_EXPORT LibraryInfo
{
public:
@@ -152,6 +160,7 @@ private:
QList<QmlDirParser::TypeInfo> _typeinfos;
typedef QList<LanguageUtils::FakeMetaObject::ConstPtr> FakeMetaObjectList;
FakeMetaObjectList _metaObjects;
QList<ModuleApiInfo> _moduleApis;
PluginTypeInfoStatus _dumpStatus;
QString _dumpError;
@@ -176,6 +185,12 @@ public:
void setMetaObjects(const FakeMetaObjectList &objects)
{ _metaObjects = objects; }
QList<ModuleApiInfo> moduleApis() const
{ return _moduleApis; }
void setModuleApis(const QList<ModuleApiInfo> &apis)
{ _moduleApis = apis; }
bool isValid() const
{ return _status == Found; }

View File

@@ -1285,13 +1285,10 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf
QString error, warning;
QFile file(qmlTypeFile.absoluteFilePath());
if (file.open(QIODevice::ReadOnly)) {
QString contents = QString::fromUtf8(file.readAll());
QByteArray contents = file.readAll();
file.close();
TypeDescriptionReader reader(contents);
if (!reader(&newObjects))
error = reader.errorMessage();
warning = reader.warningMessage();
parseQmlTypeDescriptions(contents, &newObjects, 0, &error, &warning);
} else {
error = file.errorString();
}
@@ -1312,13 +1309,14 @@ CppQmlTypesLoader::BuiltinObjects CppQmlTypesLoader::loadQmlTypes(const QFileInf
void CppQmlTypesLoader::parseQmlTypeDescriptions(const QByteArray &xml,
BuiltinObjects *newObjects,
QList<ModuleApiInfo> *newModuleApis,
QString *errorMessage,
QString *warningMessage)
{
errorMessage->clear();
warningMessage->clear();
TypeDescriptionReader reader(QString::fromUtf8(xml));
if (!reader(newObjects)) {
if (!reader(newObjects, newModuleApis)) {
if (reader.errorMessage().isEmpty()) {
*errorMessage = QLatin1String("unknown error");
} else {

View File

@@ -643,7 +643,7 @@ public:
static void parseQmlTypeDescriptions(
const QByteArray &qmlTypes,
BuiltinObjects *newObjects,
QString *errorMessage, QString *warningMessage);
QList<ModuleApiInfo> *newModuleApis, QString *errorMessage, QString *warningMessage);
};
class QMLJS_EXPORT CppQmlTypes

View File

@@ -89,6 +89,8 @@ public:
QHash<ImportCacheKey, Import> importCache;
QHash<QString, QList<ModuleApiInfo> > importableModuleApis;
Document::Ptr document;
QList<DiagnosticMessage> *diagnosticMessages;
@@ -231,6 +233,8 @@ Context::ImportsPerDocument LinkPrivate::linkImports()
void LinkPrivate::populateImportedTypes(Imports *imports, Document::Ptr doc)
{
importableModuleApis.clear();
// implicit imports: the <default> package is always available
loadImplicitDefaultImports(imports);
@@ -315,6 +319,18 @@ Import LinkPrivate::importFileOrDirectory(Document::Ptr doc, const ImportInfo &i
return import;
}
static ModuleApiInfo findBestModuleApi(const QList<ModuleApiInfo> &apis, const ComponentVersion &version)
{
ModuleApiInfo best;
foreach (const ModuleApiInfo &moduleApi, apis) {
if (moduleApi.version <= version
&& (!best.version.isValid() || best.version < moduleApi.version)) {
best = moduleApi;
}
}
return best;
}
/*
import Qt 4.6
import Qt 4.6 as Xxx
@@ -372,6 +388,13 @@ Import LinkPrivate::importNonFile(Document::Ptr doc, const ImportInfo &importInf
}
}
// check module apis that previous imports may have enabled
ModuleApiInfo moduleApi = findBestModuleApi(importableModuleApis.value(packageName), version);
if (moduleApi.version.isValid()) {
importFound = true;
import.object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(moduleApi.name));
}
if (!importFound && importInfo.ast()) {
import.valid = false;
error(doc, locationFromRange(importInfo.ast()->firstSourceLocation(),
@@ -442,6 +465,21 @@ bool LinkPrivate::importLibrary(Document::Ptr doc,
foreach (const CppComponentValue *object, valueOwner->cppQmlTypes().createObjectsForImport(packageName, version)) {
import->object->setMember(object->className(), object);
}
// all but no-uri module apis become available for import
QList<ModuleApiInfo> noUriModuleApis;
foreach (const ModuleApiInfo &moduleApi, libraryInfo.moduleApis()) {
if (moduleApi.uri.isEmpty()) {
noUriModuleApis += moduleApi;
} else {
importableModuleApis[moduleApi.uri] += moduleApi;
}
}
// if a module api has no uri, it shares the same name
ModuleApiInfo sameUriModuleApi = findBestModuleApi(noUriModuleApis, version);
if (sameUriModuleApi.version.isValid())
import->object->setPrototype(valueOwner->cppQmlTypes().objectByCppName(sameUriModuleApi.name));
}
}

View File

@@ -59,7 +59,9 @@ TypeDescriptionReader::~TypeDescriptionReader()
{
}
bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::ConstPtr> *objects)
bool TypeDescriptionReader::operator()(
QHash<QString, FakeMetaObject::ConstPtr> *objects,
QList<ModuleApiInfo> *moduleApis)
{
Engine engine;
@@ -77,6 +79,7 @@ bool TypeDescriptionReader::operator()(QHash<QString, FakeMetaObject::ConstPtr>
}
_objects = objects;
_moduleApis = moduleApis;
readDocument(parser.ast());
return _errorMessage.isEmpty();
@@ -152,8 +155,11 @@ void TypeDescriptionReader::readModule(UiObjectDefinition *ast)
continue;
}
if (typeName == QLatin1String("Component"))
if (typeName == QLatin1String("Component")) {
readComponent(component);
} else if (typeName == QLatin1String("ModuleApi")) {
readModuleApi(component);
}
}
}
@@ -226,6 +232,40 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast)
_objects->insert(fmo->className(), fmo);
}
void TypeDescriptionReader::readModuleApi(UiObjectDefinition *ast)
{
ModuleApiInfo apiInfo;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
UiScriptBinding *script = dynamic_cast<UiScriptBinding *>(member);
if (script) {
const QString name = toString(script->qualifiedId);
if (name == "uri") {
apiInfo.uri = readStringBinding(script);
} else if (name == "version") {
apiInfo.version = readNumericVersionBinding(script);
} else if (name == "name") {
apiInfo.name = readStringBinding(script);
} else {
addWarning(script->firstSourceLocation(),
"Expected only uri, version and name script bindings");
}
} else {
addWarning(member->firstSourceLocation(), "Expected only script bindings");
}
}
if (!apiInfo.version.isValid()) {
addError(ast->firstSourceLocation(), "ModuleApi definition has no or invalid 'version' binding");
return;
}
if (_moduleApis)
_moduleApis->append(apiInfo);
}
void TypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bool isMethod, FakeMetaObject::Ptr fmo)
{
FakeMetaMethod fmm;
@@ -438,6 +478,30 @@ double TypeDescriptionReader::readNumericBinding(AST::UiScriptBinding *ast)
return numericLit->value;
}
ComponentVersion TypeDescriptionReader::readNumericVersionBinding(UiScriptBinding *ast)
{
ComponentVersion invalidVersion;
if (!ast || !ast->statement) {
addError(ast->colonToken, "Expected numeric literal after colon");
return invalidVersion;
}
ExpressionStatement *expStmt = AST::cast<ExpressionStatement *>(ast->statement);
if (!expStmt) {
addError(ast->statement->firstSourceLocation(), "Expected numeric literal after colon");
return invalidVersion;
}
NumericLiteral *numericLit = AST::cast<NumericLiteral *>(expStmt->expression);
if (!numericLit) {
addError(expStmt->firstSourceLocation(), "Expected numeric literal after colon");
return invalidVersion;
}
return ComponentVersion(_source.mid(numericLit->literalToken.begin(), numericLit->literalToken.length));
}
int TypeDescriptionReader::readIntBinding(AST::UiScriptBinding *ast)
{
double v = readNumericBinding(ast);

View File

@@ -34,6 +34,8 @@
#define QMLJSTYPEDESCRIPTIONREADER_H
#include <languageutils/fakemetaobject.h>
#include <languageutils/componentversion.h>
#include "qmljsdocument.h"
// for Q_DECLARE_TR_FUNCTIONS
#include <QtCore/QCoreApplication>
@@ -60,7 +62,9 @@ public:
explicit TypeDescriptionReader(const QString &data);
~TypeDescriptionReader();
bool operator()(QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects);
bool operator()(
QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *objects,
QList<ModuleApiInfo> *moduleApis);
QString errorMessage() const;
QString warningMessage() const;
@@ -68,6 +72,7 @@ private:
void readDocument(AST::UiProgram *ast);
void readModule(AST::UiObjectDefinition *ast);
void readComponent(AST::UiObjectDefinition *ast);
void readModuleApi(AST::UiObjectDefinition *ast);
void readSignalOrMethod(AST::UiObjectDefinition *ast, bool isMethod, LanguageUtils::FakeMetaObject::Ptr fmo);
void readProperty(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
void readEnum(AST::UiObjectDefinition *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
@@ -76,6 +81,7 @@ private:
QString readStringBinding(AST::UiScriptBinding *ast);
bool readBoolBinding(AST::UiScriptBinding *ast);
double readNumericBinding(AST::UiScriptBinding *ast);
LanguageUtils::ComponentVersion readNumericVersionBinding(AST::UiScriptBinding *ast);
int readIntBinding(AST::UiScriptBinding *ast);
void readExports(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
void readMetaObjectRevisions(AST::UiScriptBinding *ast, LanguageUtils::FakeMetaObject::Ptr fmo);
@@ -88,6 +94,7 @@ private:
QString _errorMessage;
QString _warningMessage;
QHash<QString, LanguageUtils::FakeMetaObject::ConstPtr> *_objects;
QList<ModuleApiInfo> *_moduleApis;
};
} // namespace QmlJS