diff --git a/src/qmljsc/CMakeLists.txt b/src/qmljsc/CMakeLists.txt --- a/src/qmljsc/CMakeLists.txt +++ b/src/qmljsc/CMakeLists.txt @@ -10,6 +10,7 @@ ir/module.cpp ir/file.cpp ir/typesystem.cpp + ir/builtintypes.cpp compilerpasses/parserpass.cpp compilerpasses/prettygeneratorpass.cpp diff --git a/src/qmljsc/moduleloading/qtqmlmoduleloader.h b/src/qmljsc/ir/builtintypes.h copy from src/qmljsc/moduleloading/qtqmlmoduleloader.h copy to src/qmljsc/ir/builtintypes.h --- a/src/qmljsc/moduleloading/qtqmlmoduleloader.h +++ b/src/qmljsc/ir/builtintypes.h @@ -18,37 +18,41 @@ * */ -#ifndef QTQMLMODULELOADER_H -#define QTQMLMODULELOADER_H +#ifndef BUILTINTYPES_H +#define BUILTINTYPES_H -#include "abstractmoduleloader.h" - -//Qt -#include +#include namespace QmlJSc { namespace IR { - class Module; -} -/** - * This class creates the QtQml module, including all the basic types that exist - * in QML and ECMAScript. Especially as there's no module for the ECMAScript - * API, we have an extra loader class for it. - */ -class QtQmlModuleLoader : public AbstractModuleLoader +class Type; + +class BuiltinTypes { public: - static QtQmlModuleLoader *create(IR::Module *module); - - bool canLoad() override; - void doLoad() override; + static Type *type(const QString &name); + static Type *typeFromJSName(const QString &name); + static Type *boolType(); + static Type *doubleType(); + static Type *enumType(); + static Type *intType(); + static Type *listType(); + static Type *realType(); + static Type *stringType(); + static Type *urlType(); + static Type *varType(); private: - QtQmlModuleLoader(IR::Module *module); + static bool init(); + + static const int builtinTypesCount = 9; + + static Type s_builtinTypes[builtinTypesCount]; }; +} // namespace IR } // namespace QMLJSc -#endif // QTQMLMODULELOADER_H +#endif // BUILTINTYPES_H diff --git a/src/qmljsc/ir/builtintypes.cpp b/src/qmljsc/ir/builtintypes.cpp new file mode 100644 --- /dev/null +++ b/src/qmljsc/ir/builtintypes.cpp @@ -0,0 +1,104 @@ +/* + * 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 "builtintypes.h" +#include "ir/typesystem.h" + +using namespace QmlJSc::IR; + +Type BuiltinTypes::s_builtinTypes[] = +{ + {"bool", "Boolean"}, + {"double", "QWDouble"}, + {"enum", "QWEnum"}, + {"int", "QWInt"}, + {"list", "QWList", Type::IsList}, + {"real", "QWReal"}, + {"string", "String"}, + {"url", "QWUrl"}, + {"var", "QWVar"} +}; + +Type *BuiltinTypes::type(const QString &name) +{ + for (int i = 0; i < builtinTypesCount; i++) { + if (s_builtinTypes[i].name() == name) { + return &s_builtinTypes[i]; + } + } + return 0; +} + +Type *BuiltinTypes::typeFromJSName(const QString &jsName) +{ + for (int i = 0; i < builtinTypesCount; i++) { + if (s_builtinTypes[i].javaScriptName() == jsName) { + return &s_builtinTypes[i]; + } + } + return 0; +} + +Type *BuiltinTypes::boolType() +{ + return &s_builtinTypes[0]; +} + +Type *BuiltinTypes::doubleType() +{ + return &s_builtinTypes[1]; +} + +Type *BuiltinTypes::enumType() +{ + return &s_builtinTypes[2]; +} + +Type *BuiltinTypes::intType() +{ + return &s_builtinTypes[3]; +} + +Type *BuiltinTypes::listType() +{ + return &s_builtinTypes[4]; +} + +Type *BuiltinTypes::realType() +{ + return &s_builtinTypes[5]; +} + +Type *BuiltinTypes::stringType() +{ + return &s_builtinTypes[6]; +} + +Type *BuiltinTypes::urlType() +{ + return &s_builtinTypes[7]; +} + +Type *BuiltinTypes::varType() +{ + return &s_builtinTypes[8]; +} + diff --git a/src/qmljsc/ir/typesystem.h b/src/qmljsc/ir/typesystem.h --- a/src/qmljsc/ir/typesystem.h +++ b/src/qmljsc/ir/typesystem.h @@ -52,12 +52,13 @@ enum Flag { None = 0, IsInstantiable = 1, - IsComponent = 2 + IsComponent = 2, + IsList = 4 }; Q_DECLARE_FLAGS(Flags, Flag); Type(); - Type(Flags flags); + Type(const QString &name, const QString &jsName = QString(), Flags flags = None); const QString &name(); const QString &javaScriptName(); diff --git a/src/qmljsc/ir/typesystem.cpp b/src/qmljsc/ir/typesystem.cpp --- a/src/qmljsc/ir/typesystem.cpp +++ b/src/qmljsc/ir/typesystem.cpp @@ -24,13 +24,15 @@ using namespace QmlJSc::IR; Type::Type() - : m_super(0) + : m_super(0) { } -Type::Type(Flags flags) - : m_flags(flags) - , m_super(0) +Type::Type(const QString &name, const QString &jsName, Flags flags) + : m_name(name) + , m_javaScriptName(jsName) + , m_flags(flags) + , m_super(0) { } diff --git a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp --- a/src/qmljsc/moduleloading/javascriptmoduleloader.cpp +++ b/src/qmljsc/moduleloading/javascriptmoduleloader.cpp @@ -23,6 +23,7 @@ #include "moduleloading.h" #include "ir/module.h" #include "ir/typesystem.h" +#include "ir/builtintypes.h" #include "compiler.h" #include "error.h" @@ -411,13 +412,16 @@ } -IR::Type *TypeDefinitionVisitor::getType(const QStringRef& name) +IR::Type *TypeDefinitionVisitor::getType(const QStringRef& nameRef) { - IR::Type *t = 0; - t = m_module->typeFromJSName(name.toString()); - // TODO: Search different locations (Task T488). + IR::Type *type = 0; + QString name = nameRef.toString(); + type = m_module->typeFromJSName(name); + if (!type) { + type = IR::BuiltinTypes::typeFromJSName(name); + } - return t; + return type; } diff --git a/src/qmljsc/moduleloading/qtqmlmoduleloader.h b/src/qmljsc/moduleloading/qtqmlmoduleloader.h --- a/src/qmljsc/moduleloading/qtqmlmoduleloader.h +++ b/src/qmljsc/moduleloading/qtqmlmoduleloader.h @@ -33,9 +33,7 @@ } /** - * This class creates the QtQml module, including all the basic types that exist - * in QML and ECMAScript. Especially as there's no module for the ECMAScript - * API, we have an extra loader class for it. + * This class is used when loading the QtQml module. */ class QtQmlModuleLoader : public AbstractModuleLoader { diff --git a/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp b/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp --- a/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp +++ b/src/qmljsc/moduleloading/qtqmlmoduleloader.cpp @@ -22,6 +22,7 @@ #include "qtqmlmoduleloader.h" #include "ir/typesystem.h" #include "ir/module.h" +#include "ir/builtintypes.h" #include "error.h" using namespace QmlJSc; @@ -48,65 +49,16 @@ IR::Method *m = 0; IR::Signal *s = 0; - // Basic types - IR::Type *boolType = new IR::Type; - boolType->setName("bool"); - boolType->setJavaScriptName("Boolean"); - module->addType(boolType); - - IR::Type *doubleType = new IR::Type; - doubleType->setName("double"); - doubleType->setJavaScriptName("QWDouble"); - module->addType(doubleType); - - IR::Type *enumType = new IR::Type; - enumType->setName("enum"); - enumType->setJavaScriptName("QWEnum"); - module->addType(enumType); - - IR::Type *intType = new IR::Type; - intType->setName("int"); - intType->setJavaScriptName("QWInt"); - module->addType(intType); - - IR::Type *listType = new IR::Type; - listType->setName("list"); - listType->setJavaScriptName("QWList"); - // TODO: Add list-flag (Requires T504) - module->addType(listType); - - IR::Type *realType = new IR::Type; - realType->setName("real"); - realType->setJavaScriptName("QWReal"); - module->addType(realType); - - IR::Type *stringType = new IR::Type; - stringType->setName("string"); - stringType->setJavaScriptName("String"); - module->addType(stringType); - - IR::Type *urlType = new IR::Type; - urlType->setName("url"); - urlType->setJavaScriptName("QWUrl"); - module->addType(urlType); - - IR::Type *varType = new IR::Type; - varType->setName("var"); - varType->setJavaScriptName("QWVar"); - module->addType(varType); - // === Classes === // Component - IR::Type *componentClass = new IR::Type( IR::Type::Flags(IR::Type::IsInstantiable | IR::Type::IsComponent) ); - componentClass->setName("Component"); - componentClass->setJavaScriptName("QWComponent"); + IR::Type *componentClass = new IR::Type("Component", "QWComponent", IR::Type::Flags(IR::Type::IsInstantiable | IR::Type::IsComponent) ); p = componentClass->addProperty("progress"); - p->type = realType; + p->type = IR::BuiltinTypes:: realType(); p = componentClass->addProperty("status"); - p->type = enumType; + p->type = IR::BuiltinTypes:: enumType(); p = componentClass->addProperty("url"); - p->type = urlType; + p->type = IR::BuiltinTypes:: urlType(); m = componentClass->addMethod("createObject"); m->parameters.append("parent"); m->parameters.append("properties"); @@ -116,53 +68,48 @@ m->parameters.append("properties"); m->parameters.append("mode"); - IR::Type *componentAttached = new IR::Type(IR::Type::IsInstantiable); + IR::Type *componentAttached = new IR::Type; componentAttached->addSignal("completed"); componentAttached->addSignal("destruction"); componentClass->setAttachedType(componentAttached); module->addType(componentClass); // QtObject - IR::Type *qtobjectClass = new IR::Type(IR::Type::IsInstantiable); - qtobjectClass->setName("QtObject"); - qtobjectClass->setJavaScriptName("QWObject"); + IR::Type *qtobjectClass = new IR::Type("QtObject", "QWObject", IR::Type::IsInstantiable); p = qtobjectClass->addProperty("objectName"); - p->type = stringType; + p->type = IR::BuiltinTypes:: stringType(); module->addType(qtobjectClass); // Binding - IR::Type *bindingClass = new IR::Type(IR::Type::IsInstantiable); - bindingClass->setName("Binding"); + IR::Type *bindingClass = new IR::Type("Binding", "", IR::Type::IsInstantiable); p = bindingClass->addProperty("property"); - p->type = stringType; + p->type = IR::BuiltinTypes:: stringType(); p = bindingClass->addProperty("target"); p->type = qtobjectClass; p = bindingClass->addProperty("value"); - p->type = varType; + p->type = IR::BuiltinTypes:: varType(); p = bindingClass->addProperty("when"); - p->type = boolType; + p->type = IR::BuiltinTypes:: boolType(); module->addType(bindingClass); // Connections - IR::Type *connectionsClass = new IR::Type(IR::Type::IsInstantiable); - connectionsClass->setName("Connections"); + IR::Type *connectionsClass = new IR::Type("Connections", "", IR::Type::IsInstantiable); p = connectionsClass->addProperty("ignoreUnknownSignals"); - p->type = boolType; + p->type = IR::BuiltinTypes:: boolType(); p = connectionsClass->addProperty("target"); p->type = qtobjectClass; module->addType(connectionsClass); // Timer - IR::Type *timerClass = new IR::Type(IR::Type::IsInstantiable); - timerClass->setName("Timer"); + IR::Type *timerClass = new IR::Type("Timer", "", IR::Type::IsInstantiable); p = timerClass->addProperty("interval"); - p->type = intType; + p->type = IR::BuiltinTypes:: intType(); p = timerClass->addProperty("repeat"); - p->type = boolType; + p->type = IR::BuiltinTypes:: boolType(); p = timerClass->addProperty("running"); - p->type = boolType; + p->type = IR::BuiltinTypes:: boolType(); p = timerClass->addProperty("triggeredOnStart"); - p->type = boolType; + p->type = IR::BuiltinTypes:: boolType(); timerClass->addSignal("triggered"); timerClass->addMethod("restart"); timerClass->addMethod("start"); diff --git a/tests/auto/data/imports/TestModule.0.1.js b/tests/auto/data/imports/TestModule.0.1.js --- a/tests/auto/data/imports/TestModule.0.1.js +++ b/tests/auto/data/imports/TestModule.0.1.js @@ -49,6 +49,7 @@ } __engine.registerModule({ + Oven: Oven, Pastry: Pastry, Cake: Cake, Pizza: Pizza diff --git a/tests/auto/qmljsc/testir.cpp b/tests/auto/qmljsc/testir.cpp --- a/tests/auto/qmljsc/testir.cpp +++ b/tests/auto/qmljsc/testir.cpp @@ -28,6 +28,7 @@ #include "../../../src/qmljsc/ir/objecttree.h" #include "../../../src/qmljsc/ir/visitor.h" #include "../../../src/qmljsc/ir/typesystem.h" +#include "../../../src/qmljsc/ir/builtintypes.h" // Qt private #include @@ -47,6 +48,7 @@ void testBasics(); void testAdd(); void testVisitorAPI(); + void testBuiltinTypes(); private: Type city; @@ -353,6 +355,46 @@ QCOMPARE(lastValueAssigned->value.toString(), QStringLiteral("København")); } +void TestIR::testBuiltinTypes() +{ + Type *boolType = BuiltinTypes::type("bool"); + QVERIFY(boolType); + QCOMPARE(BuiltinTypes::typeFromJSName("Boolean"), boolType); + + Type *doubleType = BuiltinTypes::type("double"); + QVERIFY(doubleType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWDouble"), doubleType); + + Type *enumType = BuiltinTypes::type("enum"); + QVERIFY(enumType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWEnum"), enumType); + + Type *intType = BuiltinTypes::type("int"); + QVERIFY(intType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWInt"), intType); + + Type *listType = BuiltinTypes::type("list"); + QVERIFY(listType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWList"), listType); + QCOMPARE(listType->flags(), Type::IsList); + + Type *realType = BuiltinTypes::type("real"); + QVERIFY(realType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWReal"), realType); + + Type *stringType = BuiltinTypes::type("string"); + QVERIFY(stringType); + QCOMPARE(BuiltinTypes::typeFromJSName("String"), stringType); + + Type *urlType = BuiltinTypes::type("url"); + QVERIFY(urlType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWUrl"), urlType); + + Type *varType = BuiltinTypes::type("var"); + QVERIFY(varType); + QCOMPARE(BuiltinTypes::typeFromJSName("QWVar"), varType); +} + } // namespace IR } // namespace QMLJSc diff --git a/tests/auto/qmljsc/testmodules.cpp b/tests/auto/qmljsc/testmodules.cpp --- a/tests/auto/qmljsc/testmodules.cpp +++ b/tests/auto/qmljsc/testmodules.cpp @@ -33,6 +33,7 @@ #include "../../../src/qmljsc/moduleloading/javascriptmoduleloader.h" #include "../../../src/qmljsc/moduleloading/qtqmlmoduleloader.h" #include "../../../src/qmljsc/ir/module.h" +#include "../../../src/qmljsc/ir/builtintypes.h" class TestModules : public QObject { @@ -141,52 +142,16 @@ IR::Method *m = 0; IR::Signal *s = 0; - Type *boolType = qtqmlModule->type("bool"); - QVERIFY(boolType); - QCOMPARE(qtqmlModule->typeFromJSName("Boolean"), boolType); - - Type *doubleType = qtqmlModule->type("double"); - QVERIFY(doubleType); - QCOMPARE(qtqmlModule->typeFromJSName("QWDouble"), doubleType); - - Type *enumType = qtqmlModule->type("enum"); - QVERIFY(enumType); - QCOMPARE(qtqmlModule->typeFromJSName("QWEnum"), enumType); - - Type *intType = qtqmlModule->type("int"); - QVERIFY(intType); - QCOMPARE(qtqmlModule->typeFromJSName("QWInt"), intType); - - Type *listType = qtqmlModule->type("list"); - QVERIFY(listType); - QCOMPARE(qtqmlModule->typeFromJSName("QWList"), listType); - - Type *realType = qtqmlModule->type("real"); - QVERIFY(realType); - QCOMPARE(qtqmlModule->typeFromJSName("QWReal"), realType); - - Type *stringType = qtqmlModule->type("string"); - QVERIFY(stringType); - QCOMPARE(qtqmlModule->typeFromJSName("String"), stringType); - - Type *urlType = qtqmlModule->type("url"); - QVERIFY(urlType); - QCOMPARE(qtqmlModule->typeFromJSName("QWUrl"), urlType); - - Type *varType = qtqmlModule->type("var"); - QVERIFY(varType); - QCOMPARE(qtqmlModule->typeFromJSName("QWVar"), varType); - Type *componentClass = qtqmlModule->type("Component"); QVERIFY(componentClass); QCOMPARE(qtqmlModule->typeFromJSName("QWComponent"), componentClass); QVERIFY(componentClass->flags() & IR::Type::IsComponent); QVERIFY(p = componentClass->property("progress")); - QCOMPARE(p->type, realType); + QCOMPARE(p->type, BuiltinTypes:: realType()); QVERIFY(p = componentClass->property("status")); - QCOMPARE(p->type, enumType); + QCOMPARE(p->type, BuiltinTypes:: enumType()); QVERIFY(p = componentClass->property("url")); - QCOMPARE(p->type, urlType); + QCOMPARE(p->type, BuiltinTypes:: urlType()); QVERIFY(!componentClass->property("heyo")); QVERIFY(!componentClass->method("heyo")); QVERIFY(m = componentClass->method("createObject")); @@ -213,38 +178,38 @@ QVERIFY(qtobjectClass); QCOMPARE(qtqmlModule->typeFromJSName("QWObject"), qtobjectClass); QVERIFY(p = qtobjectClass->property("objectName")); - QCOMPARE(p->type, stringType); + QCOMPARE(p->type, BuiltinTypes:: stringType()); Type *bindingClass = qtqmlModule->type("Binding"); QVERIFY(bindingClass); QVERIFY(p = bindingClass->property("property")); - QCOMPARE(p->type, stringType); + QCOMPARE(p->type, BuiltinTypes:: stringType()); QVERIFY(p = bindingClass->property("target")); QCOMPARE(p->type, qtobjectClass); QVERIFY(p = bindingClass->property("value")); - QCOMPARE(p->type, varType); + QCOMPARE(p->type, BuiltinTypes:: varType()); QVERIFY(p = bindingClass->property("when")); - QCOMPARE(p->type, boolType); + QCOMPARE(p->type, BuiltinTypes:: boolType()); Type *connectionsClass = qtqmlModule->type("Connections"); QVERIFY(connectionsClass); QVERIFY(p = connectionsClass->property("ignoreUnknownSignals")); - QCOMPARE(p->type, boolType); + QCOMPARE(p->type, BuiltinTypes:: boolType()); QVERIFY(p = connectionsClass->property("target")); QCOMPARE(p->type, qtobjectClass); Type *timerClass = qtqmlModule->type("Timer"); QVERIFY(timerClass); QVERIFY(p = timerClass->property("interval")); - QCOMPARE(p->type, intType); + QCOMPARE(p->type, BuiltinTypes:: intType()); QVERIFY(p = timerClass->property("repeat")); - QCOMPARE(p->type, boolType); + QCOMPARE(p->type, BuiltinTypes:: boolType()); QVERIFY(p = timerClass->property("running")); - QCOMPARE(p->type, boolType); + QCOMPARE(p->type, BuiltinTypes:: boolType()); QVERIFY(p = timerClass->property("triggeredOnStart")); - QCOMPARE(p->type, boolType); + QCOMPARE(p->type, BuiltinTypes:: boolType()); QVERIFY(timerClass->method("restart")); QVERIFY(timerClass->method("start")); QVERIFY(timerClass->method("stop")); @@ -254,7 +219,6 @@ void TestModules::loadModule() { - QSKIP("This will be implemented later (Task T488)."); const ImportDescription qtqmlImportDescription = {ImportDescription::Kind_ModuleImport, "QtQml", 1, 0}; const ImportDescription testImportDescription = {ImportDescription::Kind_ModuleImport, "TestModule", 0, 1}; @@ -280,15 +244,15 @@ IR::Property *p = 0; QVERIFY(p = pastry->property("bakingTime")); - QCOMPARE(p->type, qtqmlModule->type("int")); + QCOMPARE(p->type, BuiltinTypes::type("int")); QVERIFY(p = cake->property("containsRawEgg")); - QCOMPARE(p->type, qtqmlModule->type("bool")); + QCOMPARE(p->type, BuiltinTypes::type("bool")); QVERIFY(p = cake->property("bakingTime")); - QCOMPARE(p->type, qtqmlModule->type("int")); + QCOMPARE(p->type, BuiltinTypes::type("int")); QVERIFY(p = pizza->property("isCalzone")); - QCOMPARE(p->type, qtqmlModule->type("bool")); + QCOMPARE(p->type, BuiltinTypes::type("bool")); QVERIFY(p = pizza->property("topping")); - QCOMPARE(p->type, qtqmlModule->type("var")); + QCOMPARE(p->type, BuiltinTypes::type("var")); QVERIFY(!pizza->property("containsRawEgg")); IR::Property *baked = pizza->property("baked");