diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,10 +10,10 @@ # QMLJSC set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) -set(CMAKE_CXX_FLAGS "-std=c++0x") +set(CMAKE_CXX_FLAGS "-std=c++14") find_package(Qt5 COMPONENTS Core) # Components of qmlweb add_subdirectory(src/qmljsc) -add_subdirectory(tests/auto/qmljsc) \ No newline at end of file +add_subdirectory(tests/auto/qmljsc) diff --git a/src/qmljsc/CMakeLists.txt b/src/qmljsc/CMakeLists.txt --- a/src/qmljsc/CMakeLists.txt +++ b/src/qmljsc/CMakeLists.txt @@ -4,7 +4,6 @@ compiler.cpp compilerpipeline.cpp compilerpass.cpp - purejavascriptgenerator.cpp ir/objecttree.cpp ir/module.cpp @@ -21,6 +20,9 @@ moduleloading/javascriptmoduleloader.cpp moduleloading/qtqmlmoduleloader.cpp + codegeneration/purejavascriptgenerator.cpp + codegeneration/codegeneratorforqml.cpp + utils/error.cpp utils/shortsymbolname.cpp ) diff --git a/src/qmljsc/codegeneration/codegeneratorforqml.h b/src/qmljsc/codegeneration/codegeneratorforqml.h new file mode 100644 --- /dev/null +++ b/src/qmljsc/codegeneration/codegeneratorforqml.h @@ -0,0 +1,58 @@ +/* + * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. + * + * Copyright (C) 2015 Jan Marker + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef QMLWEB_CODEGENERATORPASS_H +#define QMLWEB_CODEGENERATORPASS_H + +#include + +#include "../compilerpass.h" +#include "../ir/visitor.h" + +namespace QmlJSc { + +class PureJavaScriptGenerator; + +class CodeGeneratorForQml : IR::Visitor { +public: + explicit CodeGeneratorForQml(); + virtual ~CodeGeneratorForQml(); + + QString getGeneratedCode(); + + void endVisit(IR::File *file) override; + void endVisit(IR::Import *import) override; + void endVisit(IR::ObjectSpec *object) override; + void endVisit(IR::Property *property) override; + void endVisit(IR::Method *method) override; + void endVisit(IR::Signal *signal) override; + void endVisit(IR::ValueAssignment *valueAssignment) override; + void endVisit(IR::SignalHandler *signalHandler) override; + +private: + friend class TestCodeGeneratorForQml; + + PureJavaScriptGenerator *m_jsGenerator; + QStack m_outputStack; +}; + +} // namespace QmlJSc + +#endif //QMLWEB_CODEGENERATORPASS_H diff --git a/src/qmljsc/codegeneration/codegeneratorforqml.cpp b/src/qmljsc/codegeneration/codegeneratorforqml.cpp new file mode 100644 --- /dev/null +++ b/src/qmljsc/codegeneration/codegeneratorforqml.cpp @@ -0,0 +1,185 @@ +/* + * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. + * + * Copyright (C) 2015 Jan Marker + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "codegeneratorforqml.h" +#include "../utils/error.h" +#include "../ir/file.h" +#include "../ir/module.h" +#include "purejavascriptgenerator.h" + +using namespace QmlJSc; + +static const char16_t fileTemplate[] = u"{$class:\"Component\",$children:[%1],$imports:[%2]}"; +static const char16_t importTemplate[] = u"[\"qmlimport\",\"%1\",%2.%3,\"%4\",true]"; +static const char16_t objectSpecTemplate[] = u"{__proto__:QMLMetaElement.prototype,$class:\"%1\"%2}"; //FIXME: Don't use non-standard __proto__ +static const char16_t propertyTemplate[] = u"%1: new QMLPropertyDefinition(\"%2\")"; +static const char16_t methodTemplate[] = u"%1: new QMLMethod(\"%2\")"; +static const char16_t signalTemplate[] = u"%1: new QMLSignalDefinition([%2])"; +static const char16_t signalParameterTemplate[] = u"{name:\"%1\",type:\"%2\"},"; +static const char16_t signalHandlerTemplate[] = u"on%1: new QmlBinding(\"%2\")"; +static const char16_t jsValueAssignmentTemplate[] = u"%1: %2"; +static const char16_t objectAssignmentTemplate[] = u"%1: %2"; +static const char16_t objectListAssignmentTemplate[] = u"%1: [%2]"; +static const char16_t bindingTemplate[] = u"%1: new QmlBinding(\"%2\")"; + +CodeGeneratorForQml::CodeGeneratorForQml() + : IR::Visitor() + , m_jsGenerator(new PureJavaScriptGenerator) +{ +} + +QmlJSc::CodeGeneratorForQml::~CodeGeneratorForQml() +{ +} + +QString CodeGeneratorForQml::getGeneratedCode() +{ + if (m_outputStack.size() == 0) { + return QString(); + } + if (m_outputStack.size() != 1) { + const QString errorDescription = QStringLiteral("Stack was not reduced correctly, top element is %1").arg(m_outputStack.top()); + Error *stackError = new Error(Error::InternalError, errorDescription); + throw stackError; + } + return m_outputStack.pop(); +} + +void CodeGeneratorForQml::endVisit(IR::File *file) +{ + QString rootObjCode = m_outputStack.pop(); + QString importsCode; + if (file->importedModules().size()) { + for (const IR::Import &data: file->importedModules()) { + importsCode += m_outputStack.pop() + ','; + } + importsCode.remove(-1, 1); // remove last comma + } + + m_outputStack.push(QString::fromUtf16(fileTemplate).arg(rootObjCode, importsCode)); +} + +void QmlJSc::CodeGeneratorForQml::endVisit(IR::Import* import) +{ + m_outputStack.push(QString::fromUtf16(importTemplate).arg(import->module()->name()) + .arg(import->module()->versionMajor()) + .arg(import->module()->versionMinor()) + .arg(import->localPrefix())); +} + +void CodeGeneratorForQml::endVisit(IR::ObjectSpec *object) +{ + QString code; + int listSize = object->ownPropertiesSize() + + object->ownMethodsSize() + + object->ownSignalsSize() + + object->valueAssignments().size() + + object->signalHandlers().size(); + QStack::iterator positionOnStack = m_outputStack.end(); + positionOnStack -= listSize; + for (; positionOnStack != m_outputStack.end(); positionOnStack++) { + code += ',' + *positionOnStack; // We know QStack is actually just a QVector, + // so we can just access random items in constant time + } + m_outputStack.erase(m_outputStack.end() - listSize, m_outputStack.end()); + + m_outputStack.push(QString::fromUtf16(objectSpecTemplate).arg(object->super()->name(), code)); +} + +void CodeGeneratorForQml::endVisit(IR::Property* property) +{ + m_outputStack.push(QString::fromUtf16(propertyTemplate) + .arg(property->name, property->type->name())); +} + +void CodeGeneratorForQml::endVisit(IR::Method* method) +{ + if (method->body) { + Q_ASSERT(method->body->elements); + method->body->elements->accept(m_jsGenerator); + } + m_outputStack.push(QString::fromUtf16(methodTemplate) + .arg(method->name, method->body ? m_jsGenerator->getGeneratedCode() : QString())); +} + +void CodeGeneratorForQml::endVisit(IR::Signal* signal) +{ + QString parameters; + if (!signal->parameters.isEmpty()) { + for (const IR::Parameter ¶meter : signal->parameters) { + parameters += QString::fromUtf16(signalParameterTemplate) + .arg(parameter.name, parameter.type->name()); + } + parameters.remove(-1, 1); // remove last comma + } + m_outputStack.push(QString::fromUtf16(signalTemplate) + .arg(signal->name, parameters)); +} + +void CodeGeneratorForQml::endVisit(IR::ValueAssignment* valueAssignment) +{ + //FIXME: We should split ValueAssignment into subclasses. This is not how the + // visitor pattern is supposed to look like. + switch (valueAssignment->assignmentType()) { + case IR::ValueAssignment::JsAssignment: + valueAssignment->jsValue()->accept(m_jsGenerator); + m_outputStack.push(QString::fromUtf16(jsValueAssignmentTemplate) + .arg(valueAssignment->property()->name, m_jsGenerator->getGeneratedCode())); + break; + case IR::ValueAssignment::ObjectAssignment: + m_outputStack.push(QString::fromUtf16(objectAssignmentTemplate) + .arg(valueAssignment->property()->name, m_outputStack.pop())); + break; + case IR::ValueAssignment::ObjectList: + { + QString listCode; + int listSize = valueAssignment->objectList()->size(); + if (listSize) { + QStack::iterator positionOnStack = m_outputStack.end(); + positionOnStack -= listSize; + for (; positionOnStack != m_outputStack.end(); positionOnStack++) { + listCode += *positionOnStack + ','; // We know QStack is actually just a QVector, + // so we can just access random items in constant time + } + listCode.remove(-1, 1); + } + m_outputStack.erase(m_outputStack.end() - listSize, m_outputStack.end()); + m_outputStack.push(QString::fromUtf16(objectListAssignmentTemplate) + .arg(valueAssignment->property()->name, listCode)); + break; + } + case IR::ValueAssignment::Binding: + valueAssignment->bindingCode()->accept(m_jsGenerator); + m_outputStack.push(QString::fromUtf16(bindingTemplate) + .arg(valueAssignment->property()->name, m_jsGenerator->getGeneratedCode())); + break; + default: + throw new Error(Error::InternalError, + QStringLiteral("We have an invalid value assignment here. This should not happen.")); + } +} + +void CodeGeneratorForQml::endVisit(IR::SignalHandler* signalHandler) +{ + QString signalName = signalHandler->signal()->name; + *signalName.begin() = signalName.begin()->toUpper(); + signalHandler->handlerCode()->accept(m_jsGenerator); + m_outputStack.push(QString::fromUtf16(signalHandlerTemplate).arg(signalName, m_jsGenerator->getGeneratedCode())); +} diff --git a/src/qmljsc/purejavascriptgenerator.h b/src/qmljsc/codegeneration/purejavascriptgenerator.h rename from src/qmljsc/purejavascriptgenerator.h rename to src/qmljsc/codegeneration/purejavascriptgenerator.h --- a/src/qmljsc/purejavascriptgenerator.h +++ b/src/qmljsc/codegeneration/purejavascriptgenerator.h @@ -26,6 +26,8 @@ #include #include +namespace QmlJSc { + class PureJavaScriptGenerator : public QQmlJS::AST::Visitor { public: @@ -137,4 +139,6 @@ m_outputStack << code; } +} // namespace QmlJSc + #endif //QMLWEB_PUREJAVASCRIPTGENERATOR_H diff --git a/src/qmljsc/purejavascriptgenerator.cpp b/src/qmljsc/codegeneration/purejavascriptgenerator.cpp rename from src/qmljsc/purejavascriptgenerator.cpp rename to src/qmljsc/codegeneration/purejavascriptgenerator.cpp --- a/src/qmljsc/purejavascriptgenerator.cpp +++ b/src/qmljsc/codegeneration/purejavascriptgenerator.cpp @@ -23,20 +23,22 @@ #include "purejavascriptgenerator.h" #include "utils/error.h" +using namespace QmlJSc; using namespace QQmlJS; PureJavaScriptGenerator::PureJavaScriptGenerator() : m_outputStack() { } QString PureJavaScriptGenerator::getGeneratedCode() { - if (m_outputStack.size() > 1) { + if (m_outputStack.size() == 0) { + return QString(); + } + if (m_outputStack.size() != 1) { const QString errorDescription = QString("stack was not reduced correctly, top element is %1").arg(m_outputStack.top()); - QmlJSc::Error stackError(QmlJSc::Error::InternalError, errorDescription); + Error *stackError = new Error(Error::InternalError, errorDescription); throw stackError; - } else if (m_outputStack.size() == 0) { - return ""; } return m_outputStack.pop(); } @@ -570,4 +572,4 @@ labelStatementCode.append(label.toString()); } m_outputStack << labelStatementCode + ';'; -} \ No newline at end of file +} diff --git a/src/qmljsc/compilerpass.h b/src/qmljsc/compilerpass.h --- a/src/qmljsc/compilerpass.h +++ b/src/qmljsc/compilerpass.h @@ -18,8 +18,8 @@ * */ -#ifndef PIPELINESTAGE_H -#define PIPELINESTAGE_H +#ifndef COMPILERPASS_H +#define COMPILERPASS_H #include #include @@ -60,4 +60,4 @@ } -#endif // PIPELINESTAGE_H +#endif // COMPILERPASS_H diff --git a/src/qmljsc/compilerpasses/asttoirpass.cpp b/src/qmljsc/compilerpasses/asttoirpass.cpp --- a/src/qmljsc/compilerpasses/asttoirpass.cpp +++ b/src/qmljsc/compilerpasses/asttoirpass.cpp @@ -55,26 +55,26 @@ bool AstToIRPass::visit(QQmlJS::AST::UiImport *import) { Q_ASSERT(import); - IR::ImportDescription desc; + QString name; + int versionMajor; + int versionMinor; if (!import->fileName.isEmpty()) { // TODO: Decide between directory and file import - desc.kind = IR::ImportDescription::Kind_FileImport; - desc.name = import->fileName.toString(); + name = import->fileName.toString(); } else if (import->importUri && !import->importUri->name.isEmpty()) { - desc.kind = IR::ImportDescription::Kind_ModuleImport; QQmlJS::AST::UiQualifiedId *id = import->importUri; - desc.name = id->name.toString(); + name = id->name.toString(); while ((id = id->next)){ - desc.name += "."; - desc.name += id->name; + name += "."; + name += id->name; } QStringRef versionRef(import->importUri->name.string(), import->versionToken.offset, import->versionToken.length); - QmlIR::IRBuilder::extractVersion(versionRef, &desc.versionMajor, &desc.versionMinor); + QmlIR::IRBuilder::extractVersion(versionRef, &versionMajor, &versionMinor); IR::Module *module = 0; try { - module = ModuleLoading::loadModule(desc); + module = ModuleLoading::loadModule(name, versionMajor, versionMinor); } catch (Error *error) { QQmlJS::AST::SourceLocation token = import->fileNameToken; error->setLine(token.startLine); diff --git a/src/qmljsc/ir/file.h b/src/qmljsc/ir/file.h --- a/src/qmljsc/ir/file.h +++ b/src/qmljsc/ir/file.h @@ -22,32 +22,59 @@ #define FILE_H #include "objecttree.h" -#include "importdefinition.h" #include "../utils/shortsymbolname.h" #include #include #include #include #include +#include namespace QmlJSc { namespace IR { class Module; class Type; -class File : public Node +class Import : public Node { public: - struct ModuleData { - Module *module; - QString localPrefix; - - bool operator==(const ModuleData &other) const; + enum ImportType { + Invalid, + ModuleImport, + FileImport, + DirectoryImport }; - explicit File(); + Import(); + Import(const Import &other); + Import(Module *module, const QString &localPrefix = QString()); + Import(const QUrl &url, const QString &localPrefix= QString()); + + bool operator==(const Import &other) const; + + ImportType importType() const; + Module *module() const; + QUrl filePath() const; + const QString &localPrefix() const; + + virtual Kind kind() const override; + virtual void accept(Visitor * visitor) override; + +private: + ImportType m_importType; + Module *m_module; + QUrl m_filePath; // for file and directory imports + QString m_localPrefix; // import [...] as +}; + +class File : public Node +{ +public: + + File(); + File(std::initializer_list imports, ObjectSpec *rootObject); virtual ~File(); virtual Node::Kind kind() const override; @@ -62,12 +89,12 @@ virtual void accept(Visitor * visitor) override; - const QVector &importedModules() const; + const QVector &importedModules() const; private: - const ModuleData *moduleForType(const QString &typeName) const; + const Import *moduleForType(const QString &typeName) const; - QVector m_importedModules; + QVector m_importedModules; ShortSymbolName m_prefix; ObjectSpec *m_rootObject; }; diff --git a/src/qmljsc/ir/file.cpp b/src/qmljsc/ir/file.cpp --- a/src/qmljsc/ir/file.cpp +++ b/src/qmljsc/ir/file.cpp @@ -28,16 +28,86 @@ using namespace QmlJSc; using namespace QmlJSc::IR; -bool File::ModuleData::operator==(const File::ModuleData& other) const +Import::Import(const QUrl& url, const QString& localPrefix) + : m_filePath(url) + , m_module(0) + , m_localPrefix(localPrefix) { - return module == other.module; + m_importType = FileImport; //TODO: Decide between file and directory import +} + +Import::Import(Module* module, const QString& localPrefix) + : m_importType(ModuleImport) + , m_module(module) + , m_localPrefix(localPrefix) +{ +} + +QmlJSc::IR::Import::Import() + : m_importType(Invalid) + , m_module(0) +{ +} + +QmlJSc::IR::Import::Import(const QmlJSc::IR::Import& other) + : m_importType(other.importType()) + , m_module(other.module()) + , m_filePath(other.filePath()) + , m_localPrefix(other.localPrefix()) +{ +} + +bool QmlJSc::IR::Import::operator==(const QmlJSc::IR::Import& other) const +{ + return m_importType == other.importType() + && m_module == other.module() + && m_filePath == other.filePath() + && m_importType == other.importType(); +} + +void Import::accept(Visitor* visitor) +{ + visitor->visit(this); + visitor->endVisit(this); +} + +Node::Kind Import::kind() const +{ + return Kind_Import; +} + +Module * Import::module() const +{ + return m_module; +} + +QUrl Import::filePath() const +{ + return m_filePath; +} + +Import::ImportType Import::importType() const +{ + return m_importType; +} + +const QString &Import::localPrefix() const +{ + return m_localPrefix; } File::File() : m_prefix('A' - 1) // we want the prefix to be 'A' after the first preincrement { } +File::File(std::initializer_list imports, ObjectSpec *rootObject) + : m_importedModules(imports) + , m_prefix('A' - 1) + , m_rootObject(rootObject) +{ +} + File::~File() { } @@ -49,34 +119,28 @@ void File::addModule(Module *module, const QString &prefix) { - if (m_importedModules.contains({ module, QString() })) + if (m_importedModules.contains({ module })) return; - ModuleData moduleData; - moduleData.module = module; - if (!prefix.isEmpty()) { - moduleData.localPrefix = prefix; - } else { - moduleData.localPrefix = ++m_prefix; - } - m_importedModules.append(moduleData); + Import import(module, prefix.isEmpty() ? ++m_prefix : prefix); + m_importedModules.append(import); } Type *File::type(const QString &typeName) const { if (Type *builtinType = IR::BuiltinTypes::type(typeName)) { return builtinType; } - const ModuleData *data = moduleForType(typeName); - if (data && data->module) - return data->module->type(typeName); + const Import *data = moduleForType(typeName); + if (data && data->module()) + return data->module()->type(typeName); return 0; } QString File::fullyQualifiedName(const QString &typeName) { - return QStringLiteral("%1.%2").arg(moduleForType(typeName)->localPrefix, typeName); + return QStringLiteral("%1.%2").arg(moduleForType(typeName)->localPrefix(), typeName); } ObjectSpec *File::rootObject() const @@ -89,17 +153,17 @@ m_rootObject = rootObject; } -const File::ModuleData *File::moduleForType(const QString &typeName) const +const Import *File::moduleForType(const QString &typeName) const { Type *foundType = 0; - const ModuleData *moduleData = 0; - foreach (const ModuleData &data, m_importedModules) { - if (Type * type = data.module->type(typeName)) { + const Import *moduleData = 0; + foreach (const Import &data, m_importedModules) { + if (Type * type = data.module()->type(typeName)) { if (foundType) { throw Error( QmlJSc::Error::SymbolLookupError, QString("Ambigious type name. Type %1 was defined by module %2 and %3.") - .arg(typeName, moduleData->module->name(), data.module->name()) + .arg(typeName, moduleData->module()->name(), data.module()->name()) ); return 0; } else { @@ -114,11 +178,14 @@ void QmlJSc::IR::File::accept(QmlJSc::IR::Visitor* visitor) { visitor->visit(this); + for (Import &import : m_importedModules) { + import.accept(visitor); + } m_rootObject->accept(visitor); visitor->endVisit(this); } -const QVector &File::importedModules() const +const QVector &File::importedModules() const { return m_importedModules; } diff --git a/src/qmljsc/ir/importdefinition.h b/src/qmljsc/ir/importdefinition.h deleted file mode 100644 --- a/src/qmljsc/ir/importdefinition.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. - * - * Copyright (C) 2015 Anton Kreuzkamp - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -#ifndef IMPORTDESCRIPTION_H -#define IMPORTDESCRIPTION_H - -#include -#include - -namespace QmlJSc { -namespace IR { - -struct ImportDescription { - enum Kind { - Kind_ModuleImport, - Kind_FileImport, - Kind_DirectoryImport - }; - - Kind kind; - QString name; - int versionMajor; - int versionMinor; - - inline bool operator==(const ImportDescription& other) const - { - return name == other.name && versionMajor == other.versionMajor && versionMinor == other.versionMinor; - } -}; - -inline uint qHash(const ImportDescription &key, uint seed) -{ - return qHash(key.name, seed) ^ key.versionMajor ^ key.versionMinor; -} - -} // namespace IR -} // namespace QmlJSc - -Q_DECLARE_METATYPE(QmlJSc::IR::ImportDescription); - -#endif // IMPORTDESCRIPTION_H - diff --git a/src/qmljsc/ir/module.h b/src/qmljsc/ir/module.h --- a/src/qmljsc/ir/module.h +++ b/src/qmljsc/ir/module.h @@ -45,7 +45,7 @@ ErrorState }; - explicit Module(ImportDescription import, QObject *parent = 0); + explicit Module(QString name, int versionMajor, int versionMinor, QObject *parent = 0); ~Module(); LoadingState loadingState(); @@ -69,16 +69,18 @@ */ Type *typeFromJSName(QString name); - const QString &name(); + const QString &name() const; + int versionMajor() const; + int versionMinor() const; void addType(Type *type); - ImportDescription importDescription(); - private: + QString m_name; + int m_versionMajor; + int m_versionMinor; QHash m_types; QHash m_jsNameToTypeHash; - ImportDescription m_importDescription; LoadingState m_loadingState; QWaitCondition m_loadFinishedCondition; QMutex m_loadMutex; diff --git a/src/qmljsc/ir/module.cpp b/src/qmljsc/ir/module.cpp --- a/src/qmljsc/ir/module.cpp +++ b/src/qmljsc/ir/module.cpp @@ -38,8 +38,10 @@ using namespace QmlJSc::IR; using namespace QQmlJS::AST; -Module::Module(ImportDescription import, QObject *parent) - : m_importDescription(import) +Module::Module(QString name, int versionMajor, int versionMinor, QObject *parent) + : m_name(name) + , m_versionMajor(versionMajor) + , m_versionMinor(versionMinor) , m_loadingState(Loading) { } @@ -68,9 +70,19 @@ } -const QString &Module::name() +const QString &Module::name() const { - return m_importDescription.name; + return m_name; +} + +int QmlJSc::IR::Module::versionMajor() const +{ + return m_versionMajor; +} + +int QmlJSc::IR::Module::versionMinor() const +{ + return m_versionMinor; } Type *Module::type(QString name) @@ -102,8 +114,3 @@ m_loadFinishedCondition.wait(&m_loadMutex); m_loadMutex.unlock(); } - -ImportDescription Module::importDescription() -{ - return m_importDescription; -} diff --git a/src/qmljsc/ir/objecttree.h b/src/qmljsc/ir/objecttree.h --- a/src/qmljsc/ir/objecttree.h +++ b/src/qmljsc/ir/objecttree.h @@ -49,7 +49,8 @@ Kind_ValueAssignment, Kind_SignalHandler, Kind_ObjectSpec, - Kind_File + Kind_File, + Kind_Import }; virtual void accept(Visitor *visitor) = 0; virtual Kind kind() const = 0; @@ -79,6 +80,9 @@ }; ValueAssignment(Property *property = 0); + ValueAssignment(Property *property, QQmlJS::AST::Statement *statement, AssignmentType type); + ValueAssignment(Property *property, ObjectSpec *obj); + ValueAssignment(Property *property, std::initializer_list< QmlJSc::IR::ObjectSpec *> objList); virtual ~ValueAssignment(); virtual Node::Kind kind() const override; diff --git a/src/qmljsc/ir/objecttree.cpp b/src/qmljsc/ir/objecttree.cpp --- a/src/qmljsc/ir/objecttree.cpp +++ b/src/qmljsc/ir/objecttree.cpp @@ -33,6 +33,27 @@ { } +ValueAssignment::ValueAssignment(Property* property, ObjectSpec* obj) + : m_property(property) + , m_assignmentType(ObjectAssignment) + , m_objectValue(obj) +{ +} + +ValueAssignment::ValueAssignment(Property* property, QQmlJS::AST::Statement* statement, AssignmentType type) + : m_property(property) + , m_assignmentType(type) + , m_jsValue(statement) // sets m_bindingCode as well (union) +{ +} + +ValueAssignment::ValueAssignment(Property* property, std::initializer_list objList) + : m_property(property) + , m_assignmentType(ObjectList) + , m_objectList(new QVector(objList)) +{ +} + ValueAssignment::~ValueAssignment() { if (m_assignmentType == ObjectList) { @@ -282,15 +303,26 @@ visitor->endVisit(this); } -void ObjectSpec::visitChildren(Visitor *visitor) { +void ObjectSpec::visitChildren(Visitor *visitor) +{ + for (auto i = m_properties.begin(); i != m_properties.end(); i++) { + i->accept(visitor); + } + + for (auto i = m_methods.begin(); i != m_methods.end(); i++) { + i->accept(visitor); + } + + for (auto i = m_signals.begin(); i != m_signals.end(); i++) { + i->accept(visitor); + } for (auto i = m_signalHandlers.begin(); i != m_signalHandlers.end(); i++) { i->accept(visitor); } for (auto i = m_valueAssignments.begin(); i != m_valueAssignments.end(); i++) { i->accept(visitor); } - } diff --git a/src/qmljsc/ir/typesystem.h b/src/qmljsc/ir/typesystem.h --- a/src/qmljsc/ir/typesystem.h +++ b/src/qmljsc/ir/typesystem.h @@ -39,6 +39,7 @@ class Property; class Method; class Signal; +class Visitor; /** * This class provides API representing Qml.js objects and types and allows to @@ -88,6 +89,22 @@ Property *defaultProperty(); void setDefaultProperty(Property *); + /** + * Returns the number of properties that are declared for this object spec, + * not considering properties that were inherited from super types. + */ + int ownPropertiesSize() const; + /** + * Returns the number of methods that are declared for this object spec, + * not considering methods that were inherited from super types. + */ + int ownMethodsSize() const; + /** + * Returns the number of signals that are declared for this object spec, + * not considering signals that were inherited from super types. + */ + int ownSignalsSize() const; + protected: QString m_name; QString m_javaScriptName; @@ -115,9 +132,11 @@ class Method { public: Method(); - Method(const QString &name); + Method(const QString &name, QQmlJS::AST::FunctionBody *body = 0); Method(Type *returnType, QString name); + void accept(Visitor *visitor); + Type *returnType; QString name; QVector parameters; @@ -127,7 +146,10 @@ class Signal { public: Signal(); - Signal(QString name); + Signal(const QString &name); + Signal(const QString &name, std::initializer_list params); + + void accept(Visitor *visitor); QString name; QVector parameters; @@ -139,6 +161,8 @@ Property(const QString &name); Property(Type *type, QString name); + void accept(Visitor *visitor); + Type *type; QString name; diff --git a/src/qmljsc/ir/typesystem.cpp b/src/qmljsc/ir/typesystem.cpp --- a/src/qmljsc/ir/typesystem.cpp +++ b/src/qmljsc/ir/typesystem.cpp @@ -20,6 +20,7 @@ */ #include "typesystem.h" +#include "visitor.h" using namespace QmlJSc::IR; @@ -119,6 +120,20 @@ return 0; } +int QmlJSc::IR::Type::ownMethodsSize() const +{ + return m_methods.size(); +} + +int QmlJSc::IR::Type::ownPropertiesSize() const +{ + return m_properties.size(); +} + +int QmlJSc::IR::Type::ownSignalsSize() const +{ + return m_signals.size(); +} bool Type::hasMember(const QString &name) { @@ -171,9 +186,9 @@ { } -Method::Method(const QString &name) - : returnType(0) - , name(name) +QmlJSc::IR::Method::Method(const QString &name_, QQmlJS::AST::FunctionBody *body_) + : name(name_) + , body(body_) { } @@ -183,15 +198,33 @@ { } +void Method::accept(Visitor *visitor) +{ + visitor->visit(this); + visitor->endVisit(this); +} + Signal::Signal() { } -Signal::Signal(QString name) +Signal::Signal(const QString &name) : name(name) { } +Signal::Signal(const QString& name_, std::initializer_list params) + : name(name_) + , parameters(params) +{ +} + +void Signal::accept(Visitor *visitor) +{ + visitor->visit(this); + visitor->endVisit(this); +} + Property::Property() : type(0) { @@ -208,3 +241,9 @@ , name(name) { } + +void Property::accept(Visitor *visitor) +{ + visitor->visit(this); + visitor->endVisit(this); +} diff --git a/src/qmljsc/ir/visitor.h b/src/qmljsc/ir/visitor.h --- a/src/qmljsc/ir/visitor.h +++ b/src/qmljsc/ir/visitor.h @@ -28,6 +28,7 @@ class Node; class File; +class Import; class ObjectSpec; class ValueAssignment; class BindingAssignment; @@ -41,12 +42,20 @@ public: virtual void visit(File *file) {} + virtual void visit(Import *import) {} virtual void visit(ObjectSpec *object) {} + virtual void visit(Property *property) {} + virtual void visit(Method *method) {} + virtual void visit(Signal *signal) {} virtual void visit(ValueAssignment *valueAssignment) {} virtual void visit(SignalHandler *signalHandler) {} virtual void endVisit(File *file) {} + virtual void endVisit(Import *import) {} virtual void endVisit(ObjectSpec *object) {} + virtual void endVisit(Property *property) {} + virtual void endVisit(Method *method) {} + virtual void endVisit(Signal *signal) {} virtual void endVisit(ValueAssignment *valueAssignment) {} virtual void endVisit(SignalHandler *signalHandler) {} }; diff --git a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp --- a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp +++ b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp @@ -440,9 +440,10 @@ { IR::Module *module = AbstractModuleLoader::module(); - QString moduleFileName = QStringLiteral("%1.%2.%3.js").arg(module->importDescription().name) - .arg(module->importDescription().versionMajor) - .arg(module->importDescription().versionMinor); + QString moduleFileName = QString("%1.%2.%3.js"); + moduleFileName = moduleFileName.arg(module->name()); + moduleFileName = moduleFileName.arg(module->versionMajor()); + moduleFileName = moduleFileName.arg(module->versionMinor()); // For now we only support local files. const QStringList &includePaths = compiler->includePaths(); @@ -492,9 +493,9 @@ err->setLine(parser->errorLineNumber()); throw new Error(Error::ModuleImportError, QStringLiteral("Error while processing module %1 %2.%3") - .arg(module->importDescription().name) - .arg(module->importDescription().versionMajor) - .arg(module->importDescription().versionMinor), + .arg(module->name()) + .arg(module->versionMajor()) + .arg(module->versionMinor()), err); } diff --git a/src/qmljsc/moduleloading/moduleloading.h b/src/qmljsc/moduleloading/moduleloading.h --- a/src/qmljsc/moduleloading/moduleloading.h +++ b/src/qmljsc/moduleloading/moduleloading.h @@ -50,12 +50,12 @@ * * This function is to be called from the compile-unit thread. */ - static IR::Module *loadModule(IR::ImportDescription import); + static IR::Module *loadModule(QString name, int versionMajor, int versionMinor); static void registerModuleLoader(ModuleLoaderFactoryFunc factory); private: - static QHash s_loadedModules; + static QHash s_loadedModules; static QVector s_moduleLoaderFactories; }; diff --git a/src/qmljsc/moduleloading/moduleloading.cpp b/src/qmljsc/moduleloading/moduleloading.cpp --- a/src/qmljsc/moduleloading/moduleloading.cpp +++ b/src/qmljsc/moduleloading/moduleloading.cpp @@ -46,18 +46,18 @@ using namespace QmlJSc; using namespace QQmlJS; -QHash ModuleLoading::s_loadedModules; +QHash ModuleLoading::s_loadedModules; QVector ModuleLoading::s_moduleLoaderFactories; -IR::Module *ModuleLoading::loadModule(IR::ImportDescription import) +IR::Module *ModuleLoading::loadModule(QString name, int versionMajor, int versionMinor) { - Q_ASSERT(import.kind == IR::ImportDescription::Kind_ModuleImport); - if (IR::Module *module = s_loadedModules.value(import)) { + QString hashKey = QString("%1.%2.%3").arg(name).arg(versionMajor).arg(versionMinor); + if (IR::Module *module = s_loadedModules.value(hashKey)) { return module; } - IR::Module *module = new IR::Module(import, compiler); - s_loadedModules.insert(import, module); + IR::Module *module = new IR::Module(name, versionMajor, versionMinor, compiler); + s_loadedModules.insert(hashKey, module); AbstractModuleLoader *loader = 0; foreach (ModuleLoaderFactoryFunc createLoaderFor, s_moduleLoaderFactories) { loader = createLoaderFor(module); // will delete itself when done @@ -71,7 +71,7 @@ if (!loader) { throw new Error(Error::ModuleImportError, QStringLiteral("Module %1 %2.%3 was not " - "found. Check version and include paths.").arg(import.name).arg(import.versionMajor).arg(import.versionMinor)); + "found. Check version and include paths.").arg(name).arg(versionMajor).arg(versionMinor)); } QThreadPool::globalInstance()->start(loader); diff --git a/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp b/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp --- a/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp +++ b/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp @@ -38,7 +38,7 @@ bool QmlJSc::QtQmlModuleLoader::canLoad() { - return module()->importDescription().name == "QtQml"; + return module()->name() == "QtQml"; } void QtQmlModuleLoader::doLoad() diff --git a/tests/auto/qmljsc/CMakeLists.txt b/tests/auto/qmljsc/CMakeLists.txt --- a/tests/auto/qmljsc/CMakeLists.txt +++ b/tests/auto/qmljsc/CMakeLists.txt @@ -27,3 +27,4 @@ new_test(TEST testpurejavascriptgenerator) new_test(TEST testpurejavascriptgenerator_integration RESOURCES ../data/javascript/) new_test(TEST testasttoir RESOURCES ../data/testasttoir/qtquick-import.qml) +new_test(TEST testcodegeneratorforqml) diff --git a/tests/auto/qmljsc/testasttoir.cpp b/tests/auto/qmljsc/testasttoir.cpp --- a/tests/auto/qmljsc/testasttoir.cpp +++ b/tests/auto/qmljsc/testasttoir.cpp @@ -54,18 +54,18 @@ bool canLoad() override { if (module()->name() == "QtQuick" - && module()->importDescription().versionMajor == 2 - && module()->importDescription().versionMinor <= 1) { + && module()->versionMajor() == 2 + && module()->versionMinor() <= 1) { return true; } if (module()->name() == "QtQuick.Controls" - && module()->importDescription().versionMajor == 1 - && module()->importDescription().versionMinor <= 3) { + && module()->versionMajor() == 1 + && module()->versionMinor() <= 3) { return true; } if (module()->name() == "IExistInVersionTwoOne" - && module()->importDescription().versionMajor == 2 - && module()->importDescription().versionMinor <= 1) { + && module()->versionMajor() == 2 + && module()->versionMinor() <= 1) { return true; } return false; @@ -138,7 +138,7 @@ : QObject() , m_lexer(&m_engine) , m_parser(&m_engine) - , m_pizzaModule({IR::ImportDescription::Kind_ModuleImport, "Pizzeria", 1, 0}) + , m_pizzaModule("Pizzeria", 1, 0) { ModuleLoading::registerModuleLoader(&MockModuleLoader::create); @@ -226,13 +226,13 @@ m_parser.parse(); AST::cast(m_parser.rootNode())->headers->headerItem->accept(&m_pass); - const QVector &importedModules = m_pass.m_file->importedModules(); + const QVector &importedModules = m_pass.m_file->importedModules(); QCOMPARE(importedModules.count(), 1); - QVERIFY(importedModules.first().module); - QCOMPARE(importedModules.first().module->name(), moduleName); - QCOMPARE(importedModules.first().module->importDescription().versionMajor, majorVersion); - QCOMPARE(importedModules.first().module->importDescription().versionMinor, minorVersion); - QCOMPARE(importedModules.first().localPrefix, prefix); + QVERIFY(importedModules.first().module()); + QCOMPARE(importedModules.first().module()->name(), moduleName); + QCOMPARE(importedModules.first().module()->versionMajor(), majorVersion); + QCOMPARE(importedModules.first().module()->versionMinor(), minorVersion); + QCOMPARE(importedModules.first().localPrefix(), prefix); } void TestAstToIR::init() diff --git a/tests/auto/qmljsc/testcodegeneratorforqml.cpp b/tests/auto/qmljsc/testcodegeneratorforqml.cpp new file mode 100644 --- /dev/null +++ b/tests/auto/qmljsc/testcodegeneratorforqml.cpp @@ -0,0 +1,149 @@ +/* + * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. + * + * Copyright (C) 2016 Anton Kreuzkamp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include + +#include +#include "../../../src/qmljsc/utils/error.h" +#include "../../../src/qmljsc/codegeneration/codegeneratorforqml.h" +#include "../../../src/qmljsc/ir/module.h" + +#define TEST_VISIT(className, scenarioName, instance, stackContent, expectedTopOfStack) \ + void test_visit_ ## className ## _ ## scenarioName() { \ + m_generator->m_outputStack.append(QVectorstackContent); \ + m_generator->endVisit(instance); \ + QCOMPARE(m_generator->m_outputStack.top(), QLatin1String(expectedTopOfStack)); \ + QCOMPARE(m_generator->m_outputStack.count(), 1); \ + } + +using namespace QQmlJS; + +Q_DECLARE_METATYPE(QmlJSc::IR::Node *); + +namespace QmlJSc { + +class TestCodeGeneratorForQml + : public QObject +{ + Q_OBJECT + +public: + TestCodeGeneratorForQml() + { + m_sourceElements.finish(); + + m_fullObject.addValueAssignment(&m_property); + m_fullObject.addSignalHandler(&m_signal); + m_fullObject.addProperty("someProperty"); + m_fullObject.addSignal("someSignal"); + m_fullObject.addSignal("someOtherSignal"); + m_fullObject.addMethod("someMethod"); + } + +private: + CodeGeneratorForQml *m_generator; + + const QString m_someLabel {"foo"}; + const QStringRef m_someLabelStringRef {&m_someLabel}; + + AST::NumericLiteral m_numericalExpressionPi {3.14}; + AST::ExpressionStatement m_simpleJsStatement {&m_numericalExpressionPi}; + AST::IdentifierExpression m_idExpression {m_someLabelStringRef}; + AST::PreIncrementExpression m_preIncExpression {&m_idExpression}; + AST::ExpressionStatement m_preIncStatement {&m_preIncExpression}; + AST::StatementSourceElement m_sourceElement {&m_preIncStatement}; + AST::SourceElements m_sourceElements {&m_sourceElement}; + AST::FunctionBody m_functionBody { &m_sourceElements }; + + IR::Type m_type { "T" }; + IR::Property m_property {&m_type, QStringLiteral("propName")}; + IR::Method m_emptyMethod {QStringLiteral("someMethod")}; + IR::Method m_methodWithContent {QStringLiteral("m2"), &m_functionBody}; + IR::Signal m_signal { QStringLiteral("someSignal") }; + IR::Signal m_paramSignal { QStringLiteral("otherSignal"), {{&m_type, "a"}, {&m_type, "b"}}}; + IR::Module m_module {"Mod", 1, 0}; + + IR::ValueAssignment m_jsAssignment {&m_property, &m_simpleJsStatement, IR::ValueAssignment::JsAssignment}; + IR::ValueAssignment m_objectAssignment {&m_property, (IR::ObjectSpec*)nullptr}; + IR::ValueAssignment m_bindingAssignment {&m_property, &m_preIncStatement, IR::ValueAssignment::Binding}; + IR::ValueAssignment m_emptyObjectListAssignment {&m_property, {}}; + IR::ValueAssignment m_objectListAssignment {&m_property, {0, 0, 0}}; + + IR::SignalHandler m_signalHandler {&m_signal, &m_preIncStatement}; + + IR::ObjectSpec m_emptyObject { &m_type }; + IR::ObjectSpec m_fullObject { &m_type }; + IR::Import m_import {&m_module, ""}; + IR::Import m_importLocalPrefix {&m_module, "Foo"}; + IR::File m_fileWithoutImports { {}, &m_emptyObject }; + IR::File m_fileWithOneModuleImport { {{&m_module, ""}}, &m_emptyObject }; + +private slots: + void init() { + m_generator = new CodeGeneratorForQml(); + }; + + void cleanup() { + delete m_generator; + } + + void testGeneratedCodeIsInitiallyEmpty() { + QCOMPARE(m_generator->getGeneratedCode(), QStringLiteral("")); + } + + void test_getGeneratedCode_getsTopOfStack() { + // Prepare + m_generator->m_outputStack << "1"; + + // Verify + QCOMPARE(m_generator->getGeneratedCode(), QStringLiteral("1")); + } + + void test_getGeneratedCode_throwsError_OnStackSizeGreaterThanOne() { + // Prepare + m_generator->m_outputStack << "1" << "2"; + + // Verify + QVERIFY_EXCEPTION_THROWN(m_generator->getGeneratedCode(), QmlJSc::Error *); + } + + TEST_VISIT(ValueAssignment, JsAssignment , &m_jsAssignment , {} , "propName: 3.14;") + TEST_VISIT(ValueAssignment, Binding , &m_bindingAssignment , {} , "propName: new QmlBinding(\"++foo;\")" ) + TEST_VISIT(ValueAssignment, ObjectAssignment , &m_objectAssignment , {"{}"} , "propName: {}" ) + TEST_VISIT(ValueAssignment, EmptyObjectList , &m_emptyObjectListAssignment, ({}) , "propName: []") + TEST_VISIT(ValueAssignment, ObjectList , &m_objectListAssignment , ({"{}","{}","{}"}) , "propName: [{},{},{}]") + TEST_VISIT(SignalHandler , SimpleHandler , &m_signalHandler , {} , "onSomeSignal: new QmlBinding(\"++foo;\")") + TEST_VISIT(ObjectSpec , EmptyObject , &m_emptyObject , {} , "{__proto__:QMLMetaElement.prototype,$class:\"T\"}") + TEST_VISIT(ObjectSpec , ObjectWithEverything , &m_fullObject , ({"1", "2", "3", "4", "5", "6"}), "{__proto__:QMLMetaElement.prototype,$class:\"T\",1,2,3,4,5,6}") + TEST_VISIT(Import , ModuleImportNoAs , &m_import , {} , "[\"qmlimport\",\"Mod\",1.0,\"\",true]" ) + TEST_VISIT(Import , ModuleImportWithAs , &m_importLocalPrefix , {} , "[\"qmlimport\",\"Mod\",1.0,\"Foo\",true]" ) + TEST_VISIT(File , FileWithoutImport , &m_fileWithoutImports , {"{}"} , "{$class:\"Component\",$children:[{}],$imports:[]}") + TEST_VISIT(File , FileWithOneModuleImport, &m_fileWithOneModuleImport , ({"[]","{}"}) , "{$class:\"Component\",$children:[{}],$imports:[[]]}") + TEST_VISIT(Property , SimpleProperty , &m_property , ({}) , "propName: new QMLPropertyDefinition(\"T\")") + TEST_VISIT(Method , EmptyMethod , &m_emptyMethod , ({}) , "someMethod: new QMLMethod(\"\")") + TEST_VISIT(Method , MethodWithContent , &m_methodWithContent , ({}) , "m2: new QMLMethod(\"++foo;\")") + TEST_VISIT(Signal , SimpleSignal , &m_signal , ({}) , "someSignal: new QMLSignalDefinition([])") + TEST_VISIT(Signal , SignalWithParams , &m_paramSignal , ({}) , "otherSignal: new QMLSignalDefinition([{name:\"a\",type:\"T\"},{name:\"b\",type:\"T\"}])") +}; + +} // namespace QmlJSc + +QTEST_MAIN(QmlJSc::TestCodeGeneratorForQml) +#include "testcodegeneratorforqml.moc" diff --git a/tests/auto/qmljsc/testmodules.cpp b/tests/auto/qmljsc/testmodules.cpp --- a/tests/auto/qmljsc/testmodules.cpp +++ b/tests/auto/qmljsc/testmodules.cpp @@ -63,9 +63,7 @@ void TestModules::loadMinimalModule() { - const ImportDescription testImportDescription = {ImportDescription::Kind_ModuleImport, "MinimalModule", 0, 1}; - - IR::Module *module = ModuleLoading::loadModule(testImportDescription); + IR::Module *module = ModuleLoading::loadModule("MinimalModule", 0, 1); module->waitForLoaded(); Type *a = module->type("A"); @@ -134,8 +132,7 @@ void TestModules::loadQtQml() { - const ImportDescription qtqmlImportDescription = {ImportDescription::Kind_ModuleImport, "QtQml", 1, 0}; - IR::Module *qtqmlModule = ModuleLoading::loadModule(qtqmlImportDescription); + IR::Module *qtqmlModule = ModuleLoading::loadModule("QtQml", 1, 0); qtqmlModule->waitForLoaded(); IR::Property *p = 0; @@ -219,11 +216,8 @@ void TestModules::loadModule() { - const ImportDescription qtqmlImportDescription = {ImportDescription::Kind_ModuleImport, "QtQml", 1, 0}; - const ImportDescription testImportDescription = {ImportDescription::Kind_ModuleImport, "TestModule", 0, 1}; - - IR::Module *module = ModuleLoading::loadModule(testImportDescription); - IR::Module *qtqmlModule = ModuleLoading::loadModule(qtqmlImportDescription); + IR::Module *module = ModuleLoading::loadModule("TestModule", 0, 1); + IR::Module *qtqmlModule = ModuleLoading::loadModule("QtQml", 1, 0); module->waitForLoaded(); qtqmlModule->waitForLoaded(); diff --git a/tests/auto/qmljsc/testpurejavascriptgenerator.cpp b/tests/auto/qmljsc/testpurejavascriptgenerator.cpp --- a/tests/auto/qmljsc/testpurejavascriptgenerator.cpp +++ b/tests/auto/qmljsc/testpurejavascriptgenerator.cpp @@ -25,7 +25,7 @@ #include #include "../../../src/qmljsc/utils/error.h" -#include "../../../src/qmljsc/purejavascriptgenerator.h" +#include "../../../src/qmljsc/codegeneration/purejavascriptgenerator.h" #define TEST_VISIT_PUTS_ON_STACK(className, testSituation, expectedStackContent, instance) \ void test_visit_ ## className ## _ ## testSituation ## _returnsTrue() { \ @@ -70,6 +70,8 @@ using namespace QQmlJS; +namespace QmlJSc { + class TestPureJavaScriptGenerator : public QObject { @@ -429,7 +431,7 @@ asPureJSGen(m_generator)->m_outputStack << "1" << "2"; // Verify - QVERIFY_EXCEPTION_THROWN(asPureJSGen(m_generator)->getGeneratedCode(), QmlJSc::Error); + QVERIFY_EXCEPTION_THROWN(asPureJSGen(m_generator)->getGeneratedCode(), QmlJSc::Error *); } TEST_VISIT_DEFAULT_IMPL_(Block , m_block) @@ -600,5 +602,7 @@ TEST_VISIT_BINARYOP_PUTS_ON_STACK(InstanceOf, " instanceof ") }; -QTEST_MAIN(TestPureJavaScriptGenerator) +} // namespace QmlJSc + +QTEST_MAIN(QmlJSc::TestPureJavaScriptGenerator) #include "testpurejavascriptgenerator.moc" diff --git a/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp b/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp --- a/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp +++ b/tests/auto/qmljsc/testpurejavascriptgenerator_integration.cpp @@ -18,7 +18,7 @@ * */ -#include "../../../src/qmljsc/purejavascriptgenerator.h" +#include "../../../src/qmljsc/codegeneration/purejavascriptgenerator.h" #include #include @@ -31,6 +31,8 @@ Q_DECLARE_METATYPE(QQmlJS::AST::Node*) +namespace QmlJSc { + class TestPureJavaScriptGeneratorIntegration : public QObject { @@ -115,5 +117,7 @@ }; -QTEST_MAIN(TestPureJavaScriptGeneratorIntegration) +} // namespace QmlJSc + +QTEST_MAIN(QmlJSc::TestPureJavaScriptGeneratorIntegration) #include "testpurejavascriptgenerator_integration.moc"