diff --git a/src/qmljsc/CMakeLists.txt b/src/qmljsc/CMakeLists.txt index 948f162..2f42ae5 100644 --- a/src/qmljsc/CMakeLists.txt +++ b/src/qmljsc/CMakeLists.txt @@ -1,32 +1,34 @@ find_package(Qt5 COMPONENTS Core Qml) set(libqmljsc_srcs compiler.cpp error.cpp compilerpipeline.cpp compilerpass.cpp ir/ir.cpp - ir/module.cpp ir/file.cpp + typesystem/typesystem.cpp + typesystem/module.cpp + compilerpasses/parserpass.cpp compilerpasses/prettygeneratorpass.cpp moduleloading/abstractmoduleloader.cpp moduleloading/javascriptmoduleloader.cpp moduleloading/moduleloading.cpp utils/shortsymbolname.cpp ) add_library(libqmljsc SHARED ${libqmljsc_srcs}) qt5_use_modules(libqmljsc Core Qml) include_directories(${Qt5Qml_PRIVATE_INCLUDE_DIRS}) set(qmljsc_srcs main.cpp ) add_executable(qmljsc ${qmljsc_srcs}) target_link_libraries(qmljsc libqmljsc) diff --git a/src/qmljsc/compilerpass.cpp b/src/qmljsc/compilerpass.cpp index 71ba27b..9a4cb4d 100644 --- a/src/qmljsc/compilerpass.cpp +++ b/src/qmljsc/compilerpass.cpp @@ -1,53 +1,53 @@ /* * 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 "compilerpipeline.h" #include "compilerpass.h" using namespace QmlJSc; CompilerPass::CompilerPass(QObject *parent): QObject(parent) { } void CompilerPass::connectToSuccessor(CompilerPass *successor) { connect(this, SIGNAL(finished(QString)), successor, SLOT(process(QString))); connect(this, SIGNAL(finished(QQmlJS::AST::UiProgram*)), successor, SLOT(process(QQmlJS::AST::UiProgram*))); } void CompilerPass::process(QString) { failBecauseOfWrongType(); } void CompilerPass::process(QQmlJS::AST::UiProgram*) { failBecauseOfWrongType(); } -void CompilerPass::process(IR::Component*) { +void CompilerPass::process(IR::File*) { failBecauseOfWrongType(); } void CompilerPass::failBecauseOfWrongType() { Q_STATIC_ASSERT_X(1, "The type is not supported by this compiler pass, is the compiler pass order correct?"); } diff --git a/src/qmljsc/compilerpass.h b/src/qmljsc/compilerpass.h index 50e185e..323b5cf 100644 --- a/src/qmljsc/compilerpass.h +++ b/src/qmljsc/compilerpass.h @@ -1,63 +1,63 @@ /* * 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 PIPELINESTAGE_H #define PIPELINESTAGE_H #include #include #include "error.h" -#include "ir/ir.h" +#include "ir/file.h" #include Q_DECLARE_METATYPE(QQmlJS::AST::UiProgram*) namespace QmlJSc { class CompilerPipeline; class CompilerPass : public QObject { Q_OBJECT public: CompilerPass(QObject *parent = 0); void connectToSuccessor(CompilerPass *successor); public slots: virtual void process(QString); virtual void process(QQmlJS::AST::UiProgram*); - virtual void process(IR::Component*); + virtual void process(IR::File*); signals: void finished(QString); void finished(QQmlJS::AST::UiProgram*); - void finished(IR::Component*); + void finished(IR::File*); private: void failBecauseOfWrongType(); }; } #endif // PIPELINESTAGE_H diff --git a/src/qmljsc/compilerpasses/prettygeneratorpass.cpp b/src/qmljsc/compilerpasses/prettygeneratorpass.cpp index 8f0eb59..18b4f5e 100644 --- a/src/qmljsc/compilerpasses/prettygeneratorpass.cpp +++ b/src/qmljsc/compilerpasses/prettygeneratorpass.cpp @@ -1,79 +1,78 @@ /* * 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 #include "compiler.h" #include "compilerpipeline.h" #include "ir/file.h" #include "prettygeneratorpass.h" using namespace QmlJSc; const QString RUNTIME_INHERIT = QStringLiteral("QW_INHERIT"); const QString RUNTIME_CONTEXT = QStringLiteral("QWContext"); const QString TEMPLATE_COMPONENT_HEAD = QStringLiteral( "%1(%2, %3);\n" \ "function %2(parent) {\n" \ " %3.call(this, parent);\n" \ " var __ = new %4(this);\n" \ ); const QString TEMPLATE_COMPONENT_FOOT = QStringLiteral( "\n\n" \ "%1;" ); PrettyGeneratorPass::PrettyGeneratorPass() : m_output() { m_componentRoot = false; m_output.setString(new QString()); } -void PrettyGeneratorPass::process(IR::Component* immediateRepresentation) +void PrettyGeneratorPass::process(IR::File* immediateRepresentation) { Q_ASSERT(immediateRepresentation); immediateRepresentation->accept(this); emit finished( *(m_output.string()) ); } -void PrettyGeneratorPass::visit(IR::Component* component) { - IR::File file; - const QString objectIdentifier = component->super()->name(); - const QString objectFqi = file.fullyQualifiedName(objectIdentifier); +void PrettyGeneratorPass::visit(IR::File* file) { + const QString objectIdentifier = file->rootObject()->super()->name(); + const QString objectFqi = file->fullyQualifiedName(objectIdentifier); m_output << TEMPLATE_COMPONENT_HEAD .arg(RUNTIME_INHERIT) .arg("__comp") .arg(objectFqi) .arg("QWContext"); } -void PrettyGeneratorPass::endVisit(IR::Component *) { +void PrettyGeneratorPass::endVisit(IR::File *) { m_output << '}'; // close __comp definition m_output << TEMPLATE_COMPONENT_FOOT .arg("__comp"); } \ No newline at end of file diff --git a/src/qmljsc/compilerpasses/prettygeneratorpass.h b/src/qmljsc/compilerpasses/prettygeneratorpass.h index ac57a64..b673813 100644 --- a/src/qmljsc/compilerpasses/prettygeneratorpass.h +++ b/src/qmljsc/compilerpasses/prettygeneratorpass.h @@ -1,53 +1,53 @@ /* * 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 PRETTYGENERATORSTAGE_H #define PRETTYGENERATORSTAGE_H #include "../ir/visitor.h" #include "../compilerpass.h" namespace QmlJSc { class PrettyGeneratorPass : public CompilerPass, public IR::Visitor { Q_OBJECT public: PrettyGeneratorPass(); - virtual void visit(IR::Component* component) override; - virtual void endVisit(IR::Component* component) override; + virtual void visit(IR::File* file) override; + virtual void endVisit(IR::File* file) override; public slots: - void process(IR::Component* rootComponent) override; + void process(IR::File *file) override; private: int m_levelSpaceCount = 4; QTextStream m_output; bool m_componentRoot; }; } #endif // PRETTYGENERATORSTAGE_H diff --git a/src/qmljsc/ir/file.cpp b/src/qmljsc/ir/file.cpp index 4c5515f..5682d89 100644 --- a/src/qmljsc/ir/file.cpp +++ b/src/qmljsc/ir/file.cpp @@ -1,98 +1,106 @@ /* * 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 . * */ #include "file.h" -#include "module.h" +#include "../typesystem/module.h" #include "../error.h" #include "../compiler.h" +#include "visitor.h" using namespace QmlJSc; using namespace QmlJSc::IR; bool File::ModuleData::operator==(const File::ModuleData& other) const { return module == other.module; } File::File() : m_prefix('A' - 1) // we want the prefix to be 'A' after the first preincrement { } File::~File() { } -void File::addModule(Module *module) +void File::addModule(TypeSystem::Module *module) { if (m_importedModules.contains({ module, QString() })) return; m_importedModules.append({ module, ++m_prefix }); } -Type *File::type(const QString &typeName) const +TypeSystem::Type *File::type(const QString &typeName) const { const ModuleData *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); } -Component *File::rootObject() const +Object *File::rootObject() const { return m_rootObject; } -void File::setRootObject(Component *rootObject) +void File::setRootObject(Object *rootObject) { m_rootObject = rootObject; } const File::ModuleData *File::moduleForType(const QString &typeName) const { - Type *foundType = 0; + TypeSystem::Type *foundType = 0; const ModuleData *moduleData = 0; foreach (const ModuleData &data, m_importedModules) { - if (Type * type = data.module->type(typeName)) { + if (TypeSystem::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()) - ); + QmlJSc::Error::SymbolLookupError, + QString("Ambigious type name. Type %1 was defined by module %2 and %3.") + .arg(typeName, moduleData->module->name(), data.module->name()) + ); return 0; } else { foundType = type; moduleData = &data; } } } return moduleData; } + +void QmlJSc::IR::File::accept(QmlJSc::IR::Visitor* visitor) +{ + visitor->visit(this); + m_rootObject->accept(visitor); + visitor->endVisit(this); +} diff --git a/src/qmljsc/ir/file.h b/src/qmljsc/ir/file.h index 82996ba..3b4bfa7 100644 --- a/src/qmljsc/ir/file.h +++ b/src/qmljsc/ir/file.h @@ -1,72 +1,78 @@ /* * 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 FILE_H #define FILE_H #include "ir.h" #include "importdefinition.h" #include "../utils/shortsymbolname.h" #include #include #include #include #include namespace QmlJSc { + +namespace TypeSystem { + class Module; + class Type; +} + namespace IR { -class Module; -struct Type; -class File +class File : public Node { struct ModuleData { - Module *module; + TypeSystem::Module *module; QString localPrefix; bool operator==(const ModuleData &other) const; }; public: explicit File(); virtual ~File(); - void addModule(Module *module); + void addModule(TypeSystem::Module *module); - Type* type(const QString &typeName) const; + TypeSystem::Type* type(const QString &typeName) const; QString fullyQualifiedName(const QString &typeName); - Component *rootObject() const; - void setRootObject(Component *root); + Object *rootObject() const; + void setRootObject(Object *root); + + virtual void accept(Visitor * visitor) override; private: const ModuleData *moduleForType(const QString &typeName) const; QVector m_importedModules; ShortSymbolName m_prefix; - Component *m_rootObject; + Object *m_rootObject; }; } // namespace IR } // namespace QMLJSc #endif // FILE_H diff --git a/src/qmljsc/ir/ir.cpp b/src/qmljsc/ir/ir.cpp index e7127dc..a0c2763 100644 --- a/src/qmljsc/ir/ir.cpp +++ b/src/qmljsc/ir/ir.cpp @@ -1,349 +1,110 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Anton Kreuzkamp * 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 "visitor.h" #include "ir.h" +using namespace QmlJSc; using namespace QmlJSc::IR; -Type::Type() - : m_super(0) -{ -} - -Type::Kind Type::kind() -{ - return m_kind; -} - -const QString &Type::name() -{ - return m_name; -} - -const QString &Type::javaScriptName() -{ - return m_javaScriptName; -} - -Property *Type::addProperty(const QString &name) -{ - return &m_properties.insert(name, Property(name)).value(); -} - -Method *Type::addMethod(const QString &name) -{ - return &m_methods.insert(name, Method(name)).value(); -} - -Signal *Type::addSignal(const QString &name) -{ - return &m_signals.insert(name, Signal(name)).value(); -} - -void Type::setName(const QString &name) -{ - m_name = name; -} - -void Type::setJavaScriptName(const QString &jsName) -{ - m_javaScriptName = jsName; -} - -Property *Type::property(const QString &name) -{ - if (m_properties.contains(name)) { - return &m_properties[name]; - } - if (m_super) { - return m_super->property(name); - } - return 0; -} - -Method *Type::method(const QString &name) -{ - if (m_methods.contains(name)) { - return &m_methods[name]; - } - if (m_super) { - return m_super->method(name); - } - return 0; -} - -Signal *Type::signal(const QString &name) -{ - if (m_signals.contains(name)) { - return &m_signals[name]; - } - if (m_super) { - return m_super->signal(name); - } - return 0; -} - -Node *Type::member(const QString &name) -{ - if (m_properties.contains(name)) { - return &m_properties[name]; - } - if (m_methods.contains(name)) { - return &m_methods[name]; - } - if (m_signals.contains(name)) { - return &m_signals[name]; - } - if (m_super) { - return m_super->member(name); - } - return 0; -} - -void Type::accept(Visitor *visitor) { - visitor->visit(this); - visitChildren(visitor); - visitor->endVisit(this); -} - -void Type::visitChildren(Visitor *visitor) { - for (auto i = m_properties.begin(); i != m_properties.end(); i++) { - i.value().accept(visitor); - } - for (auto i = m_methods.begin(); i != m_methods.end(); i++) { - i.value().accept(visitor); - } - for (auto i = m_signals.begin(); i != m_signals.end(); i++) { - i.value().accept(visitor); - } -} - -Type *Type::super() { - return m_super; -} - -void Type::setSuper(Type *superType) { - m_super = superType; -} - -Class::Class() - : Type() -{ - m_kind = Type::Kind_Class; -} - -void Class::accept(Visitor *visitor) { - visitor->visit(this); - visitor->endVisit(this); -} - Object::Object() - : Type() + : Node() + , TypeSystem::Type() { - m_kind = Type::Kind_Object; } QVector &Object::valueAssignments() { return m_valueAssignments; } QVector &Object::bindingAssignments() { return m_bindingAssignments; } ValueAssignment::ValueAssignment() : property(0) , objectValue(0) , jsValue(0) { } -ValueAssignment::ValueAssignment(Property *property, Object *objectValue, QQmlJS::AST::ExpressionNode *jsValue) +ValueAssignment::ValueAssignment(TypeSystem::Property *property, Object *objectValue, QQmlJS::AST::ExpressionNode *jsValue) : property(property) , objectValue(objectValue) , jsValue(jsValue) { } ValueAssignment *Object::addValueAssignment() { m_valueAssignments.append(ValueAssignment()); return &m_valueAssignments.last(); } void ValueAssignment::accept(Visitor *visitor) { visitor->visit(this); if (objectValue) { objectValue->accept(visitor); } visitor->endVisit(this); } -BindingAssignment::BindingAssignment(Property *property, QQmlJS::AST::ExpressionNode *binding) - : property(0) - , binding(0) +BindingAssignment::BindingAssignment(TypeSystem::Property *property, QQmlJS::AST::ExpressionNode *binding) + : property(property) + , binding(binding) { } BindingAssignment::BindingAssignment() - : property(property) - , binding(binding) + : property(0) + , binding(0) { } void BindingAssignment::accept(Visitor *visitor) { visitor->visit(this); visitor->endVisit(this); } BindingAssignment *Object::addBindingAssignment() { m_bindingAssignments.append(BindingAssignment()); return &m_bindingAssignments.last(); } void Object::accept(Visitor *visitor) { visitor->visit(this); visitChildren(visitor); visitor->endVisit(this); } void Object::visitChildren(Visitor *visitor) { - Type::visitChildren(visitor); - for (auto i = m_valueAssignments.begin(); i != m_valueAssignments.end(); i++) { i->accept(visitor); } for (auto i = m_bindingAssignments.begin(); i != m_bindingAssignments.end(); i++) { i->accept(visitor); } -} - -Component::Component() - : Object() -{ - m_kind = Type::Kind_Component; -} - -Object *Component::object(const QString &id) -{ - if (m_ids.contains(id)) { - return m_ids[id]; - } - if (m_parentComponent) { - return m_parentComponent->object(id); - } - return 0; -} - -void Component::accept(Visitor *visitor) { - visitor->visit(this); - visitChildren(visitor); - visitor->endVisit(this); -} - -void Component::visitChildren(Visitor *visitor) { - Object::visitChildren(visitor); - - for (auto i = m_ids.begin(); i != m_ids.end(); i++) { - i.value()->accept(visitor); - } -} - -Method::Method() - : returnType(0) -{ - kind = Kind_Method; -} - -Method::Method(const QString &name) - : returnType(0) - , name(name) -{ - kind = Kind_Method; -} - -Method::Method(QmlJSc::IR::Type *returnType, QString name) - : returnType(returnType) - , name(name) -{ - kind = Kind_Method; -} - -void Method::accept(QmlJSc::IR::Visitor *visitor) { - visitor->visit(this); - visitor->endVisit(this); -} - -Signal::Signal() -{ - kind = Kind_Signal; -} - -Signal::Signal(QString name) - : name(name) -{ - kind = Kind_Signal; -} - -void Signal::accept(QmlJSc::IR::Visitor *visitor) { - visitor->visit(this); - visitor->endVisit(this); -} - -Property::Property() - : type(0) - , objectValue(0) - , jsValue(0) -{ - kind = Kind_Property; -} - -Property::Property(const QString &name) - : type(0) - , name(name) - , objectValue(0) - , jsValue(0) -{ - kind = Kind_Property; -} - -Property::Property(QmlJSc::IR::Type *type, QString name) - : type(type) - , name(name) - , objectValue(0) - , jsValue(0) -{ - kind = Kind_Property; -} - -void Property::accept(QmlJSc::IR::Visitor *visitor) { - visitor->visit(this); - if (objectValue) { - objectValue->accept(visitor); - } - visitor->endVisit(this); } \ No newline at end of file diff --git a/src/qmljsc/ir/ir.h b/src/qmljsc/ir/ir.h index 61e460b..13bce14 100644 --- a/src/qmljsc/ir/ir.h +++ b/src/qmljsc/ir/ir.h @@ -1,260 +1,129 @@ /* * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. * * Copyright (C) 2015 Anton Kreuzkamp * 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_IR_H #define QMLWEB_IR_H #include #include #include +#include "../typesystem/typesystem.h" + namespace QQmlJS { namespace AST { class ExpressionNode; } } namespace QmlJSc { namespace IR { class Visitor; class Node { public: enum Kind { Kind_Invalid, Kind_Property, Kind_Method, Kind_Signal, Kind_BasicType, Kind_List, Kind_Class, Kind_Component, Kind_Object }; template T *as() { if (T::kind == kind) { return reinterpret_cast(this); } return 0; } virtual void accept(Visitor *visitor) = 0; Kind kind; }; -class Property; -class Method; -class Signal; - -/** - * This class provides API representing Qml.js objects and types and allows to - * learn about the type's properties, functions, etc. - * - * Type hereby refers to (built in) basic types, types provided by modules and - * components as well as any objects defined in QML. - */ -class Type : public Node -{ -public: - Type(); - - Kind kind(); - const QString &name(); - const QString &javaScriptName(); - Property *property(const QString &name); - Method *method(const QString &name); - Signal *signal(const QString &name); - Node *member(const QString &name); - - Property *addProperty(const QString &name); - Method *addMethod(const QString &name); - Signal *addSignal(const QString &name); - - void setName(const QString &name); - void setJavaScriptName(const QString &jsName); - - Type *super(); - void setSuper(Type *superType); - - virtual void accept(Visitor *visitor) override; - -protected: - Kind m_kind; - -protected: - QString m_name; - QString m_javaScriptName; - QHash m_properties; - QHash m_methods; - QHash m_signals; - - virtual void visitChildren(Visitor *visitor); - - /** - * pointer to the super class or in case of objects the class of the object - */ - Type *m_super; - - - friend class TestIR; -}; - -class Class : public Type -{ -public: - Class(); - - virtual void accept(Visitor *visitor) override; - -private: - Type *m_attached; - - friend class TestIR; -}; - class Object; struct ValueAssignment : public Node { ValueAssignment(); - ValueAssignment(Property *property, Object *objectValue, QQmlJS::AST::ExpressionNode *jsValue); + ValueAssignment(TypeSystem::Property *property, Object *objectValue, QQmlJS::AST::ExpressionNode *jsValue); - Property *property; + TypeSystem::Property *property; Object *objectValue; QQmlJS::AST::ExpressionNode *jsValue; virtual void accept(Visitor *visitor) override; }; struct BindingAssignment : public Node { BindingAssignment(); - BindingAssignment(Property *property, QQmlJS::AST::ExpressionNode *binding); + BindingAssignment(TypeSystem::Property *property, QQmlJS::AST::ExpressionNode *binding); - Property *property; + TypeSystem::Property *property; QQmlJS::AST::ExpressionNode *binding; virtual void accept(Visitor *visitor) override; }; -class Component; - -class Object : public Type +class Object : public Node, public TypeSystem::Type { public: Object(); QVector &valueAssignments(); QVector &bindingAssignments(); ValueAssignment *addValueAssignment(); BindingAssignment *addBindingAssignment(); virtual void accept(Visitor *visitor) override; protected: QVector m_valueAssignments; QVector m_bindingAssignments; - virtual void visitChildren(Visitor *visitor) override; + virtual void visitChildren(Visitor *visitor); /** * Refers to the component that contains this object. * If this is a component root itself, it's a pointer to itself. */ - Component *m_component; - - friend class TestIR; -}; - -class Component : public Object -{ -public: - Component(); - - Object *object(const QString &id); - - virtual void accept(Visitor *visitor) override; - virtual void visitChildren(Visitor *visitor) override; - -private: - QHash m_ids; - - Component *m_parentComponent; +// Component *m_component; friend class TestIR; }; -struct Parameter { - QmlJSc::IR::Type *type; - QString name; -}; - -struct Method : public QmlJSc::IR::Node { - Method(); - Method(const QString &name); - Method(QmlJSc::IR::Type *returnType, QString name); - - QmlJSc::IR::Type *returnType; - QString name; - QVector parameters; - - virtual void accept(QmlJSc::IR::Visitor *visitor) override; -}; - -struct Signal : public QmlJSc::IR::Node { - Signal(); - Signal(QString name); - QString name; - QVector parameters; - - virtual void accept(QmlJSc::IR::Visitor *visitor) override; -}; - -struct Property : public QmlJSc::IR::Node { - Property(); - Property(const QString &name); - Property(QmlJSc::IR::Type *type, QString name); - - QmlJSc::IR::Type *type; - QString name; - - QmlJSc::IR::Object *objectValue; - QQmlJS::AST::ExpressionNode *jsValue; - bool readOnly :1; - bool constant :1; - bool dummy :6; - - virtual void accept(QmlJSc::IR::Visitor *visitor) override; -}; - } // namespace IR } // namespace QmlJSc #endif //QMLWEB_IR_H diff --git a/src/qmljsc/ir/visitor.h b/src/qmljsc/ir/visitor.h index 316dcfa..dfb2761 100644 --- a/src/qmljsc/ir/visitor.h +++ b/src/qmljsc/ir/visitor.h @@ -1,69 +1,69 @@ /* * 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_VISITOR_H #define QMLWEB_VISITOR_H namespace QmlJSc { namespace IR { class Node; -class Component; +class File; class Class; class Type; class Object; class Property; class Method; class Signal; class Symbol; class ValueAssignment; class BindingAssignment; class Visitor { public: - virtual void visit(Component *component) {} - virtual void visit(Class *_class) {} + virtual void visit(File *file) {} + virtual void visit(Class *class_) {} virtual void visit(Type *type) {} virtual void visit(Object *object) {} virtual void visit(Property *property) {} virtual void visit(Method *method) {} virtual void visit(Signal *signal) {} virtual void visit(Symbol *symbol) {} virtual void visit(ValueAssignment *valueAssignment) {} virtual void visit(BindingAssignment *bindingAssignment) {} - virtual void endVisit(Component *component) {} - virtual void endVisit(Class *_class) {} + virtual void endVisit(File *file) {} + virtual void endVisit(Class *class_) {} virtual void endVisit(Type *type) {} virtual void endVisit(Object *object) {} virtual void endVisit(Property *property) {} virtual void endVisit(Method *method) {} virtual void endVisit(Signal *signal) {} virtual void endVisit(Symbol *symbol) {} virtual void endVisit(ValueAssignment *valueAssignment) {} virtual void endVisit(BindingAssignment *bindingAssignment) {} }; } // namespace IR } // namespace QmlJSc #endif //QMLWEB_VISITOR_H diff --git a/src/qmljsc/moduleloading/abstractmoduleloader.cpp b/src/qmljsc/moduleloading/abstractmoduleloader.cpp index 5b8b820..e994a4c 100644 --- a/src/qmljsc/moduleloading/abstractmoduleloader.cpp +++ b/src/qmljsc/moduleloading/abstractmoduleloader.cpp @@ -1,47 +1,47 @@ /* * 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 . * */ // Own #include "abstractmoduleloader.h" -#include "ir/module.h" +#include "typesystem/module.h" #include "error.h" using namespace QmlJSc; -AbstractModuleLoader::AbstractModuleLoader(IR::Module *module) +AbstractModuleLoader::AbstractModuleLoader(TypeSystem::Module *module) : QRunnable() , m_module(module) {} void AbstractModuleLoader::run() { try { doLoad(); } catch (Error *e) { qWarning() << e->what(); - m_module->setLoadingState(IR::Module::ErrorState); + m_module->setLoadingState(TypeSystem::Module::ErrorState); } } -IR::Module *AbstractModuleLoader::module() +TypeSystem::Module *AbstractModuleLoader::module() { return m_module; } diff --git a/src/qmljsc/moduleloading/abstractmoduleloader.h b/src/qmljsc/moduleloading/abstractmoduleloader.h index 613c70a..fde1f10 100644 --- a/src/qmljsc/moduleloading/abstractmoduleloader.h +++ b/src/qmljsc/moduleloading/abstractmoduleloader.h @@ -1,68 +1,68 @@ /* * 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 ABSTRACTMODULELOADER_H #define ABSTRACTMODULELOADER_H //Qt #include namespace QmlJSc { -namespace IR { +namespace TypeSystem { class Module; } /** * This class provides an abstract base class for classes that can load modules. * Examples for base classes are the javascript-module loader and the * qtqml-module loader. * * It brings the basic infrastructure to run it on it's own thread (so module * loaders will always run asynchronously in their own thread) and to figure out * if it's the right loader for a specific module. * * If you implement this class, you need to implement canLoad, telling if the * class is suitable to load this module and doLoad, to actually load it. * Use module() to get the module you're about to load and add types to it. */ class AbstractModuleLoader : public QRunnable { public: - AbstractModuleLoader(IR::Module *module); + AbstractModuleLoader(TypeSystem::Module *module); /** * Don't reimplement this in a moduleloader. */ void run() override; virtual bool canLoad() = 0; virtual void doLoad() = 0; - IR::Module *module(); + TypeSystem::Module *module(); private: - IR::Module *m_module; + TypeSystem::Module *m_module; }; } // namespace QMLJSc #endif // ABSTRACTMODULELOADER_H diff --git a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp index fb5ae19..07713d5 100644 --- a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp +++ b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp @@ -1,514 +1,510 @@ /* * 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 . * */ // Own #include "javascriptmoduleloader.h" #include "moduleloading.h" -#include "ir/module.h" +#include "typesystem/module.h" #include "ir/ir.h" #include "compiler.h" #include "error.h" // Qt #include #include #include #include // Qt private #include #include #include #define assert(condition, token, errorMessage) \ if (!condition) { \ assertFailed(token, errorMessage); \ } using namespace QmlJSc; using namespace QQmlJS; static void assertFailed(const AST::SourceLocation &token, QString errorMessage) { // Normally you wouldn't throw by reference but by value. We need to create // the error object on the stack and throw by pointer, because we'll need it // to be available on another thread. Error *error = new Error(Error::ModuleImportError, errorMessage); error->setLine(token.startLine); error->setColumn(token.startColumn); throw error; } -RegisterModuleVisitor::RegisterModuleVisitor(IR::Module* module) +RegisterModuleVisitor::RegisterModuleVisitor(TypeSystem::Module* module) : QQmlJS::AST::Visitor() , m_module(module) { } bool RegisterModuleVisitor::visit(AST::CallExpression *call) { if (call->base->kind != AST::Node::Kind_FieldMemberExpression) { return true; } AST::FieldMemberExpression *base = AST::cast(call->base); if (!base || base->name != QStringLiteral("registerModule")) { return true; } AST::IdentifierExpression *probablyEngine = AST::cast(base->base); if (!probablyEngine || probablyEngine->name != QStringLiteral("__engine")) { return true; } // Ok, apparently, it's the __engine.registerModule expression, we're looking for. // If now still some assumption fails, throw an error. if (!call->arguments) { Error *error = new Error(Error::ModuleImportError, "Malformed registerModule call: No argument provided."); error->setLine(call->lparenToken.startLine); error->setColumn(call->lparenToken.startColumn); throw error; } AST::ObjectLiteral *moduleInfoLiteral = AST::cast(call->arguments->expression); assert(moduleInfoLiteral, call->lparenToken, "Malformed registerModule call: Wrong argument type provided. Expected Object Literal."); AST::PropertyAssignmentList *assignment = moduleInfoLiteral->properties; while(assignment) { AST::PropertyNameAndValue *nameAndValue = AST::cast(assignment->assignment); assert(nameAndValue, assignment->assignment->firstSourceLocation(), "Malformed registerModule call: Invalid type specification." ); AST::IdentifierExpression *functionId = AST::cast(nameAndValue->value); assert(functionId, nameAndValue->value->firstSourceLocation(), "Malformed registerModule call: Can't recognize function identifier. " "Please use a simple identifier as value on type object." ); - IR::Class *c = new IR::Class; + TypeSystem::LibraryClass *c = new TypeSystem::LibraryClass; c->setName(nameAndValue->name->asString()); c->setJavaScriptName(functionId->name.toString()); m_module->addType(c); assignment = assignment->next; } return true; } -TypeDefinitionVisitor::TypeDefinitionVisitor(IR::Module* module) +TypeDefinitionVisitor::TypeDefinitionVisitor(TypeSystem::Module* module) : QQmlJS::AST::Visitor() , m_module(module) { } bool TypeDefinitionVisitor::visit(AST::FunctionExpression* func) { m_currentFunctionStack << func; return true; } void TypeDefinitionVisitor::endVisit(AST::FunctionExpression* func) { m_currentFunctionStack.removeLast(); } bool TypeDefinitionVisitor::visit(AST::FunctionDeclaration* func) { m_currentFunctionStack << func; return true; } void TypeDefinitionVisitor::endVisit(AST::FunctionDeclaration* func) { m_currentFunctionStack.removeLast(); } bool TypeDefinitionVisitor::visit(AST::BinaryExpression* expr) { // --- Might be a property, a method, a signal, a class or uninteresting. if (expr->right->kind == AST::Node::Kind_FunctionExpression) { findMethodDefinition(expr); // Each function expression is a potential class definition. Give it // a name, so we may reference it later on. QStringRef name; if (expr->left->kind == AST::Node::Kind_FieldMemberExpression) { name = AST::cast(expr->left)->name; } else if (expr->left->kind == AST::Node::Kind_FunctionExpression) { name = AST::cast(expr->left)->name; } else { return true; } AST::cast(expr->right)->name = name; } else if (expr->right->kind == AST::Node::Kind_CallExpression) { findSignalDefinition(expr); } else if (expr->right->kind == AST::Node::Kind_NewMemberExpression) { findPropertyDefinition(expr); } return true; } bool TypeDefinitionVisitor::visit(AST::VariableDeclaration *var) { AST::FunctionExpression *func = AST::cast(var->expression); if (!func) { return true; } // This is a potential class definition. Give the function a name, so we may // reference it later on. func->name = var->name; return true; } bool TypeDefinitionVisitor::visit(AST::CallExpression *call) { if (call->base->kind != AST::Node::Kind_IdentifierExpression) { return true; } AST::IdentifierExpression *maybeInheritance = AST::cast(call->base); if (!maybeInheritance || maybeInheritance->name != QStringLiteral("QW_INHERIT")) { return true; } // Apparently this is a QW_INHERIT call, we're looking for. // If now still some assumption fails, throw an error. assert(call->arguments && call->arguments->next, call->lparenToken, "Malformed QW_INHERIT call: One or no argument provided. Expected two." ); AST::IdentifierExpression *constructor = AST::cast(call->arguments->expression); AST::IdentifierExpression *baseClass = AST::cast(call->arguments->next->expression); assert(constructor && baseClass, call->lparenToken, "Malformed QW_INHERIT call: Wrong argument types provided. Expected two identifier expressions." ); - IR::Type *t = m_module->typeFromJSName(constructor->name.toString()); + TypeSystem::Type *t = m_module->typeFromJSName(constructor->name.toString()); assert(t, constructor->firstSourceLocation(), "Using a type that won't get registered."); t->setSuper(getType(baseClass->name)); return true; } void TypeDefinitionVisitor::findPropertyDefinition(AST::BinaryExpression *expr) { if (expr->op != QSOperator::Assign) { return; } AST::FieldMemberExpression *lValue = AST::cast(expr->left); AST::NewMemberExpression *rValue = AST::cast(expr->right); if (!rValue || !lValue) { return; } AST::IdentifierExpression *constructor = AST::cast(rValue->base); AST::ThisExpression *maybeThis = AST::cast(lValue->base); if (!constructor || constructor->name != QStringLiteral("QWProperty") || !maybeThis) { return; } // Ok, this is a property definition - IR::Type *t = m_module->typeFromJSName(m_currentFunctionStack.last()->name.toString()); + TypeSystem::Type *t = m_module->typeFromJSName(m_currentFunctionStack.last()->name.toString()); assert(t, lValue->firstSourceLocation(), "Registering properties to a type that won't get registered."); - IR::Property *property = t->addProperty(lValue->name.toString()); + TypeSystem::Property *property = t->addProperty(lValue->name.toString()); AST::ObjectLiteral *parameters = AST::cast(rValue->arguments->expression); if (!parameters) { return; } for (AST::PropertyAssignmentList *aList = parameters->properties; aList; aList = aList->next) { AST::PropertyNameAndValue *nameAndValue = AST::cast(aList->assignment); assert(nameAndValue, aList->assignment->firstSourceLocation(), "Malformed QWProperty call: Expected argument to be a name value pair." ); if (nameAndValue->name->asString() == "type") { AST::IdentifierExpression *id = AST::cast(nameAndValue->value); assert(id, nameAndValue->value->firstSourceLocation(), "Malformed QWProperty call: Expected argument 'type' to have an identifier expression as value." ); property->type = getType(id->name); continue; } if (nameAndValue->name->asString() == "typeArg") { AST::IdentifierExpression *id = AST::cast(nameAndValue->value); assert(id, nameAndValue->value->firstSourceLocation(), "Malformed QWProperty call: Expected argument 'typeArg' to have an identifier expression as value." ); property->type = getType(id->name); continue; } - if (nameAndValue->name->asString() == "initialValue") { - property->jsValue = nameAndValue->value; - continue; - } if (nameAndValue->name->asString() == "readonly") { assert(nameAndValue->value->kind == AST::Node::Kind_TrueLiteral || nameAndValue->value->kind == AST::Node::Kind_FalseLiteral, nameAndValue->colonToken, "Malformed QWProperty call: readonly may only have true or false as value." ); property->readOnly = nameAndValue->value->kind == AST::Node::Kind_TrueLiteral; continue; } if (nameAndValue->name->asString() == "constant") { assert(nameAndValue->value->kind == AST::Node::Kind_TrueLiteral || nameAndValue->value->kind == AST::Node::Kind_FalseLiteral, nameAndValue->colonToken, "Malformed QWProperty call: constant may only have true or false as value." ); property->constant = nameAndValue->value->kind == AST::Node::Kind_TrueLiteral; continue; } } } void TypeDefinitionVisitor::findMethodDefinition(AST::BinaryExpression *expr) { if (expr->op != QSOperator::Assign) { return; } AST::FieldMemberExpression *lValue = AST::cast(expr->left); AST::FunctionExpression *func = AST::cast(expr->right); - IR::Type *t; + TypeSystem::Type *t; if (lValue->base->kind == AST::Node::Kind_ThisExpression) { t = m_module->typeFromJSName(m_currentFunctionStack.last()->name.toString()); } else { AST::FieldMemberExpression *first = AST::cast(lValue->base); if (!first || first->name != QStringLiteral("prototype")) { return; } AST::IdentifierExpression *constructor = AST::cast(first->base); if (!first) { return; } t = m_module->typeFromJSName(constructor->name.toString()); } if (!t) { return; } // Treat as a method definiton of a class. We can't ever be sure, but let's // try and discard later, if it turns out not to be one. - IR::Method *method = t->addMethod(lValue->name.toString()); + TypeSystem::Method *method = t->addMethod(lValue->name.toString()); AST::FormalParameterList *parameter = func->formals; while (parameter) { method->parameters << parameter->name.toString(); parameter = parameter->next; } } void TypeDefinitionVisitor::findSignalDefinition(AST::BinaryExpression *expr) { if (expr->op != QSOperator::Assign) { return; } AST::FieldMemberExpression *lValue = AST::cast(expr->left); AST::CallExpression *rValue = AST::cast(expr->right); if (!rValue || !lValue) { return; } AST::IdentifierExpression *maybeSignal = AST::cast(rValue->base); AST::ThisExpression *maybeThis = AST::cast(lValue->base); if (!maybeSignal || maybeSignal->name != QStringLiteral("QWSignal") || !maybeThis) { return; } // Ok, this is a signal definition - IR::Type *t = m_module->typeFromJSName(m_currentFunctionStack.last()->name.toString()); + TypeSystem::Type *t = m_module->typeFromJSName(m_currentFunctionStack.last()->name.toString()); assert(t, lValue->firstSourceLocation(), "Registering a signal to a type that won't get registered."); - IR::Signal *signal = t->addSignal(lValue->name.toString()); + TypeSystem::Signal *signal = t->addSignal(lValue->name.toString()); AST::ArgumentList *argumentList = rValue->arguments; if (!argumentList) { return; // Ok, no arguments, so we're done here. } AST::ArrayLiteral *arrayLit = AST::cast(argumentList->expression); assert(arrayLit, argumentList->expression->firstSourceLocation(), "Malformed Signal definition:" " First argument must be an array literal."); AST::ElementList *array = arrayLit->elements; // Go through all the elements in the list, each of which is an object // literal describing one parameter while (array) { AST::ObjectLiteral *parameterObject = AST::cast(array->expression); assert(parameterObject, array->expression->firstSourceLocation(), "Malformed Signal definition: Array elements must be object literals."); AST::PropertyAssignmentList *parameterData = parameterObject->properties; - IR::Type *type = 0; + TypeSystem::Type *type = 0; QString name; // Go through all properties of the object literal. Basically we're // looking for "type" and "name" while (parameterData) { AST::PropertyNameAndValue *nameAndValue = AST::cast(parameterData->assignment); assert(nameAndValue, parameterData->assignment->firstSourceLocation(), "Malformed Signal definition: The definition of a parameter " "must only contain name and value."); if (nameAndValue->name->asString() == QStringLiteral("type")) { AST::IdentifierExpression *t = AST::cast(nameAndValue->value); assert(t, nameAndValue->value->firstSourceLocation(), "Malformed Signal definition:" "The type definition of a parameter must be an identifier expression" "that refers to a type."); type = getType(t->name); } else if (nameAndValue->name->asString() == QStringLiteral("name")) { AST::StringLiteral *n = AST::cast(nameAndValue->value); assert(n, nameAndValue->value->firstSourceLocation(), "Malformed Signal definition:" "The name definition of a parameter must be a string literal."); name = n->value.toString(); } parameterData = parameterData->next; } signal->parameters.append({type, name}); array = array->next; } } -IR::Type *TypeDefinitionVisitor::getType(const QStringRef& name) +TypeSystem::Type *TypeDefinitionVisitor::getType(const QStringRef& name) { - IR::Type *t = 0; + TypeSystem::Type *t = 0; t = m_module->typeFromJSName(name.toString()); // TODO: Search different locations (Task T488). return t; } -JavaScriptModuleLoader *JavaScriptModuleLoader::create(IR::Module *module) +JavaScriptModuleLoader *JavaScriptModuleLoader::create(TypeSystem::Module *module) { return new JavaScriptModuleLoader(module); } -JavaScriptModuleLoader::JavaScriptModuleLoader(IR::Module *module) +JavaScriptModuleLoader::JavaScriptModuleLoader(TypeSystem::Module *module) : AbstractModuleLoader(module) {} bool JavaScriptModuleLoader::canLoad() { - IR::Module *module = AbstractModuleLoader::module(); + TypeSystem::Module *module = AbstractModuleLoader::module(); QString moduleFileName = QStringLiteral("%1.%2.%3.js").arg(module->importDescription().name) .arg(module->importDescription().versionMajor) .arg(module->importDescription().versionMinor); // For now we only support local files. const QStringList &includePaths = compiler->includePaths(); foreach (QString includePath, includePaths) { QDir includeDir(includePath); if (includeDir.exists(moduleFileName)) { m_moduleFile.setFileName(includeDir.absoluteFilePath(moduleFileName)); break; } } return m_moduleFile.exists(); } void JavaScriptModuleLoader::doLoad() { - IR::Module *module = AbstractModuleLoader::module(); + TypeSystem::Module *module = AbstractModuleLoader::module(); if (!m_moduleFile.exists()) { // We checked that already, so it should never happen. throw new Error(Error::ModuleImportError, QStringLiteral("Could not find file %1 in path.").arg(m_moduleFile.fileName())); } // Read file m_moduleFile.open(QFile::ReadOnly); QTextStream modueFileStream(&m_moduleFile); QString moduleSource = modueFileStream.readAll(); // === Parse file === // parsing happens in three steps: Calling the QQmlJS-parser to parse the // file and return an AST, then using the visit functions of this class to // collect the data we need and and third calling finalizeParse() to // evaluate the parse data and transform it to actual type information. QQmlJS::Engine* engine = new QQmlJS::Engine(); QQmlJS::Lexer* lexer = new QQmlJS::Lexer(engine); lexer->setCode(moduleSource, 1, true); QQmlJS::Parser* parser = new QQmlJS::Parser(engine); bool successfullyParsed = parser->parseProgram(); if (!successfullyParsed) { Error *err = new Error(Error::ParseError, parser->errorMessage()); err->setColumn(parser->errorColumnNumber()); 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), err); } AST::Program *ast = AST::cast(parser->rootNode()); try { RegisterModuleVisitor registerModuleVisitor(module); TypeDefinitionVisitor typeDefinitionVisitor(module); ast->accept(®isterModuleVisitor); ast->accept(&typeDefinitionVisitor); } catch (Error *e) { e->setFile(m_moduleFile.fileName()); throw e; } - module->setLoadingState(IR::Module::Successful); + module->setLoadingState(TypeSystem::Module::Successful); } diff --git a/src/qmljsc/moduleloading/javascriptmoduleloader.h b/src/qmljsc/moduleloading/javascriptmoduleloader.h index 61f63da..573f94d 100644 --- a/src/qmljsc/moduleloading/javascriptmoduleloader.h +++ b/src/qmljsc/moduleloading/javascriptmoduleloader.h @@ -1,113 +1,113 @@ /* * 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 JAVASCRIPTMODULELOADER_H #define JAVASCRIPTMODULELOADER_H // Qt #include #include // private Qt #include #include // own #include "abstractmoduleloader.h" #include "../ir/file.h" namespace QmlJSc { namespace IR { class Class; class Module; } class RegisterModuleVisitor : public QQmlJS::AST::Visitor { public: - explicit RegisterModuleVisitor(IR::Module *module); + explicit RegisterModuleVisitor(TypeSystem::Module *module); bool visit(QQmlJS::AST::CallExpression *call) override; private: - IR::Module *m_module; + TypeSystem::Module *m_module; }; class TypeDefinitionVisitor : public QQmlJS::AST::Visitor { public: - explicit TypeDefinitionVisitor(IR::Module *module); + explicit TypeDefinitionVisitor(TypeSystem::Module *module); bool visit(QQmlJS::AST::FunctionExpression*) override; void endVisit(QQmlJS::AST::FunctionExpression*) override; bool visit(QQmlJS::AST::FunctionDeclaration*) override; void endVisit(QQmlJS::AST::FunctionDeclaration*) override; bool visit(QQmlJS::AST::BinaryExpression*) override; bool visit(QQmlJS::AST::VariableDeclaration*) override; bool visit(QQmlJS::AST::CallExpression *call) override; void findPropertyDefinition(QQmlJS::AST::BinaryExpression *expr); void findMethodDefinition(QQmlJS::AST::BinaryExpression *expr); void findSignalDefinition(QQmlJS::AST::BinaryExpression *expr); /** * Looks for the type with the given name at several places and returns it, * if found or, if not, it will throw an error. * * This is used when seeing a referenced type. */ - IR::Type *getType(const QStringRef &name); + TypeSystem::Type *getType(const QStringRef &name); private: - IR::Module *m_module; + TypeSystem::Module *m_module; /** * Stack of nested functions (closures) we're in. * Each function is represented by it's AST subtree. */ QVector m_currentFunctionStack; }; /** * This class parses the javascript source of a module and analyses it for * class definitions, properties, methods, etc. to create a Module object. * * It will always run asynchronously in its own thread. * * To load a module, use the static function ModuleLoading::loadModule(). */ class JavaScriptModuleLoader : public AbstractModuleLoader { public: - static JavaScriptModuleLoader *create(IR::Module *module); + static JavaScriptModuleLoader *create(TypeSystem::Module *module); bool canLoad(); void doLoad(); private: - JavaScriptModuleLoader(IR::Module *module); + JavaScriptModuleLoader(TypeSystem::Module *module); QFile m_moduleFile; }; } // namespace QMLJSc #endif // JAVASCRIPTMODULELOADER_H diff --git a/src/qmljsc/moduleloading/moduleloading.cpp b/src/qmljsc/moduleloading/moduleloading.cpp index 5823c6c..6ba8e0d 100644 --- a/src/qmljsc/moduleloading/moduleloading.cpp +++ b/src/qmljsc/moduleloading/moduleloading.cpp @@ -1,86 +1,86 @@ /* * 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 . * */ // Own #include "moduleloading.h" #include "abstractmoduleloader.h" -#include "ir/module.h" +#include "typesystem/module.h" #include "ir/ir.h" #include "compiler.h" #include "error.h" // Qt #include #include #include #include // Qt private #include #include #include #define assert(condition, token, errorMessage) \ if (!condition) { \ assertFailed(token, errorMessage); \ } 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) +TypeSystem::Module *ModuleLoading::loadModule(IR::ImportDescription import) { Q_ASSERT(import.kind == IR::ImportDescription::Kind_ModuleImport); - if (IR::Module *module = s_loadedModules.value(import)) { + if (TypeSystem::Module *module = s_loadedModules.value(import)) { return module; } - IR::Module *module = new IR::Module(import, compiler); + TypeSystem::Module *module = new TypeSystem::Module(import, compiler); s_loadedModules.insert(import, module); AbstractModuleLoader *loader = 0; foreach (ModuleLoaderFactoryFunc createLoaderFor, s_moduleLoaderFactories) { loader = createLoaderFor(module); // will delete itself when done if (loader->canLoad()) { break; } else { delete loader; loader = 0; } } if (!loader) { throw new Error(Error::ModuleImportError, QStringLiteral("Module %1 %2.%3 was not " "found. Check if it is installed and include paths are correctly set")); } QThreadPool::globalInstance()->start(loader); return module; } void ModuleLoading::registerModuleLoader(ModuleLoaderFactoryFunc factory) { s_moduleLoaderFactories.append(factory); } diff --git a/src/qmljsc/moduleloading/moduleloading.h b/src/qmljsc/moduleloading/moduleloading.h index 68db9b5..dda532a 100644 --- a/src/qmljsc/moduleloading/moduleloading.h +++ b/src/qmljsc/moduleloading/moduleloading.h @@ -1,65 +1,65 @@ /* * 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 MODULELOADING_H #define MODULELOADING_H // Qt #include // std #include // own #include "../ir/file.h" namespace QmlJSc { namespace IR { class Class; } class AbstractModuleLoader; -typedef std::function ModuleLoaderFactoryFunc; +typedef std::function ModuleLoaderFactoryFunc; class ModuleLoading { public: /** * Initializes module loading. * Creates a AbstractModuleLoader object and runs it through QThreadPool. * Beware, that it is an asynchronous function and returns a valid but * uncompleted Module as soon as loading *started* (not when finished). * * This function is to be called from the compile-unit thread. */ - static IR::Module *loadModule(IR::ImportDescription import); + static TypeSystem::Module *loadModule(IR::ImportDescription import); static void registerModuleLoader(ModuleLoaderFactoryFunc factory); private: - static QHash s_loadedModules; + static QHash s_loadedModules; static QVector s_moduleLoaderFactories; }; } // namespace QMLJSc #endif // MODULELOADING_H diff --git a/src/qmljsc/ir/module.cpp b/src/qmljsc/typesystem/module.cpp similarity index 94% rename from src/qmljsc/ir/module.cpp rename to src/qmljsc/typesystem/module.cpp index 7546cbb..ad05f8c 100644 --- a/src/qmljsc/ir/module.cpp +++ b/src/qmljsc/typesystem/module.cpp @@ -1,109 +1,109 @@ /* * 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 . * */ // Own #include "module.h" #include "../compiler.h" #include "../error.h" // Qt #include #include #include #include // Qt private #include #include #include using namespace QmlJSc; -using namespace QmlJSc::IR; +using namespace QmlJSc::TypeSystem; using namespace QQmlJS::AST; -Module::Module(ImportDescription import, QObject *parent) +Module::Module(IR::ImportDescription import, QObject *parent) : m_importDescription(import) , m_loadingState(Loading) { } Module::~Module() { foreach (Type *type, m_types) { delete type; } } Module::LoadingState Module::loadingState() { return m_loadingState; } void Module::setLoadingState(Module::LoadingState status) { Q_ASSERT_X(m_loadingState == Loading, __FILE__, "It's not allowed to change status after loading finished."); m_loadingState = status; if (m_loadingState == Successful || m_loadingState == ErrorState) { m_loadFinishedCondition.wakeAll(); } } const QString &Module::name() { return m_importDescription.name; } Type *Module::type(QString name) { waitForLoaded(); return m_types.value(name); } Type *Module::typeFromJSName(QString name) { return m_jsNameToTypeHash.value(name); } void Module::addType(Type *type) { Q_ASSERT_X(m_loadingState == Loading, __FILE__, "It's not allowed to add types after loading finished."); m_types.insert(type->name(), type); m_jsNameToTypeHash.insert(type->javaScriptName(), type); } void Module::waitForLoaded() { if (m_loadingState != Loading) return; m_loadMutex.lock(); m_loadFinishedCondition.wait(&m_loadMutex); m_loadMutex.unlock(); } -ImportDescription Module::importDescription() +IR::ImportDescription Module::importDescription() { return m_importDescription; } diff --git a/src/qmljsc/ir/module.h b/src/qmljsc/typesystem/module.h similarity index 90% rename from src/qmljsc/ir/module.h rename to src/qmljsc/typesystem/module.h index 2ef3c25..8924a88 100644 --- a/src/qmljsc/ir/module.h +++ b/src/qmljsc/typesystem/module.h @@ -1,90 +1,90 @@ /* * 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 MODULE_H #define MODULE_H -#include "file.h" +#include "../ir/file.h" namespace QmlJSc { class ModuleLoader; -namespace IR { +namespace TypeSystem { /** * This class provides API representing a Qml.js module and allows to learn * about the modules API. * * Therefore it parses the javascript source of the module and analyses it for * class definitions, properties, methods, etc. */ class Module { public: enum LoadingState { Loading, Successful, ErrorState }; - explicit Module(ImportDescription import, QObject *parent = 0); + explicit Module(IR::ImportDescription import, QObject *parent = 0); ~Module(); LoadingState loadingState(); void setLoadingState(LoadingState status); void waitForLoaded(); /** * Returns the type object for the (QML-) name. * * If the data isn't available, yet, because the module is still loading, * this function will block until the data is available. */ Type *type(QString name); /** * Returns the type object for the name it has in JS code. * * This function won't wait for the data to be available, only use this * function if you're certain about it! */ Type *typeFromJSName(QString name); const QString &name(); void addType(Type *type); - ImportDescription importDescription(); + IR::ImportDescription importDescription(); private: QHash m_types; QHash m_jsNameToTypeHash; - ImportDescription m_importDescription; + IR::ImportDescription m_importDescription; LoadingState m_loadingState; QWaitCondition m_loadFinishedCondition; QMutex m_loadMutex; }; -} // namespace IR +} // namespace TypeSystem } // namespace QMLJSc #endif // MODULE_H diff --git a/src/qmljsc/typesystem/typesystem.cpp b/src/qmljsc/typesystem/typesystem.cpp new file mode 100644 index 0000000..d90760b --- /dev/null +++ b/src/qmljsc/typesystem/typesystem.cpp @@ -0,0 +1,153 @@ +/* + * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. + * + * Copyright (C) 2015 Anton Kreuzkamp + * 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 "typesystem.h" + +using namespace QmlJSc::TypeSystem; + +Type::Type() + : m_super(0) +{ +} + +const QString &Type::name() +{ + return m_name; +} + +const QString &Type::javaScriptName() +{ + return m_javaScriptName; +} + +Property *Type::addProperty(const QString &name) +{ + return &m_properties.insert(name, Property(name)).value(); +} + +Method *Type::addMethod(const QString &name) +{ + return &m_methods.insert(name, Method(name)).value(); +} + +Signal *Type::addSignal(const QString &name) +{ + return &m_signals.insert(name, Signal(name)).value(); +} + +void Type::setName(const QString &name) +{ + m_name = name; +} + +void Type::setJavaScriptName(const QString &jsName) +{ + m_javaScriptName = jsName; +} + +Property *Type::property(const QString &name) +{ + if (m_properties.contains(name)) { + return &m_properties[name]; + } + if (m_super) { + return m_super->property(name); + } + return 0; +} + +Method *Type::method(const QString &name) +{ + if (m_methods.contains(name)) { + return &m_methods[name]; + } + if (m_super) { + return m_super->method(name); + } + return 0; +} + +Signal *Type::signal(const QString &name) +{ + if (m_signals.contains(name)) { + return &m_signals[name]; + } + if (m_super) { + return m_super->signal(name); + } + return 0; +} + +Type *Type::super() { + return m_super; +} + +void Type::setSuper(Type *superType) { + m_super = superType; +} + +LibraryClass::LibraryClass() + : Type() +{ +} + +Method::Method() + : returnType(0) +{ +} + +Method::Method(const QString &name) + : returnType(0) + , name(name) +{ +} + +Method::Method(Type *returnType, QString name) + : returnType(returnType) + , name(name) +{ +} + +Signal::Signal() +{ +} + +Signal::Signal(QString name) + : name(name) +{ +} + +Property::Property() + : type(0) +{ +} + +Property::Property(const QString &name) + : type(0) + , name(name) +{ +} + +Property::Property(Type *type, QString name) + : type(type) + , name(name) +{ +} \ No newline at end of file diff --git a/src/qmljsc/typesystem/typesystem.h b/src/qmljsc/typesystem/typesystem.h new file mode 100644 index 0000000..515bd00 --- /dev/null +++ b/src/qmljsc/typesystem/typesystem.h @@ -0,0 +1,138 @@ +/* + * Qml.js Compiler - a QML to JS compiler bringing QML's power to the web. + * + * Copyright (C) 2015 Anton Kreuzkamp + * 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 TYPESYSTEM_H +#define TYPESYSTEM_H + +#include +#include +#include + +namespace QQmlJS { + namespace AST { + class ExpressionNode; + } +} + +namespace QmlJSc { +namespace TypeSystem { + +class Property; +class Method; +class Signal; + +/** + * This class provides API representing Qml.js objects and types and allows to + * learn about the type's properties, functions, etc. + * + * Type hereby refers to (built in) basic types, types provided by modules and + * components as well as any objects defined in QML. + */ +class Type +{ +public: + Type(); + + const QString &name(); + const QString &javaScriptName(); + Property *property(const QString &name); + Method *method(const QString &name); + Signal *signal(const QString &name); + + Property *addProperty(const QString &name); + Method *addMethod(const QString &name); + Signal *addSignal(const QString &name); + + void setName(const QString &name); + void setJavaScriptName(const QString &jsName); + + Type *super(); + void setSuper(Type *superType); + +protected: + QString m_name; + QString m_javaScriptName; + QHash m_properties; + QHash m_methods; + QHash m_signals; + + /** + * pointer to the super class or in case of objects the class of the object + */ + Type *m_super; + + + friend class TestIR; +}; + +class LibraryClass : public Type +{ +public: + LibraryClass(); + +private: + Type *m_attached; +}; + +struct Parameter { + Type *type; + QString name; +}; + +class Method { +public: + Method(); + Method(const QString &name); + Method(Type *returnType, QString name); + + Type *returnType; + QString name; + QVector parameters; +}; + +class Signal { +public: + Signal(); + Signal(QString name); + + QString name; + QVector parameters; +}; + +class Property { +public: + Property(); + Property(const QString &name); + Property(Type *type, QString name); + + Type *type; + QString name; + + bool readOnly :1; + bool constant :1; + bool dummy :6; +}; + +} // namespace TypeSystem +} // namespace QmlJSc + +#endif // TYPESYSTEM_H + diff --git a/tests/auto/qmljsc/testir.cpp b/tests/auto/qmljsc/testir.cpp index f526e7c..abff57f 100644 --- a/tests/auto/qmljsc/testir.cpp +++ b/tests/auto/qmljsc/testir.cpp @@ -1,436 +1,397 @@ /* * 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 . * */ #include #include #include #include #include "../../../src/qmljsc/compiler.h" #include "../../../src/qmljsc/ir/ir.h" #include "../../../src/qmljsc/ir/visitor.h" +#include "../../../src/qmljsc/typesystem/typesystem.h" // Qt private #include namespace QmlJSc { namespace IR { class TestIR : public QObject { Q_OBJECT public: TestIR(); private slots: void initTestCase(); void testBasics(); void testAdd(); void testAsSymbolTable(); void testVisitorAPI(); private: - Class city; + TypeSystem::LibraryClass city; Object christiania; Object copenhagen; - Class state; - Class democracy; + TypeSystem::LibraryClass state; + TypeSystem::LibraryClass democracy; Object ottomanEmpire; Object denmark; QString christianiaName; QString copenhagenName; QString ottomanEmpireName; QString ottomanEmpireLanguage; QString denmarkName; QString denmarkLanguage; QString denmarkRParty; QStringRef christianiaNameRef; QStringRef copenhagenNameRef; QStringRef ottomanEmpireNameRef; QStringRef ottomanEmpireLangRef; QStringRef denmarkNameRef; QStringRef denmarkLangRef; QStringRef denmarkRPartyRef; QQmlJS::AST::StringLiteral christianiaNameNode; QQmlJS::AST::StringLiteral copenhagenNameNode; QQmlJS::AST::StringLiteral ottomanEmpireNameNode; QQmlJS::AST::StringLiteral ottomanEmpireLangNode; QQmlJS::AST::StringLiteral denmarkNameNode; QQmlJS::AST::StringLiteral denmarkLangNode; QQmlJS::AST::StringLiteral denmarkRPartyNode; QQmlJS::AST::NumericLiteral christianiaPostCodeNode; }; TestIR::TestIR() : QObject() , christianiaName(QStringLiteral("Fristad Christiania")) , copenhagenName(QStringLiteral("København")) , ottomanEmpireName(QStringLiteral("Osmanlı İmparatorluğu")) , ottomanEmpireLanguage(QStringLiteral("Ottoman Turkish")) , denmarkName(QStringLiteral("Danmark")) , denmarkLanguage(QStringLiteral("Danish")) , denmarkRParty(QStringLiteral("S-RV")) , christianiaNameRef(&christianiaName) , copenhagenNameRef(&copenhagenName) , ottomanEmpireNameRef(&ottomanEmpireName) , ottomanEmpireLangRef(&ottomanEmpireLanguage) , denmarkNameRef(&denmarkName) , denmarkLangRef(&denmarkLanguage) , denmarkRPartyRef(&denmarkRParty) , christianiaNameNode(christianiaNameRef) , copenhagenNameNode(copenhagenNameRef) , ottomanEmpireNameNode(ottomanEmpireNameRef) , ottomanEmpireLangNode(ottomanEmpireLangRef) , denmarkNameNode(denmarkNameRef) , denmarkLangNode(denmarkLangRef) , denmarkRPartyNode(denmarkRPartyRef) , christianiaPostCodeNode(1050) { } void TestIR::initTestCase() { city.m_name = "City"; city.m_properties = { {"name", {0,"name"}}, {"postCode", {0,"postCode"}} }; city.m_methods = { {"visit", {0, "visit"}}, }; state.m_name = "State"; state.m_properties = { {"name", {0,"name"}}, {"language", {0,"language"}}, {"capital", {&city, "capital"}} }; state.m_methods = { {"visit", {0, "visit"}}, }; Signal isOffensive("warStarted"); isOffensive.parameters.append({0, "isOffensive"}); state.m_signals = { {"warStarted", isOffensive}, }; democracy.m_name = "Democracy"; democracy.m_super = &state; democracy.m_properties = { {"reigningParty", {0,"reigningParty"}}, }; democracy.m_methods = { {"elect", {0, "elect"}}, }; democracy.m_signals = { {"lawAdopted", {"lawAdopted"}}, }; copenhagen.m_super = &city; christiania.m_super = &city; ottomanEmpire.m_name = "OttomanEmpire"; ottomanEmpire.m_super = &state; ottomanEmpire.m_methods = { {"capital", {0, "capital"}}, // Capital for year, overrides property capital. }; ottomanEmpire.m_valueAssignments = { {&state.m_properties["name"], 0, &ottomanEmpireNameNode}, {&state.m_properties["language"], 0, &ottomanEmpireLangNode} }; denmark.m_name = "Denmark"; denmark.m_super = &democracy; } void TestIR::testBasics() { - QCOMPARE(city.kind(), Type::Kind_Class); - QCOMPARE(city.name(), QStringLiteral("City")); - QVERIFY(city.property("name")); - QCOMPARE(city.property("name")->name, QStringLiteral("name")); - QVERIFY(city.property("postCode")); - QVERIFY(city.property("postCode") == city.property("postCode")); // Check that no copying happens - QVERIFY(!city.property("capital")); - QVERIFY(!city.property("visit")); - QVERIFY(city.method("visit")); - QCOMPARE(city.method("visit")->name, QStringLiteral("visit")); - QVERIFY(city.method("visit") == city.method("visit")); // Check that no copying happens - - QCOMPARE(state.kind(), Type::Kind_Class); - QCOMPARE(state.name(), QStringLiteral("State")); - QVERIFY(state.property("name")); - QCOMPARE(state.property("name")->name, QStringLiteral("name")); - QVERIFY(state.property("language")); - QVERIFY(state.property("capital")); - QCOMPARE(state.property("capital")->type, &city); - QCOMPARE(state.property("capital")->type->name(), QStringLiteral("City")); - QVERIFY(!state.property("reigningParty")); - QVERIFY(!state.property("postCode")); - QVERIFY(state.method("visit")); - QVERIFY(state.method("visit") != city.method("visit")); - QVERIFY(state.signal("warStarted")); - QVERIFY(state.signal("warStarted") == state.signal("warStarted")); // Check that no copying happens - QCOMPARE(state.signal("warStarted")->name, QStringLiteral("warStarted")); - QCOMPARE(state.signal("warStarted")->parameters[0].name, QStringLiteral("isOffensive")); - - QCOMPARE(democracy.kind(), Type::Kind_Class); - QCOMPARE(democracy.name(), QStringLiteral("Democracy")); - QVERIFY(democracy.property("name")); - QCOMPARE(democracy.property("name")->name, QStringLiteral("name")); - QVERIFY(democracy.property("language")); - QVERIFY(democracy.property("capital")); - QCOMPARE(democracy.property("capital")->type, &city); - QCOMPARE(democracy.property("capital")->type->name(), QStringLiteral("City")); - QVERIFY(democracy.property("reigningParty")); - QVERIFY(!democracy.property("postCode")); - QCOMPARE(ottomanEmpire.kind(), Type::Kind_Object); QCOMPARE(ottomanEmpire.name(), QStringLiteral("OttomanEmpire")); QVERIFY(ottomanEmpire.property("name")); QVERIFY(!ottomanEmpire.property("reigningParty")); QVERIFY(!ottomanEmpire.property("postCode")); QCOMPARE(ottomanEmpire.valueAssignments().count(), 2); QCOMPARE(ottomanEmpire.valueAssignments()[0].property, &state.m_properties["name"]); QCOMPARE(reinterpret_cast( ottomanEmpire.valueAssignments()[0].jsValue)->value.toString(), QStringLiteral("Osmanlı İmparatorluğu")); } void TestIR::testAdd() { ValueAssignment *denmarkNameAssignment = denmark.addValueAssignment(); denmarkNameAssignment->property = &state.m_properties["name"]; denmarkNameAssignment->jsValue = &denmarkNameNode; ValueAssignment *denmarkLanguageAssignment = denmark.addValueAssignment(); denmarkLanguageAssignment->property = &state.m_properties["language"]; denmarkLanguageAssignment->jsValue = &denmarkLangNode; ValueAssignment *denmarkCapitalAssignment = denmark.addValueAssignment(); denmarkCapitalAssignment->property = &state.m_properties["capital"]; denmarkCapitalAssignment->objectValue = &copenhagen; ValueAssignment *denmarkReigningPartyAssignment = denmark.addValueAssignment(); denmarkReigningPartyAssignment->property = &democracy.m_properties["reigningParty"]; denmarkReigningPartyAssignment->jsValue = &denmarkRPartyNode; Property *christianiaProperty = copenhagen.addProperty("christiania"); christianiaProperty->type = &city; christianiaProperty->objectValue = &christiania; ValueAssignment *copenhagenNameAssignment = copenhagen.addValueAssignment(); copenhagenNameAssignment->property = &city.m_properties["name"]; copenhagenNameAssignment->jsValue = &copenhagenNameNode; Method *buyWeed = christiania.addMethod("buyWeed"); Signal *policeRaid = christiania.addSignal("policeRaid"); ValueAssignment *christianiaNameAssignment = christiania.addValueAssignment(); christianiaNameAssignment->property = &city.m_properties["name"]; christianiaNameAssignment->jsValue = &christianiaNameNode; ValueAssignment *christianiaPostCodeAssignment = christiania.addValueAssignment(); christianiaPostCodeAssignment->property = &city.m_properties["postCode"]; christianiaPostCodeAssignment->jsValue = &christianiaPostCodeNode; QCOMPARE(denmark.kind(), Type::Kind_Object); QVERIFY(denmark.property("capital")); QVERIFY(denmark.property("reigningParty")); QVERIFY(!denmark.property("postCode")); QCOMPARE(denmark.valueAssignments().count(), 4); QVERIFY(denmark.valueAssignments()[2].property); QVERIFY(denmark.valueAssignments()[2].property == denmark.valueAssignments()[2].property); QCOMPARE(denmark.valueAssignments()[3].property, &democracy.m_properties["reigningParty"]); QCOMPARE(reinterpret_cast( denmark.valueAssignments()[3].jsValue)->value.toString(), QStringLiteral("S-RV")); QCOMPARE(copenhagen.kind(), Type::Kind_Object); QVERIFY(copenhagen.property("name")); QVERIFY(copenhagen.property("christiania")); QCOMPARE(copenhagen.property("christiania")->objectValue, &christiania); QCOMPARE(copenhagen.valueAssignments().count(), 1); QVERIFY(christiania.method("visit")); QVERIFY(christiania.method("buyWeed")); QCOMPARE(christiania.method("buyWeed")->name, QStringLiteral("buyWeed")); QVERIFY(christiania.method("buyWeed") == buyWeed); // Check that no copying happens QVERIFY(christiania.signal("policeRaid")); QCOMPARE(christiania.signal("policeRaid")->name, QStringLiteral("policeRaid")); QVERIFY(christiania.signal("policeRaid") == policeRaid); // Check that no copying happens } void TestIR::testAsSymbolTable() { QVERIFY(ottomanEmpire.member("name")); QCOMPARE(ottomanEmpire.member("name")->kind, Node::Kind_Property); QVERIFY(ottomanEmpire.member("visit")); QCOMPARE(ottomanEmpire.member("visit")->kind, Node::Kind_Method); QVERIFY(ottomanEmpire.member("warStarted")); QCOMPARE(ottomanEmpire.member("warStarted")->kind, Node::Kind_Signal); QCOMPARE(state.member("capital")->kind, Node::Kind_Property); QCOMPARE(ottomanEmpire.member("capital")->kind, Node::Kind_Method); QVERIFY(ottomanEmpire.member("capital") != state.member("capital")); } class TestVisitor : public Visitor { public: TestVisitor() : Visitor() , objectsVisited(0) , propertiesVisited(0) , methodsVisited(0) , signalsVisited(0) , currentDepth(0) , valueAssignmentsVisited(0) , bindingAssignmentsVisited(0) , lastValueAssigned(0) {} virtual void visit(Type *type) { currentDepth++; } virtual void visit(Object *object) { currentDepth++; objectsVisited++; } virtual void visit(Component *component) { currentDepth++; objectsVisited++; } virtual void visit(Class *_class) { currentDepth++; objectsVisited++; } virtual void visit(Symbol *symbol) { currentDepth++; } virtual void visit(Property *property) { currentDepth++; propertiesVisited++; lastPropertyVisited = property->name; } virtual void visit(Method *method) { currentDepth++; methodsVisited++; } virtual void visit(Signal *signal) { currentDepth++; signalsVisited++; } virtual void visit(ValueAssignment *valueAssignment) { currentDepth++; valueAssignmentsVisited++; lastValueAssigned = valueAssignment->jsValue; } virtual void visit(BindingAssignment *bindingAssignment) { currentDepth++; bindingAssignmentsVisited++; } virtual void endVisit(Type *type) { currentDepth--; } virtual void endVisit(Object *object) { currentDepth--; } virtual void endVisit(Component *component) { currentDepth--; } virtual void endVisit(Class *_class) { currentDepth--; } virtual void endVisit(Symbol *symbol) { currentDepth--; } virtual void endVisit(Property *property) { currentDepth--; } virtual void endVisit(Method *method) { currentDepth--; } virtual void endVisit(Signal *signal) { currentDepth--; } virtual void endVisit(ValueAssignment *valueAssignment) { currentDepth--; } virtual void endVisit(BindingAssignment *bindingAssignment) { currentDepth--; } int objectsVisited; int propertiesVisited; int methodsVisited; int signalsVisited; int valueAssignmentsVisited; int bindingAssignmentsVisited; int currentDepth; QString lastPropertyVisited; QQmlJS::AST::ExpressionNode *lastValueAssigned; }; void TestIR::testVisitorAPI() { TestVisitor visitor; copenhagen.accept(&visitor); QCOMPARE(visitor.currentDepth, 0); QCOMPARE(visitor.objectsVisited, 2); QCOMPARE(visitor.propertiesVisited, 1); QCOMPARE(visitor.methodsVisited, 1); QCOMPARE(visitor.signalsVisited, 1); QCOMPARE(visitor.valueAssignmentsVisited, 3); QCOMPARE(visitor.bindingAssignmentsVisited, 0); QCOMPARE(visitor.lastPropertyVisited, QStringLiteral("christiania")); QCOMPARE(visitor.lastValueAssigned->kind, (int)QQmlJS::AST::Node::Kind_StringLiteral); QQmlJS::AST::StringLiteral* lastValueAssigned = QQmlJS::AST::cast(visitor.lastValueAssigned); if (lastValueAssigned) QCOMPARE(lastValueAssigned->value.toString(), QStringLiteral("København")); } } // namespace IR } // namespace QMLJSc QTEST_MAIN(QmlJSc::IR::TestIR) #include "testir.moc" diff --git a/tests/auto/qmljsc/testmodules.cpp b/tests/auto/qmljsc/testmodules.cpp index 657e6fe..4388933 100644 --- a/tests/auto/qmljsc/testmodules.cpp +++ b/tests/auto/qmljsc/testmodules.cpp @@ -1,261 +1,261 @@ /* * 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 . * */ // Qt #include #include #include #include // Qt private #include // own #include "../../../src/qmljsc/compiler.h" #include "../../../src/qmljsc/moduleloading/moduleloading.h" #include "../../../src/qmljsc/moduleloading/javascriptmoduleloader.h" -#include "../../../src/qmljsc/ir/module.h" +#include "../../../src/qmljsc/typesystem/module.h" class TestModules : public QObject { Q_OBJECT private slots: void loadMinimalModule(); void loadModule(); void testShortSymbolName(); }; using namespace QmlJSc; using namespace QmlJSc::IR; using namespace QQmlJS; void TestModules::loadMinimalModule() { Compiler comp; ModuleLoading::registerModuleLoader(&JavaScriptModuleLoader::create); const ImportDescription testImportDescription = {ImportDescription::Kind_ModuleImport, "MinimalModule", 0, 1}; compiler->addIncludePath(":/test/"); IR::Module *module = ModuleLoading::loadModule(testImportDescription); module->waitForLoaded(); Type *a = module->type("A"); Type *b = module->type("B"); Type *c = module->type("C"); Type *d = module->type("D"); Type *e = module->type("E"); QCOMPARE((int)module->loadingState(), (int)Module::Successful); QVERIFY(a); QVERIFY(b); QVERIFY(c); QVERIFY(d); QVERIFY(!e); QCOMPARE(a->name(), QStringLiteral("A")); QCOMPARE(b->name(), QStringLiteral("B")); QCOMPARE(c->name(), QStringLiteral("C")); QCOMPARE(d->name(), QStringLiteral("D")); QVERIFY(b->property("minimalProp")); QVERIFY(c->property("otherPropWithType")); QVERIFY(c->property("yaPropWithType")); QVERIFY(d->property("readonlyProp")); QVERIFY(d->property("otherPropWithType")); QVERIFY(!d->property("yaPropWithType")); - IR::Property *readonlyProp = d->property("readonlyProp"); + TypeSystem::Property *readonlyProp = d->property("readonlyProp"); QVERIFY(readonlyProp); QCOMPARE(readonlyProp->type, d); QCOMPARE(readonlyProp->readOnly, true); QCOMPARE(readonlyProp->jsValue->kind, (int)AST::Node::Kind_FalseLiteral); - IR::Method *prototypeMethod = b->method("prototypeMethod"); + TypeSystem::Method *prototypeMethod = b->method("prototypeMethod"); QVERIFY(prototypeMethod); QCOMPARE(prototypeMethod->name, QStringLiteral("prototypeMethod")); - IR::Method *bPrototypeMethod = b->method("prototypeMethod"); + TypeSystem::Method *bPrototypeMethod = b->method("prototypeMethod"); QVERIFY(bPrototypeMethod); QCOMPARE(bPrototypeMethod->parameters.size(), 0); - IR::Method *bPrototypeMethod2 = b->method("prototypeMethod2"); + TypeSystem::Method *bPrototypeMethod2 = b->method("prototypeMethod2"); QVERIFY(bPrototypeMethod2); QCOMPARE(bPrototypeMethod2->parameters.size(), 1); QCOMPARE(bPrototypeMethod2->parameters[0], QStringLiteral("prop")); - IR::Method *bConstructorMethod = b->method("constructorMethod"); + TypeSystem::Method *bConstructorMethod = b->method("constructorMethod"); QVERIFY(bConstructorMethod); QCOMPARE(bConstructorMethod->parameters.size(), 2); QCOMPARE(bConstructorMethod->parameters[0], QStringLiteral("prop1")); QCOMPARE(bConstructorMethod->parameters[1], QStringLiteral("prop2")); QVERIFY(c->method("prototypeMethod")); QVERIFY(c->method("constructorMethod")); QVERIFY(d->method("prototypeMethod")); QVERIFY(d->method("constructorMethod")); - IR::Signal *someSignal = d->signal("someSignal"); + TypeSystem::Signal *someSignal = d->signal("someSignal"); QVERIFY(someSignal); QCOMPARE(someSignal->parameters.size(), 0); - IR::Signal *anotherSignal = d->signal("anotherSignal"); + TypeSystem::Signal *anotherSignal = d->signal("anotherSignal"); QVERIFY(anotherSignal); QCOMPARE(anotherSignal->parameters.size(), 2); QCOMPARE(anotherSignal->parameters[0].name, QStringLiteral("arg1")); QCOMPARE(anotherSignal->parameters[0].type, a); QCOMPARE(anotherSignal->parameters[1].name, QStringLiteral("arg2")); QCOMPARE(anotherSignal->parameters[1].type, a); } void TestModules::loadModule() { QSKIP("This will be implemented later (Task T488)."); Compiler c; const ImportDescription testImportDescription = {ImportDescription::Kind_ModuleImport, "TestModule", 0, 1}; compiler->addIncludePath(":/test/"); IR::Module *module = ModuleLoading::loadModule(testImportDescription); module->waitForLoaded(); Type *pastry = module->type("Pastry"); Type *cake = module->type("Cake"); Type *pizza = module->type("Pizza"); Type *printer = module->type("Printer"); QVERIFY(module->loadingState() == Module::Successful); QVERIFY(pastry); QVERIFY(cake); QVERIFY(pizza); QVERIFY(!printer); QCOMPARE(pastry->name(), QStringLiteral("Pastry")); QCOMPARE(cake->name(), QStringLiteral("Cake")); QCOMPARE(pizza->name(), QStringLiteral("Pizza")); QVERIFY(pastry->property("bakingTime")); QVERIFY(cake->property("containsRawEgg")); QVERIFY(cake->property("bakingTime")); QVERIFY(pizza->property("isCalzone")); QVERIFY(pizza->property("topping")); QVERIFY(!pizza->property("containsRawEgg")); - IR::Property *baked = pizza->property("baked"); + TypeSystem::Property *baked = pizza->property("baked"); QVERIFY(baked); QCOMPARE(baked->readOnly, true); QCOMPARE(baked->jsValue->kind, (int)AST::Node::Kind_FalseLiteral); QVERIFY(pastry->method("eat")); QVERIFY(pastry->method("bake")); QVERIFY(pizza->method("eat")); QVERIFY(pizza->method("bake")); QVERIFY(pizza->signal("bakingFinished")); } void TestModules::testShortSymbolName() { ShortSymbolName nA('A'); ShortSymbolName nB('B'); ShortSymbolName nZ('Z'); ShortSymbolName na('a'); ShortSymbolName nb('b'); ShortSymbolName nz('z'); ShortSymbolName nA0("A0"); ShortSymbolName nA1("A1"); ShortSymbolName nA9("A9"); ShortSymbolName nAA("AA"); ShortSymbolName nAB("AB"); ShortSymbolName nAZ("AZ"); ShortSymbolName nAa("Aa"); ShortSymbolName nAb("Ab"); ShortSymbolName nAz("Az"); ShortSymbolName na0("a0"); ShortSymbolName na1("a1"); ShortSymbolName na9("a9"); ShortSymbolName naA("aA"); ShortSymbolName naB("aB"); ShortSymbolName naZ("aZ"); ShortSymbolName naa("aa"); ShortSymbolName nab("ab"); ShortSymbolName naz("az"); ShortSymbolName nZ9("Z9"); ShortSymbolName nZZ("ZZ"); ShortSymbolName nZz("Zz"); ShortSymbolName nz9("z9"); ShortSymbolName nzZ("zZ"); ShortSymbolName nzz("zz"); ShortSymbolName nA5dh("A5dh"); ShortSymbolName nA5dz("A5dz"); ShortSymbolName nA5zz("A5zz"); ShortSymbolName nAzzz("Azzz"); ShortSymbolName nZzzz("Zzzz"); ShortSymbolName nzzzz("zzzz"); QCOMPARE(static_cast(++nA), QStringLiteral("B")); QCOMPARE(static_cast(++nB), QStringLiteral("C")); QCOMPARE(static_cast(++nZ), QStringLiteral("A0")); QCOMPARE(static_cast(++na), QStringLiteral("b")); QCOMPARE(static_cast(++nb), QStringLiteral("c")); QCOMPARE(static_cast(++nz), QStringLiteral("a0")); QCOMPARE(static_cast(++nA0), QStringLiteral("A1")); QCOMPARE(static_cast(++nA1), QStringLiteral("A2")); QCOMPARE(static_cast(++nA9), QStringLiteral("AA")); QCOMPARE(static_cast(++nAA), QStringLiteral("AB")); QCOMPARE(static_cast(++nAB), QStringLiteral("AC")); QCOMPARE(static_cast(++nAZ), QStringLiteral("Aa")); QCOMPARE(static_cast(++nAa), QStringLiteral("Ab")); QCOMPARE(static_cast(++nAb), QStringLiteral("Ac")); QCOMPARE(static_cast(++nAz), QStringLiteral("B0")); QCOMPARE(static_cast(++na0), QStringLiteral("a1")); QCOMPARE(static_cast(++na1), QStringLiteral("a2")); QCOMPARE(static_cast(++na9), QStringLiteral("aA")); QCOMPARE(static_cast(++naA), QStringLiteral("aB")); QCOMPARE(static_cast(++naB), QStringLiteral("aC")); QCOMPARE(static_cast(++naZ), QStringLiteral("aa")); QCOMPARE(static_cast(++naa), QStringLiteral("ab")); QCOMPARE(static_cast(++nab), QStringLiteral("ac")); QCOMPARE(static_cast(++naz), QStringLiteral("b0")); QCOMPARE(static_cast(++nZ9), QStringLiteral("ZA")); QCOMPARE(static_cast(++nZZ), QStringLiteral("Za")); QCOMPARE(static_cast(++nZz), QStringLiteral("A00")); QCOMPARE(static_cast(++nz9), QStringLiteral("zA")); QCOMPARE(static_cast(++nzZ), QStringLiteral("za")); QCOMPARE(static_cast(++nzz), QStringLiteral("a00")); QCOMPARE(static_cast(++nA5dh), QStringLiteral("A5di")); QCOMPARE(static_cast(++nA5dz), QStringLiteral("A5e0")); QCOMPARE(static_cast(++nA5zz), QStringLiteral("A600")); QCOMPARE(static_cast(++nAzzz), QStringLiteral("B000")); QCOMPARE(static_cast(++nZzzz), QStringLiteral("A0000")); QCOMPARE(static_cast(++nzzzz), QStringLiteral("a0000")); } QTEST_MAIN(TestModules) #include "testmodules.moc" diff --git a/tests/auto/qmljsc/testprettygeneratorpass.cpp b/tests/auto/qmljsc/testprettygeneratorpass.cpp index 1f1c5b9..962e82b 100644 --- a/tests/auto/qmljsc/testprettygeneratorpass.cpp +++ b/tests/auto/qmljsc/testprettygeneratorpass.cpp @@ -1,148 +1,150 @@ /* * 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 #include #include #include #include "../../../src/qmljsc/ir/ir.h" #include "../../../src/qmljsc/compiler.h" #include "../../../src/qmljsc/compilerpasses/prettygeneratorpass.h" template -class TestNodeComponent : public QmlJSc::IR::Component +class TestNodeFile : public QmlJSc::IR::File { public: - TestNodeComponent(TestedVisitorNodeType& testedNode) + TestNodeFile(TestedVisitorNodeType& testedNode) : m_testedNode(testedNode) { } virtual void accept(QmlJSc::IR::Visitor* visitor) override { m_testedNode.accept(visitor); } private: TestedVisitorNodeType& m_testedNode; }; class TestPrettyGeneratorPass : public QObject { Q_OBJECT private: void initBasicTypes(); QString readTestFileContent(const char* fileName); QmlJSc::PrettyGeneratorPass* m_prettyGeneratorPass = Q_NULLPTR; QString m_result; - QmlJSc::IR::Class* m_qtObjectType = Q_NULLPTR; + QmlJSc::TypeSystem::LibraryClass* m_qtObjectType = Q_NULLPTR; private slots: void setResult(QString); private slots: void initTestCase(); void init(); void emitsFinishedSignal(); - void visitComponent(); + void visitFile(); }; void TestPrettyGeneratorPass::setResult(QString result) { if (!m_result.isEmpty()) { QFAIL("finished emitted multiple times"); } else { m_result = result; } } void TestPrettyGeneratorPass::initTestCase() { initBasicTypes(); } void TestPrettyGeneratorPass::initBasicTypes() { - QmlJSc::IR::Type* stringType = new QmlJSc::IR::Type(); + QmlJSc::TypeSystem::Type* stringType = new QmlJSc::TypeSystem::Type(); stringType->setName("string"); - m_qtObjectType = new QmlJSc::IR::Class(); + m_qtObjectType = new QmlJSc::TypeSystem::LibraryClass(); m_qtObjectType->setName("QtObject"); - QmlJSc::IR::Property *p = m_qtObjectType->addProperty("objectName"); + QmlJSc::TypeSystem::Property *p = m_qtObjectType->addProperty("objectName"); p->type = stringType; } QString TestPrettyGeneratorPass::readTestFileContent(const char *fileName) { QFile testFile( QString(":/test/%1").arg(fileName) ); Q_ASSERT(testFile.open(QFile::ReadOnly)); QTextStream input(&testFile); return input.readAll(); } void TestPrettyGeneratorPass::init() { if (m_prettyGeneratorPass) { disconnect(m_prettyGeneratorPass, SIGNAL(finished(QString)), this, SLOT(setResult(QString))); delete m_prettyGeneratorPass; } m_prettyGeneratorPass = new QmlJSc::PrettyGeneratorPass(); m_result.clear(); connect(m_prettyGeneratorPass, SIGNAL(finished(QString)), this, SLOT(setResult(QString))); } void TestPrettyGeneratorPass::emitsFinishedSignal() { // Setup - QmlJSc::IR::Component component; - component.setSuper(m_qtObjectType); - TestNodeComponent testNodeComponent(component); + QmlJSc::IR::File file; + file.setRootObject(new QmlJSc::IR::Object); + file.rootObject()->setSuper(m_qtObjectType); + TestNodeFile testNodeFile(file); QSignalSpy finishedSpy(m_prettyGeneratorPass, SIGNAL(finished(QString))); // Do - m_prettyGeneratorPass->process(&testNodeComponent); + m_prettyGeneratorPass->process(&testNodeFile); // Verify QCOMPARE(finishedSpy.count(), 1); } -void TestPrettyGeneratorPass::visitComponent() +void TestPrettyGeneratorPass::visitFile() { // Setup - QString minimalComponentJs = readTestFileContent("minimal.qml.js"); + QString minimalFileJs = readTestFileContent("minimal.qml.js"); - QmlJSc::IR::Component component; - component.setSuper(m_qtObjectType); + QmlJSc::IR::File file; + file.setRootObject(new QmlJSc::IR::Object); + file.rootObject()->setSuper(m_qtObjectType); - TestNodeComponent testNodeComponent(component); + TestNodeFile testNodeFile(file); // Do - m_prettyGeneratorPass->process(&testNodeComponent); + m_prettyGeneratorPass->process(&testNodeFile); // Verify - QCOMPARE(m_result, minimalComponentJs); + QCOMPARE(m_result, minimalFileJs); } QTEST_MAIN(TestPrettyGeneratorPass) #include "testprettygeneratorpass.moc" \ No newline at end of file