From a190b92bb4eb40ecf8c30d6f368c0d15ec317580 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 27 May 2009 15:15:54 +1000 Subject: Small cleanups --- src/declarative/qml/qmlcompiler.cpp | 16 +++++++--------- src/declarative/qml/qmlcompiler_p.h | 4 +--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index cce8109..09f4e0b 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -728,12 +728,12 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) ids.clear(); if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); - ids = oldIds; create.createComponent.count = output->bytecode.count() - count; int inc = optimizeExpressions(count, count - 1 + create.createComponent.count, count); create.createComponent.count += inc; + ids = oldIds; return true; } @@ -914,7 +914,7 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt) } else if (isAttachedPropertyName(prop->name)) { - COMPILE_CHECK(compileAttachedProperty(prop, obj, ctxt)); + COMPILE_CHECK(compileAttachedProperty(prop, ctxt)); } else if (prop->index == -1) { @@ -995,7 +995,6 @@ bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, // } // GridView is an attached property object. bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, - QmlParser::Object *obj, int ctxt) { Q_ASSERT(prop->value); @@ -1158,7 +1157,7 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, Value *v = prop->values.at(ii); if (v->object) { - COMPILE_CHECK(compilePropertyObjectAssignment(prop, obj, v, ctxt)); + COMPILE_CHECK(compilePropertyObjectAssignment(prop, v, ctxt)); } else { @@ -1172,7 +1171,6 @@ bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, // Compile assigning a single object instance to a regular property bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, QmlParser::Value *v, int ctxt) { @@ -1402,6 +1400,10 @@ bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, Q_ASSERT(mo); Q_ASSERT(prop->index); + QMetaProperty mp = mo->property(prop->index); + if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) + COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); + QmlBasicScript bs; bs.compile(bind.toLatin1()); @@ -1423,11 +1425,7 @@ bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, assign.assignBinding.property = prop->index; assign.assignBinding.value = bref; - QMetaProperty mp = mo->property(assign.assignBinding.property); - if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) - COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); - savedTypes.insert(output->bytecode.count(), prop->type); output->bytecode << assign; diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index bc9e06c..6e9bafb 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -137,7 +137,6 @@ private: bool compileIdProperty(QmlParser::Property *prop, QmlParser::Object *obj); bool compileAttachedProperty(QmlParser::Property *prop, - QmlParser::Object *obj, int ctxt); bool compileNestedProperty(QmlParser::Property *prop, int ctxt); @@ -148,7 +147,6 @@ private: QmlParser::Object *obj, int ctxt); bool compilePropertyObjectAssignment(QmlParser::Property *prop, - QmlParser::Object *obj, QmlParser::Value *value, int ctxt); bool compilePropertyLiteralAssignment(QmlParser::Property *prop, @@ -166,11 +164,11 @@ private: int optimizeExpressions(int start, int end, int patch = -1); QSet ids; + QHash savedTypes; QList exceptions; QmlCompiledData *output; - QHash savedTypes; }; QT_END_NAMESPACE -- cgit v0.12 From 0a6df63c7150f0010b08ce2ba08a492cd129a96f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 27 May 2009 16:03:25 +1000 Subject: Save the JavaScript AST in the QmlParser::Variant for use by others --- src/declarative/qml/qmlparser.cpp | 18 +++++++++++++++--- src/declarative/qml/qmlparser_p.h | 7 ++++++- src/declarative/qml/qmlscriptparser.cpp | 8 ++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index c5d7092..5c2a69f 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -281,10 +281,14 @@ QmlParser::Variant::Variant(double v, const QString &asWritten) { } -QmlParser::Variant::Variant(const QString &v, Type type) -: t(type), s(v) +QmlParser::Variant::Variant(const QString &v) +: t(String), s(v) +{ +} + +QmlParser::Variant::Variant(const QString &v, JavaScript::AST::Node *n) +: t(Script), n(n), s(v) { - Q_ASSERT(type == String || type == Script); } QmlParser::Variant &QmlParser::Variant::operator=(const Variant &o) @@ -334,4 +338,12 @@ QString QmlParser::Variant::asScript() const } } +JavaScript::AST::Node *QmlParser::Variant::asAST() const +{ + if (type() == Script) + return n; + else + return 0; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 721f1a8..cb9b540 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +namespace JavaScript { namespace AST { class Node; } } + /* XXX @@ -175,7 +177,8 @@ namespace QmlParser Variant(const Variant &); Variant(bool); Variant(double, const QString &asWritten=QString()); - Variant(const QString &, Type = String); + Variant(const QString &); + Variant(const QString &, JavaScript::AST::Node *); Variant &operator=(const Variant &); Type type() const; @@ -189,12 +192,14 @@ namespace QmlParser QString asString() const; double asNumber() const; QString asScript() const; + JavaScript::AST::Node *asAST() const; private: Type t; union { bool b; double d; + JavaScript::AST::Node *n; }; QString s; }; diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 5c5b25e..b862953 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -587,7 +587,7 @@ QmlParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) if (lit->suffix == AST::NumericLiteral::noSuffix) return QmlParser::Variant(lit->value, asString(expr)); else - return QmlParser::Variant(asString(expr), QmlParser::Variant::Script); + return QmlParser::Variant(asString(expr), expr); } else { @@ -597,7 +597,7 @@ QmlParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) } } - return QmlParser::Variant(asString(expr), QmlParser::Variant::Script); + return QmlParser::Variant(asString(expr), expr); } } @@ -620,8 +620,8 @@ bool ProcessAST::visit(AST::UiScriptBinding *node) if (AST::ExpressionStatement *stmt = AST::cast(node->statement)) { primitive = getVariant(stmt->expression); } else { // do binding - primitive = QmlParser::Variant(asString(node->statement), - QmlParser::Variant::Script); + primitive = QmlParser::Variant(asString(node->statement), + node->statement); } Value *v = new Value; -- cgit v0.12 From c8f180e7023308b8a051b53943b9a088a7f0c427 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 27 May 2009 20:40:28 +1000 Subject: Small cleanups --- src/declarative/qml/qmlcompiler.cpp | 175 +++++++++++++++----------------- src/declarative/qml/qmlcompiler_p.h | 26 ++++- src/declarative/qml/qmlscriptparser.cpp | 34 +++++-- src/declarative/qml/qmlscriptparser_p.h | 2 + 4 files changed, 132 insertions(+), 105 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 09f4e0b..b9a848a 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -62,6 +62,7 @@ #include "private/qmlcustomparser_p_p.h" #include #include +#include "parser/javascriptast_p.h" #include "qmlscriptparser_p.h" @@ -516,6 +517,7 @@ bool QmlCompiler::compile(QmlEngine *engine, } output = 0; + return !isError(); } @@ -542,7 +544,7 @@ void QmlCompiler::compileTree(Object *tree) def.type = QmlInstruction::SetDefault; output->bytecode << def; - optimizeExpressions(0, output->bytecode.count() - 1, 0); + finalizeComponent(0); } bool QmlCompiler::compileObject(Object *obj, int ctxt) @@ -588,6 +590,8 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt) begin.begin.castValue = parserStatusCast; begin.line = obj->location.start.line; output->bytecode << begin; + + compileState.parserStatusCount++; } // Check if this is a custom parser type. Custom parser types allow @@ -688,9 +692,14 @@ bool QmlCompiler::compileComponent(Object *obj, int ctxt) if (!isValidId(val)) COMPILE_EXCEPTION("Invalid id property value"); - if (ids.contains(val)) + if (compileState.ids.contains(val)) COMPILE_EXCEPTION("id is not unique"); - ids.insert(val); + + IdReference reference; + reference.id = val; + reference.object = obj; + reference.instructionIdx = output->bytecode.count(); + compileState.ids.insert(val, reference); int pref = output->indexForString(val); QmlInstruction id; @@ -699,8 +708,6 @@ bool QmlCompiler::compileComponent(Object *obj, int ctxt) id.setId.value = pref; id.setId.save = -1; - savedTypes.insert(output->bytecode.count(), -1); - output->bytecode << id; } @@ -724,16 +731,16 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) init.line = obj->location.start.line; output->bytecode << init; - QSet oldIds = ids; - ids.clear(); + ComponentCompileState oldComponentCompileState = compileState; + compileState = ComponentCompileState(); if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); create.createComponent.count = output->bytecode.count() - count; - int inc = optimizeExpressions(count, count - 1 + create.createComponent.count, count); + int inc = finalizeComponent(count); create.createComponent.count += inc; - ids = oldIds; + compileState = oldComponentCompileState; return true; } @@ -950,41 +957,43 @@ bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, if (prop->values.count() > 1) COMPILE_EXCEPTION2(prop, "The object id may only be set once"); - if (prop->values.count() == 1) { - if (prop->values.at(0)->object) - COMPILE_EXCEPTION("Cannot assign an object as an id"); - QString val = prop->values.at(0)->primitive(); - if (!isValidId(val)) - COMPILE_EXCEPTION(val << "is not a valid id"); - if (ids.contains(val)) - COMPILE_EXCEPTION("id is not unique"); - ids.insert(val); + if (prop->values.at(0)->object) + COMPILE_EXCEPTION("Cannot assign an object as an id"); + QString val = prop->values.at(0)->primitive(); + if (!isValidId(val)) + COMPILE_EXCEPTION(val << "is not a valid id"); + if (compileState.ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); - int pref = output->indexForString(val); + int pref = output->indexForString(val); - if (prop->type == QVariant::String) { - QmlInstruction assign; - assign.type = QmlInstruction::StoreString; - assign.storeString.propertyIndex = prop->index; - assign.storeString.value = pref; - assign.line = prop->values.at(0)->location.start.line; - output->bytecode << assign; + if (prop->type == QVariant::String) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreString; + assign.storeString.propertyIndex = prop->index; + assign.storeString.value = pref; + assign.line = prop->values.at(0)->location.start.line; + output->bytecode << assign; - prop->values.at(0)->type = Value::Id; - } else { - prop->values.at(0)->type = Value::Literal; - } + prop->values.at(0)->type = Value::Id; + } else { + prop->values.at(0)->type = Value::Literal; + } - QmlInstruction id; - id.type = QmlInstruction::SetId; - id.line = prop->values.at(0)->location.start.line; - id.setId.value = pref; - id.setId.save = -1; - savedTypes.insert(output->bytecode.count(), obj->type); - output->bytecode << id; + IdReference reference; + reference.id = val; + reference.object = obj; + reference.instructionIdx = output->bytecode.count(); + compileState.ids.insert(val, reference); - obj->id = val.toLatin1(); - } + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = prop->values.at(0)->location.start.line; + id.setId.value = pref; + id.setId.save = -1; + output->bytecode << id; + + obj->id = val.toLatin1(); return true; } @@ -1116,7 +1125,7 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, + COMPILE_CHECK(compileBinding(v->value, prop, ctxt, obj->metaObject(), v->location.start.line)); v->type = Value::PropertyBinding; @@ -1287,7 +1296,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v->value.asScript(), prop, ctxt, + COMPILE_CHECK(compileBinding(v->value, prop, ctxt, obj->metaObject(), v->location.start.line)); @@ -1394,7 +1403,8 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } -bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, +bool QmlCompiler::compileBinding(const QmlParser::Variant &bind, + QmlParser::Property *prop, int ctxt, const QMetaObject *mo, qint64 line) { Q_ASSERT(mo); @@ -1405,13 +1415,13 @@ bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); QmlBasicScript bs; - bs.compile(bind.toLatin1()); + bs.compile(bind.asScript().toLatin1()); int bref; if (bs.isValid()) { bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); } else { - bref = output->indexForString(bind); + bref = output->indexForString(bind.asScript()); } QmlInstruction assign; @@ -1426,49 +1436,28 @@ bool QmlCompiler::compileBinding(const QString &bind, QmlParser::Property *prop, assign.assignBinding.property = prop->index; assign.assignBinding.value = bref; assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); - savedTypes.insert(output->bytecode.count(), prop->type); + BindingReference reference; + reference.expression = bind; + reference.property = prop; + reference.instructionIdx = output->bytecode.count(); + compileState.bindings << reference; + output->bytecode << assign; return true; } -int QmlCompiler::optimizeExpressions(int start, int end, int patch) +// Update the init instruction with final data, and optimize some simple +// bindings +int QmlCompiler::finalizeComponent(int patch) { - QHash ids; int saveCount = 0; int newInstrs = 0; - int bindingsCount = 0; - int parserStatusCount = 0; - for (int ii = start; ii <= end; ++ii) { - const QmlInstruction &instr = output->bytecode.at(ii); - - if (instr.type == QmlInstruction::CreateComponent) { - ii += instr.createComponent.count - 1; - continue; - } - - if (instr.type == QmlInstruction::SetId) { - QString id = output->primitives.at(instr.setId.value); - ids.insert(id, ii); - } - } - - for (int ii = start; ii <= end; ++ii) { - const QmlInstruction &instr = output->bytecode.at(ii); - - if (instr.type == QmlInstruction::CreateComponent) { - ii += instr.createComponent.count - 1; - continue; - } - - if (instr.type == QmlInstruction::StoreBinding || - instr.type == QmlInstruction::StoreCompiledBinding) { - ++bindingsCount; - } else if (instr.type == QmlInstruction::BeginObject) { - ++parserStatusCount; - } + for (int ii = 0; ii < compileState.bindings.count(); ++ii) { + const BindingReference &binding = compileState.bindings.at(ii); + QmlInstruction &instr = output->bytecode[binding.instructionIdx]; if (instr.type == QmlInstruction::StoreCompiledBinding) { QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); @@ -1478,16 +1467,17 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) if (!slt.at(0).isUpper()) continue; - if (ids.contains(slt) && + if (compileState.ids.contains(slt) && instr.assignBinding.category == QmlMetaProperty::Object) { - int id = ids[slt]; - int idType = savedTypes.value(id); - int storeType = savedTypes.value(ii); + IdReference reference = + compileState.ids[slt]; + + const QMetaObject *idMo = reference.object->metaObject(); + const QMetaObject *storeMo = QmlMetaType::rawMetaObjectForType(binding.property->type); - const QMetaObject *idMo = (idType == -1)?&QmlComponent::staticMetaObject:output->types.at(idType).metaObject(); - const QMetaObject *storeMo = - QmlMetaType::rawMetaObjectForType(storeType); + Q_ASSERT(idMo); + Q_ASSERT(storeMo); bool canAssign = false; while (!canAssign && idMo) { @@ -1502,19 +1492,19 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) int saveId = -1; - if (output->bytecode.at(id).setId.save != -1) { - saveId = output->bytecode.at(id).setId.save; + int instructionIdx = reference.instructionIdx; + if (output->bytecode.at(instructionIdx).setId.save != -1) { + saveId = output->bytecode.at(instructionIdx).setId.save; } else { - output->bytecode[id].setId.save = saveCount; + output->bytecode[instructionIdx].setId.save = saveCount; saveId = saveCount; ++saveCount; } int prop = instr.assignBinding.property; - QmlInstruction &rwinstr = output->bytecode[ii]; - rwinstr.type = QmlInstruction::PushProperty; - rwinstr.pushProperty.property = prop; + instr.type = QmlInstruction::PushProperty; + instr.pushProperty.property = prop; QmlInstruction instr; instr.type = QmlInstruction::StoreStackObject; @@ -1529,8 +1519,9 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) } output->bytecode[patch].init.dataSize = saveCount; - output->bytecode[patch].init.bindingsSize = bindingsCount; - output->bytecode[patch].init.parserStatusSize = parserStatusCount;; + output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); + output->bytecode[patch].init.parserStatusSize = + compileState.parserStatusCount; return newInstrs; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 6e9bafb..b1963da 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -158,13 +158,31 @@ private: QmlParser::Value *value); bool compileDynamicMeta(QmlParser::Object *obj); - bool compileBinding(const QString &, QmlParser::Property *prop, + bool compileBinding(const QmlParser::Variant &, QmlParser::Property *prop, int ctxt, const QMetaObject *, qint64); - int optimizeExpressions(int start, int end, int patch = -1); + int finalizeComponent(int patch); - QSet ids; - QHash savedTypes; + struct IdReference { + QString id; + QmlParser::Object *object; + int instructionIdx; + }; + + struct BindingReference { + QmlParser::Variant expression; + QmlParser::Property *property; + int instructionIdx; + }; + + struct ComponentCompileState + { + ComponentCompileState() : parserStatusCount(0) {} + QHash ids; + int parserStatusCount; + QList bindings; + }; + ComponentCompileState compileState; QList exceptions; QmlCompiledData *output; diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index b862953..b1ffc98 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -597,7 +597,7 @@ QmlParser::Variant ProcessAST::getVariant(AST::ExpressionNode *expr) } } - return QmlParser::Variant(asString(expr), expr); + return QmlParser::Variant(asString(expr), expr); } } @@ -716,33 +716,44 @@ bool ProcessAST::visit(AST::UiSourceElement *node) QmlScriptParser::QmlScriptParser() -: root(0) +: root(0), data(0) { } QmlScriptParser::~QmlScriptParser() { + clear(); } -bool QmlScriptParser::parse(const QByteArray &data, const QUrl &url) +class QmlScriptParserJsASTData +{ +public: + QmlScriptParserJsASTData(const QString &filename) + : nodePool(filename, &engine) {} + + Engine engine; + NodePool nodePool; +}; + +bool QmlScriptParser::parse(const QByteArray &qmldata, const QUrl &url) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer pt; #endif + clear(); + const QString fileName = url.toString(); - QTextStream stream(data, QIODevice::ReadOnly); + QTextStream stream(qmldata, QIODevice::ReadOnly); const QString code = stream.readAll(); - Engine engine; - - NodePool nodePool(fileName, &engine); + data = new QmlScriptParserJsASTData(fileName); - Lexer lexer(&engine); + Lexer lexer(&data->engine); lexer.setCode(code, /*line = */ 1); - Parser parser(&engine); + Parser parser(&data->engine); if (! parser.parse() || !_errors.isEmpty()) { @@ -808,6 +819,11 @@ void QmlScriptParser::clear() _nameSpacePaths.clear(); _typeNames.clear(); _errors.clear(); + + if (data) { + delete data; + data = 0; + } } int QmlScriptParser::findOrCreateTypeId(const QString &name) diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h index a9ffa47..3993194 100644 --- a/src/declarative/qml/qmlscriptparser_p.h +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -54,6 +54,7 @@ QT_MODULE(Declarative) class QByteArray; +class QmlScriptParserJsASTData; class QmlScriptParser { public: @@ -98,6 +99,7 @@ public: QList _imports; QStringList _typeNames; QString _scriptFile; + QmlScriptParserJsASTData *data; }; QT_END_NAMESPACE -- cgit v0.12 From b865ab6508963cbad0a12319b40db17f9925bbde Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 28 May 2009 10:48:50 +1000 Subject: QmlBasicScript should work on the actual JS AST tree --- src/declarative/fx/qfxkeyactions.cpp | 2 +- src/declarative/qml/parser/javascriptast_p.h | 6 +- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlbasicscript.cpp | 853 +++++++++++++++++++ src/declarative/qml/qmlbasicscript_p.h | 104 +++ src/declarative/qml/qmlbindablevalue.cpp | 4 +- src/declarative/qml/qmlbindablevalue.h | 2 +- src/declarative/qml/qmlcompiler.cpp | 45 +- src/declarative/qml/qmlengine.cpp | 36 +- src/declarative/qml/qmlengine_p.h | 4 +- src/declarative/qml/qmlexpression.h | 2 - src/declarative/qml/qmlparser.cpp | 1 - src/declarative/qml/script/generator/generator.pro | 11 - src/declarative/qml/script/generator/main.cpp | 135 --- src/declarative/qml/script/instructions.h | 32 - src/declarative/qml/script/keywords.cpp | 89 -- src/declarative/qml/script/lexer.cpp | 139 ---- src/declarative/qml/script/lexer.h | 54 -- src/declarative/qml/script/qmlbasicscript.cpp | 921 --------------------- src/declarative/qml/script/qmlbasicscript.h | 76 -- src/declarative/qml/script/qmlbasicscript_p.h | 53 -- src/declarative/qml/script/script.pri | 11 - src/declarative/qml/script/tokens.cpp | 43 - src/declarative/qml/script/tokens.h | 36 - 24 files changed, 1017 insertions(+), 1648 deletions(-) create mode 100644 src/declarative/qml/qmlbasicscript.cpp create mode 100644 src/declarative/qml/qmlbasicscript_p.h delete mode 100644 src/declarative/qml/script/generator/generator.pro delete mode 100644 src/declarative/qml/script/generator/main.cpp delete mode 100644 src/declarative/qml/script/instructions.h delete mode 100644 src/declarative/qml/script/keywords.cpp delete mode 100644 src/declarative/qml/script/lexer.cpp delete mode 100644 src/declarative/qml/script/lexer.h delete mode 100644 src/declarative/qml/script/qmlbasicscript.cpp delete mode 100644 src/declarative/qml/script/qmlbasicscript.h delete mode 100644 src/declarative/qml/script/qmlbasicscript_p.h delete mode 100644 src/declarative/qml/script/script.pri delete mode 100644 src/declarative/qml/script/tokens.cpp delete mode 100644 src/declarative/qml/script/tokens.h diff --git a/src/declarative/fx/qfxkeyactions.cpp b/src/declarative/fx/qfxkeyactions.cpp index 5a1fd7d..4aae74f 100644 --- a/src/declarative/fx/qfxkeyactions.cpp +++ b/src/declarative/fx/qfxkeyactions.cpp @@ -899,7 +899,7 @@ void QFxKeyActions::keyPressEvent(QKeyEvent *event) { Qt::Key key = (Qt::Key)event->key(); if (d->enabled && d->key(key)) { - QmlExpression b(qmlContext(this), d->action(key), this, false); + QmlExpression b(qmlContext(this), d->action(key), this); b.value(); event->accept(); } else { diff --git a/src/declarative/qml/parser/javascriptast_p.h b/src/declarative/qml/parser/javascriptast_p.h index b5fd922..23d59e5 100644 --- a/src/declarative/qml/parser/javascriptast_p.h +++ b/src/declarative/qml/parser/javascriptast_p.h @@ -61,8 +61,6 @@ QT_BEGIN_NAMESPACE #define JAVASCRIPT_DECLARE_AST_NODE(name) \ enum { K = Kind_##name }; -class NameId; - namespace QSOperator // ### rename { @@ -106,7 +104,9 @@ enum Op { } // namespace QSOperator -namespace JavaScript { namespace AST { +namespace JavaScript { +class NameId; +namespace AST { template _T1 cast(_T2 *ast) diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index b6ac30e..c61200e 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -23,7 +23,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlcompositetypemanager.cpp \ qml/qmlinfo.cpp \ qml/qmlerror.cpp \ - qml/qmlscriptparser.cpp + qml/qmlscriptparser.cpp \ + qml/qmlbasicscript.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -61,7 +62,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmllist.h \ qml/qmldeclarativedata_p.h \ qml/qmlerror.h \ - qml/qmlscriptparser_p.h + qml/qmlscriptparser_p.h \ + qml/qmlbasicscript_p.h # for qtscript debugger QT += scripttools diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp new file mode 100644 index 0000000..3d74b37 --- /dev/null +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -0,0 +1,853 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmlbasicscript_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ScriptInstruction { + enum { + Load, // fetch + Fetch, // fetch + + Add, // NA + Subtract, // NA + Multiply, // NA + Equals, // NA + And, // NA + + Int, // integer + Bool, // boolean + } type; + + union { + struct { + int idx; + } fetch; + struct { + int value; + } integer; + struct { + bool value; + } boolean; + }; +}; + +DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); + +class QmlBasicScriptPrivate +{ +public: + enum Flags { OwnData = 0x00000001 }; + + int size; + int stateSize; + int instructionCount; + int exprLen; + + ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } + + const char *expr() const + { + return (const char *)(instructions() + instructionCount); + } + + const char *data() const + { + return (const char *)(instructions() + instructionCount) + exprLen + 1; + } + + static unsigned int alignRound(int s) + { + if (s % 4) + s += 4 - (s % 4); + return s; + } +}; + +QDebug operator<<(QDebug lhs, const QmlBasicScriptNodeCache &rhs) +{ + switch(rhs.type) { + case QmlBasicScriptNodeCache::Invalid: + lhs << "Invalid"; + break; + case QmlBasicScriptNodeCache::Core: + lhs << "Core" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Attached: + lhs << "Attached" << rhs.object << rhs.attached; + break; + case QmlBasicScriptNodeCache::Signal: + lhs << "Signal" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::SignalProperty: + lhs << "SignalProperty" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Variant: + lhs << "Variant" << rhs.context; + break; + } + + return lhs; +} + +void QmlBasicScriptNodeCache::clear() +{ + object = 0; + metaObject = 0; + type = Invalid; +} + +static QVariant toObjectOrVariant(const QVariant &v) +{ + switch(v.type()) { + case QVariant::String: + case QVariant::UInt: + case QVariant::Int: + case 135: + case QVariant::Double: + case QVariant::Color: + case QVariant::Bool: + default: + return v; + case QVariant::UserType: + { + QObject *o = QmlMetaType::toQObject(v); + if (o) + return qVariantFromValue(o); + else + return v; + } + break; + } +} + +static QVariant fetch_value(QObject *o, int idx, int type) +{ + switch(type) { + case QVariant::String: + { + QString val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::UInt: + { + uint val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Int: + { + int val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case 135: + { + float val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Double: + { + double val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Color: + { + QColor val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Bool: + { + bool val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + default: + { + if (QmlMetaType::isObject(type)) { + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *val = 0; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant::fromValue(val); + } else { + QVariant var = o->metaObject()->property(idx).read(o); + if (QmlMetaType::isObject(var.userType())) { + QObject *obj = 0; + obj = *(QObject **)var.data(); + var = QVariant::fromValue(obj); + } + return var; + } + } + break; + }; +} + +QVariant QmlBasicScriptNodeCache::value(const char *) const +{ + //QFxPerfTimer pt; + switch(type) { + case Invalid: + break; + case Core: + return fetch_value(object, core, coreType); + break; + case Attached: + return qVariantFromValue(static_cast(attached)); + break; + case Signal: + // XXX + Q_ASSERT(!"Not implemented"); + break; + case SignalProperty: + break; + case Variant: + return context->propertyValues[contextIndex]; + }; + return QVariant(); +} + +struct QmlBasicScriptCompiler +{ + QmlBasicScriptCompiler() + : script(0), stateSize(0) {} + QmlBasicScript *script; + int stateSize; + + bool compile(JavaScript::AST::Node *); + + bool compileExpression(JavaScript::AST::Node *); + + bool tryConstant(JavaScript::AST::Node *); + bool parseConstant(JavaScript::AST::Node *); + bool tryName(JavaScript::AST::Node *); + bool parseName(JavaScript::AST::Node *); + bool tryBinaryExpression(JavaScript::AST::Node *); + bool compileBinaryExpression(JavaScript::AST::Node *); + + QByteArray data; + QList bytecode; +}; + +/*! + \internal + \class QmlBasicScript + \brief The QmlBasicScript class provides a fast implementation of a limited subset of JavaScript bindings. + + QmlBasicScript instances are used to accelerate binding. Instead of using + the slower, fully fledged JavaScript engine, many simple bindings can be + evaluated using the QmlBasicScript engine. + + To see if the QmlBasicScript engine can handle a binding, call compile() + and check the return value, or isValid() afterwards. + + To evaluate the binding, the QmlBasicScript instance needs some memory in + which to cache state. This may be allocated by calling newScriptState() + and destroyed by calling deleteScriptState(). The state data is then passed + to the run() method when evaluating the binding. + + To further accelerate binding, QmlBasicScript can return a precompiled + version of itself that can be saved for future use. Call compileData() to + get an opaque pointer to the compiled state, and compileDataSize() for the + size of this data in bytes. This data can be saved and passed to future + instances of the QmlBasicScript constructor. The initial copy of compile + data is owned by the QmlBindScript instance on which compile() was called. +*/ + +/*! + Create a new QmlBasicScript instance. +*/ +QmlBasicScript::QmlBasicScript() +: flags(0), d(0), rc(0) +{ +} + +/*! + Create a new QmlBasicScript instance from saved \a data. + + \a data \b must be data previously acquired from calling compileData() on a + previously created QmlBasicScript instance. Any other data will almost + certainly cause the QmlBasicScript engine to crash. + + \a data must continue to be valid throughout the QmlBasicScript instance + life. It does not assume ownership of the memory. + + If \a owner is set, it is referenced on creation and dereferenced on + destruction of this instance. +*/ +QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) +: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) +{ + if (rc) rc->addref(); +} + +/*! + Return the text of the script expression. + */ +QByteArray QmlBasicScript::expression() const +{ + if (!d) + return QByteArray(); + else + return QByteArray(d->expr()); +} + +/*! + Destroy the script instance. +*/ +QmlBasicScript::~QmlBasicScript() +{ + if (flags & QmlBasicScriptPrivate::OwnData) + free(d); + if (rc) rc->release(); + d = 0; + rc = 0; +} + +/*! + Clear this script. The object will then be in its initial state, as though + it were freshly constructed with default constructor. +*/ +void QmlBasicScript::clear() +{ + if (flags & QmlBasicScriptPrivate::OwnData) + free(d); + if (rc) rc->release(); + d = 0; + rc = 0; + flags = 0; +} + +/*! + Return the script state memory for this script instance. This memory should + only be destroyed by calling deleteScriptState(). + */ +void *QmlBasicScript::newScriptState() +{ + if (!d) { + return 0; + } else { + void *rv = ::malloc(d->stateSize * sizeof(QmlBasicScriptNodeCache)); + ::memset(rv, 0, d->stateSize * sizeof(QmlBasicScriptNodeCache)); + return rv; + } +} + +/*! + Delete the \a data previously allocated by newScriptState(). + */ +void QmlBasicScript::deleteScriptState(void *data) +{ + if (!data) return; + Q_ASSERT(d); + clearCache(data); + free(data); +} + +/*! + Dump the script instructions to stderr for debugging. + */ +void QmlBasicScript::dump() +{ + if (!d) + return; + + qWarning() << d->instructionCount << "instructions:"; + const char *data = d->data(); + for (int ii = 0; ii < d->instructionCount; ++ii) { + const ScriptInstruction &instr = d->instructions()[ii]; + + switch(instr.type) { + case ScriptInstruction::Load: + qWarning().nospace() << "LOAD\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Fetch: + qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Add: + qWarning().nospace() << "ADD"; + break; + case ScriptInstruction::Subtract: + qWarning().nospace() << "SUBTRACT"; + break; + case ScriptInstruction::Multiply: + qWarning().nospace() << "MULTIPLY"; + break; + case ScriptInstruction::Equals: + qWarning().nospace() << "EQUALS"; + break; + case ScriptInstruction::Int: + qWarning().nospace() << "INT\t\t" << instr.integer.value; + break; + case ScriptInstruction::Bool: + qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; + break; + default: + qWarning().nospace() << "UNKNOWN"; + break; + } + } +} + +/*! + Return true if this is a valid script binding, otherwise returns false. + */ +bool QmlBasicScript::isValid() const +{ + return d != 0; +} + +/*! + Compile \a v and return true if the compilation is successful, otherwise + returns false. + */ +bool QmlBasicScript::compile(const QmlParser::Variant &v) +{ + if (!v.asAST()) return false; + + QByteArray expr = v.asScript().toLatin1(); + const char *src = expr.constData(); + + QmlBasicScriptCompiler bsc; + bsc.script = this; + + if (d) { + if (flags & QmlBasicScriptPrivate::OwnData) + free(d); + d = 0; + flags = 0; + } + + if (bsc.compile(v.asAST())) { + int len = ::strlen(src); + flags = QmlBasicScriptPrivate::OwnData; + int size = sizeof(QmlBasicScriptPrivate) + + bsc.bytecode.count() * sizeof(ScriptInstruction) + + QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); + d = (QmlBasicScriptPrivate *) malloc(size); + d->size = size; + d->stateSize = bsc.stateSize; + d->instructionCount = bsc.bytecode.count(); + d->exprLen = len; + ::memcpy((char *)d->expr(), src, len + 1); + for (int ii = 0; ii < d->instructionCount; ++ii) + d->instructions()[ii] = bsc.bytecode.at(ii); + ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); + } + + return d != 0; +} + +bool QmlBasicScriptCompiler::compile(JavaScript::AST::Node *node) +{ + return compileExpression(node); +} + +using namespace JavaScript; +bool QmlBasicScriptCompiler::tryConstant(JavaScript::AST::Node *node) +{ + if (node->kind == AST::Node::Kind_TrueLiteral || + node->kind == AST::Node::Kind_FalseLiteral) + return true; + + if (node->kind == AST::Node::Kind_NumericLiteral) { + AST::NumericLiteral *lit = static_cast(node); + + return lit->suffix == AST::NumericLiteral::noSuffix && + double(int(lit->value)) == lit->value; + } + + return false; +} + +bool QmlBasicScriptCompiler::parseConstant(JavaScript::AST::Node *node) +{ + ScriptInstruction instr; + + if (node->kind == AST::Node::Kind_NumericLiteral) { + AST::NumericLiteral *lit = static_cast(node); + instr.type = ScriptInstruction::Int; + instr.integer.value = int(lit->value); + } else { + instr.type = ScriptInstruction::Bool; + instr.boolean.value = node->kind == AST::Node::Kind_TrueLiteral; + } + + bytecode.append(instr); + + return true; +} + +bool QmlBasicScriptCompiler::tryName(JavaScript::AST::Node *node) +{ + return node->kind == AST::Node::Kind_IdentifierExpression || + node->kind == AST::Node::Kind_FieldMemberExpression; +} + +bool QmlBasicScriptCompiler::parseName(AST::Node *node) +{ + bool load = false; + + QString name; + if (node->kind == AST::Node::Kind_IdentifierExpression) { + name = static_cast(node)->name->asString(); + load = true; + } else if (node->kind == AST::Node::Kind_FieldMemberExpression) { + AST::FieldMemberExpression *expr = static_cast(node); + + if (!parseName(expr->base)) + return false; + + name = expr->name->asString(); + } else { + return false; + } + + int nref = data.count(); + data.append(name.toUtf8()); + data.append('\0'); + ScriptInstruction instr; + if (load) + instr.type = ScriptInstruction::Load; + else + instr.type = ScriptInstruction::Fetch; + instr.fetch.idx = nref; + bytecode.append(instr); + ++stateSize; + + return true; +} + +bool QmlBasicScriptCompiler::compileExpression(JavaScript::AST::Node *node) +{ + if (tryBinaryExpression(node)) + return compileBinaryExpression(node); + else if (tryConstant(node)) + return parseConstant(node); + else if (tryName(node)) + return parseName(node); + else + return false; +} + +bool QmlBasicScriptCompiler::tryBinaryExpression(AST::Node *node) +{ + if (node->kind == AST::Node::Kind_BinaryExpression) { + AST::BinaryExpression *expr = + static_cast(node); + + if (expr->op == QSOperator::Add || + expr->op == QSOperator::Sub || + expr->op == QSOperator::Equal || + expr->op == QSOperator::And || + expr->op == QSOperator::Mul) + return true; + } + return false; +} + +bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) +{ + if (node->kind == AST::Node::Kind_BinaryExpression) { + AST::BinaryExpression *expr = + static_cast(node); + + if (!compileExpression(expr->left)) return false; + if (!compileExpression(expr->right)) return false; + + ScriptInstruction instr; + switch (expr->op) { + case QSOperator::Add: + instr.type = ScriptInstruction::Add; + break; + case QSOperator::Sub: + instr.type = ScriptInstruction::Subtract; + break; + case QSOperator::Equal: + instr.type = ScriptInstruction::Equals; + break; + case QSOperator::And: + instr.type = ScriptInstruction::And; + break; + case QSOperator::Mul: + instr.type = ScriptInstruction::Multiply; + break; + default: + return false; + } + + bytecode.append(instr); + return true; + } + return false; +} + +/*! + \internal +*/ +void QmlBasicScript::clearCache(void *voidCache) +{ + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast(voidCache); + + for (int ii = 0; ii < d->stateSize; ++ii) { + if (!dataCache[ii].isCore() && !dataCache[ii].isVariant() && + dataCache[ii].object) { + QMetaObject::removeGuard(&dataCache[ii].object); + dataCache[ii].object = 0; + } + dataCache[ii].clear(); + } +} + +void QmlBasicScript::guard(QmlBasicScriptNodeCache &n) +{ + if (n.object) { + if (n.isVariant()) { + } else if (n.isCore()) { + n.metaObject = + n.object->metaObject(); + } else { + QMetaObject::addGuard(&n.object); + } + } +} + +bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) +{ + return n.object == obj && + (!n.isCore() || obj->metaObject() == n.metaObject); +} + + +/*! + \enum QmlBasicScript::CacheState + \value NoChange The query has not change. Any previous monitoring is still + valid. + \value Incremental The query has been incrementally changed. Any previous + monitoring is still valid, but needs to have the fresh properties added to + it. + \value Reset The entire query has been reset from the beginning. Any previous + monitoring is now invalid. +*/ + +/*! + Run the script in \a context and return the result. \a voidCache should + contain state memory previously acquired from newScript. + */ +QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) +{ + if (!isValid()) + return QVariant(); + + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast(voidCache); + int dataCacheItem; + QStack stack; + + bool resetting = false; + bool hasReset = false; + + const char *data = d->data(); + + if (dataCache[0].type == QmlBasicScriptNodeCache::Invalid) { + resetting = true; + hasReset = true; + } + + CacheState state = NoChange; + + dataCacheItem = 0; + for (int idx = 0; idx < d->instructionCount; ++idx) { + const ScriptInstruction &instr = d->instructions()[idx]; + + switch(instr.type) { + case ScriptInstruction::Load: // either an object or a property + case ScriptInstruction::Fetch: // can only be a property + { + const char *id = data + instr.fetch.idx; + QmlBasicScriptNodeCache &n = dataCache[dataCacheItem]; + + if (instr.type == ScriptInstruction::Load) { + + if (n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast(context->d_ptr)); + state = Incremental; + } + + if(!n.isValid()) + qWarning("ReferenceError: %s is not defined", id); + + } else { // instr.type == ScriptInstruction::Fetch + + QVariant o = stack.pop(); + QObject *obj = qvariant_cast(o); + if (!obj) { + if (n.type == QmlBasicScriptNodeCache::Invalid) { + if (scriptWarnings()) + qWarning() << "QmlBasicScript: Unable to convert" << o; + *cached = state; + return QVariant(); + } else { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + } else if (n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); + guard(n); + state = Incremental; + } else if (!valid(n, obj)) { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + + } + + QVariant var = n.value(id); + stack.push(var); + ++dataCacheItem; + } + break; + case ScriptInstruction::Int: + stack.push(QVariant(instr.integer.value)); + break; + case ScriptInstruction::Bool: + stack.push(QVariant(instr.boolean.value)); + break; + case ScriptInstruction::Add: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() + lhs.toDouble()); + } + break; + case ScriptInstruction::Subtract: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(lhs.toDouble() - rhs.toDouble()); + } + break; + case ScriptInstruction::Multiply: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() * lhs.toDouble()); + } + break; + case ScriptInstruction::Equals: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs == lhs); + } + break; + case ScriptInstruction::And: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toBool() && lhs.toBool()); + } + break; + default: + break; + } + } + + *cached = state; + + if (stack.isEmpty()) + return QVariant(); + else + return stack.top(); +} + +/*! + Return a pointer to the script's compile data, or null if there is no data. + */ +const char *QmlBasicScript::compileData() const +{ + return (const char *)d; +} + +/*! + Return the size of the script's compile data, or zero if there is no data. + The size will always be a multiple of 4. + */ +unsigned int QmlBasicScript::compileDataSize() const +{ + if (d) + return d->size; + else + return 0; +} + +bool QmlBasicScript::isSingleLoad() const +{ + if (!d) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::Load; +} + +QByteArray QmlBasicScript::singleLoadTarget() const +{ + if (!isSingleLoad()) + return QByteArray(); + + // We know there is one instruction and it is a load + return QByteArray(d->data() + d->instructions()[0].fetch.idx); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h new file mode 100644 index 0000000..1117e11 --- /dev/null +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_P_H +#define QMLBASICSCRIPT_P_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QmlRefCount; +class QmlContext; +class QmlBasicScriptPrivate; +class QmlBasicScriptNodeCache; +class QmlBasicScript +{ +public: + QmlBasicScript(); + QmlBasicScript(const char *, QmlRefCount * = 0); + ~QmlBasicScript(); + + // Always 4-byte aligned + const char *compileData() const; + unsigned int compileDataSize() const; + + QByteArray expression() const; + + bool compile(const QmlParser::Variant &); + bool isValid() const; + + void clear(); + + void dump(); + void *newScriptState(); + void deleteScriptState(void *); + + enum CacheState { NoChange, Incremental, Reset }; + QVariant run(QmlContext *, void *, CacheState *); + + // Optimization opportunities + bool isSingleLoad() const; + QByteArray singleLoadTarget() const; + +private: + int flags; + QmlBasicScriptPrivate *d; + QmlRefCount *rc; + + void clearCache(void *); + void guard(QmlBasicScriptNodeCache &); + bool valid(QmlBasicScriptNodeCache &, QObject *); +}; + +class QmlContextPrivate; +class QDebug; +class QmlBasicScriptNodeCache +{ +public: + QObject *object; + const QMetaObject *metaObject; + enum { Invalid, + Core, + Attached, + Signal, + SignalProperty, + Variant + } type; + union { + int core; + QObject *attached; + QmlContextPrivate *context; + }; + int coreType; + int contextIndex; + + bool isValid() const { return type != Invalid; } + bool isCore() const { return type == Core; } + bool isVariant() const { return type == Variant; } + void clear(); + QVariant value(const char *) const; +}; + +QDebug operator<<(QDebug, const QmlBasicScriptNodeCache &); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLBASICSCRIPT_P_H + + diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index d5157b6..351e0bd 100644 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -69,8 +69,8 @@ QmlBindableValue::QmlBindableValue(void *data, QmlRefCount *rc, QObject *obj, QO { } -QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, bool sse, QObject *parent) -: QmlPropertyValueSource(*new QmlBindableValuePrivate, parent), QmlExpression(QmlContext::activeContext(), str, obj, sse) +QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, QObject *parent) +: QmlPropertyValueSource(*new QmlBindableValuePrivate, parent), QmlExpression(QmlContext::activeContext(), str, obj) { } diff --git a/src/declarative/qml/qmlbindablevalue.h b/src/declarative/qml/qmlbindablevalue.h index c5bb97b..71a7051 100644 --- a/src/declarative/qml/qmlbindablevalue.h +++ b/src/declarative/qml/qmlbindablevalue.h @@ -63,7 +63,7 @@ class Q_DECLARATIVE_EXPORT QmlBindableValue : public QmlPropertyValueSource, Q_OBJECT public: QmlBindableValue(QObject *parent); - QmlBindableValue(const QString &, QObject *, bool = true, QObject *parent=0); + QmlBindableValue(const QString &, QObject *, QObject *parent=0); QmlBindableValue(void *, QmlRefCount *, QObject *, QObject *parent); ~QmlBindableValue(); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index b9a848a..75d01c2 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -46,7 +46,7 @@ #include #include #include "private/qmetaobjectbuilder_p.h" -#include +#include "qmlbasicscript_p.h" #include #include #include @@ -1415,7 +1415,7 @@ bool QmlCompiler::compileBinding(const QmlParser::Variant &bind, COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); QmlBasicScript bs; - bs.compile(bind.asScript().toLatin1()); + bs.compile(bind); int bref; if (bs.isValid()) { @@ -1447,6 +1447,47 @@ bool QmlCompiler::compileBinding(const QmlParser::Variant &bind, return true; } +#if 0 + +#include +#ifdef Q_CC_GNU +#include +#endif + +//////////////////////////////////////////////////////////////////////////////// +// AST Dump +//////////////////////////////////////////////////////////////////////////////// +class Dump: protected JavaScript::AST::Visitor +{ + std::ostream &out; + int depth; + +public: + Dump(std::ostream &out) + : out(out), depth(-1) + { } + + void operator()(JavaScript::AST::Node *node) + { JavaScript::AST::Node::acceptChild(node, this); } + +protected: + virtual bool preVisit(JavaScript::AST::Node *node) + { + const char *name = typeid(*node).name(); +#ifdef Q_CC_GNU + name = abi::__cxa_demangle(name, 0, 0, 0) + 17; +#endif + std::cout << std::string(++depth, ' ') << name << std::endl; + return true; + } + + virtual void postVisit(JavaScript::AST::Node *) + { + --depth; + } +}; +#endif + // Update the init instruction with final data, and optimize some simple // bindings int QmlCompiler::finalizeComponent(int patch) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 3db8d92..c67c220 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -820,15 +820,9 @@ QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefC { } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile) +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) : q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) { - if (ssecompile) { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer pt; -#endif - sse.compile(expr.toLatin1()); - } } QmlExpressionPrivate::~QmlExpressionPrivate() @@ -863,19 +857,6 @@ QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, d->me = me; } -/*! \internal */ -QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, - QObject *me, bool ssecompile) -: d(new QmlExpressionPrivate(this, expr, ssecompile)) -{ - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = me; -} - /*! Create a QmlExpression object. @@ -885,7 +866,7 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, */ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, QObject *scope) -: d(new QmlExpressionPrivate(this, expression, true)) +: d(new QmlExpressionPrivate(this, expression)) { d->ctxt = ctxt; if(ctxt && ctxt->engine()) @@ -956,10 +937,7 @@ void QmlExpression::setExpression(const QString &expression) d->expression = expression; - if (d->expression.isEmpty()) - d->sse.clear(); - else - d->sse.compile(expression.toLatin1()); + d->sse.clear(); } /*! @@ -1245,13 +1223,7 @@ QmlExpressionObject::QmlExpressionObject(QObject *parent) the expression's execution. */ QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) -: QObject(parent), QmlExpression(ctxt, expression, scope, true) -{ -} - -/*! \internal */ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expr, QObject *scope, bool sse) -: QmlExpression(ctxt, expr, scope, sse) +: QObject(parent), QmlExpression(ctxt, expression, scope) { } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 0dc4736..89b0a4a 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include @@ -265,7 +265,7 @@ class QmlExpressionPrivate { public: QmlExpressionPrivate(QmlExpression *); - QmlExpressionPrivate(QmlExpression *, const QString &expr, bool); + QmlExpressionPrivate(QmlExpression *, const QString &expr); QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); ~QmlExpressionPrivate(); diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index ea3b093..651fd9c 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -62,7 +62,6 @@ class Q_DECLARATIVE_EXPORT QmlExpression public: QmlExpression(); QmlExpression(QmlContext *, const QString &, QObject *); - QmlExpression(QmlContext *, const QString &, QObject *, bool); QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me); virtual ~QmlExpression(); @@ -101,7 +100,6 @@ class Q_DECLARATIVE_EXPORT QmlExpressionObject : public QObject, public: QmlExpressionObject(QObject *parent = 0); QmlExpressionObject(QmlContext *, const QString &, QObject *scope, QObject *parent = 0); - QmlExpressionObject(QmlContext *, const QString &, QObject *scope, bool); QmlExpressionObject(QmlContext *, void *, QmlRefCount *, QObject *); public Q_SLOTS: diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 5c2a69f..f262b5d 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -52,7 +52,6 @@ #include #include "private/qmlcomponent_p.h" #include -#include #include "private/qmetaobjectbuilder_p.h" #include #include diff --git a/src/declarative/qml/script/generator/generator.pro b/src/declarative/qml/script/generator/generator.pro deleted file mode 100644 index 1b2a4c7..0000000 --- a/src/declarative/qml/script/generator/generator.pro +++ /dev/null @@ -1,11 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Mon Apr 2 20:15:52 2007 -###################################################################### - -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += main.cpp diff --git a/src/declarative/qml/script/generator/main.cpp b/src/declarative/qml/script/generator/main.cpp deleted file mode 100644 index a841cbc..0000000 --- a/src/declarative/qml/script/generator/main.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** This file is part of the $PACKAGE_NAME$. -** -** Copyright (C) $THISYEAR$ $COMPANY_NAME$. -** -** $QT_EXTENDED_DUAL_LICENSE$ -** -****************************************************************************/ - -#include -#include - - -QT_BEGIN_NAMESPACE -struct Keyword { - const char *lexem; - const char *token; -}; - -struct State -{ - State(const char* token) : token(token) - { - ::memset(next, 0, sizeof(next)); - } - State(const State &other) : token(other.token) - { - ::memcpy(next, other.next, sizeof(next)); - } - State &operator=(const State &other) - { - token = other.token; - ::memcpy(next, other.next, sizeof(next)); - return *this; - } - - QByteArray token; - int next[128]; -}; - -Keyword keywords[] = -{ - {"<", "LANGLE" }, - {">", "RANGLE" }, - {"+", "PLUS" }, - {"-", "MINUS" }, - {"*", "STAR" }, - {"==", "EQUALS" }, - {"&&", "AND" }, - {".", "DOT"}, - {"true", "TOKEN_TRUE"}, - {"false", "TOKEN_FALSE"}, - {" ", "WHITESPACE"}, - {"\t", "WHITESPACE"}, - {0, 0} -}; - -bool is_character(char s) -{ - return (s >= 'a' && s <= 'z') || - (s >= 'A' && s <= 'Z') || - (s >= '0' && s <= '9') || - s == '_'; -} - -void newState(QList &states, const char *token, const char *lexem) -{ - int state = 0; - bool character = is_character(*lexem); - - while(*lexem) { - int next = states[state].next[(int)*lexem]; - - if (!next) { - next = states.size(); - states += State(character?"CHARACTER":"INCOMPLETE"); - states[state].next[(int)*lexem] = next; - } - - state = next; - ++lexem; - character = character && is_character(*lexem); - } - - states[state].token = token; -} - -void newState(QList &states, const char *token, char lexem) -{ - int next = states[0].next[(int)lexem]; - if (!next) { - next = states.size(); - states += State(token); - states[0].next[(int)lexem] = next; - } else { - states[next].token = token; - } -} - -int main() -{ - QList states; - states += State("NOTOKEN"); - - // identifiers - for (int cc = 'a'; cc <= 'z'; ++cc) - newState(states, "CHARACTER", cc); - for (int cc = 'A'; cc <= 'Z'; ++cc) - newState(states, "CHARACTER", cc); - newState(states, "CHARACTER", '_'); - - // add digits - for (int cc = '0'; cc <= '9'; ++cc) - newState(states, "DIGIT", cc); - - // keywords - for (int ii = 0; keywords[ii].lexem; ++ii) - newState(states, keywords[ii].token, keywords[ii].lexem); - - ::printf("static const struct\n{\n" - " Token token;\n" - " char next[128];\n" - "} keywords[] = {\n"); - - for (int ii = 0; ii < states.size(); ++ii) { - printf("%s { %s, { ", ii?",\n":"", states[ii].token.data()); - for (int jj = 0; jj < 128; jj++) - printf("%s%d", jj?",":"", states[ii].next[jj]); - printf(" } }"); - } - - printf("\n};\n"); -} -QT_END_NAMESPACE diff --git a/src/declarative/qml/script/instructions.h b/src/declarative/qml/script/instructions.h deleted file mode 100644 index a21cbce..0000000 --- a/src/declarative/qml/script/instructions.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _INSTRUCTIONS_H_ -#define _INSTRUCTIONS_H_ - -struct ScriptInstruction { - enum { - Load, // fetch - Fetch, // fetch - - Add, // NA - Subtract, // NA - Multiply, // NA - Equals, // NA - And, // NA - - Int, // integer - Bool, // boolean - } type; - - union { - struct { - int idx; - } fetch; - struct { - int value; - } integer; - struct { - bool value; - } boolean; - }; -}; - -#endif // _INSTRUCTIONS_H_ diff --git a/src/declarative/qml/script/keywords.cpp b/src/declarative/qml/script/keywords.cpp deleted file mode 100644 index 4cde65b..0000000 --- a/src/declarative/qml/script/keywords.cpp +++ /dev/null @@ -1,89 +0,0 @@ -static const struct -{ - Token token; - char next[128]; -} keywords[] = { - { NOTOKEN, { 0,0,0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,0,0,0,0,0,71,0,0,0,68,66,0,67,73,0,54,55,56,57,58,59,60,61,62,63,0,0,64,69,65,0,0,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,0,0,0,0,53,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { LANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { RANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { PLUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { MINUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { STAR, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { EQUALS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { AND, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { DOT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { TOKEN_TRUE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { TOKEN_FALSE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, - { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } -}; diff --git a/src/declarative/qml/script/lexer.cpp b/src/declarative/qml/script/lexer.cpp deleted file mode 100644 index d3ef935..0000000 --- a/src/declarative/qml/script/lexer.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -** -** This file is part of the $PACKAGE_NAME$. -** -** Copyright (C) $THISYEAR$ $COMPANY_NAME$. -** -** $QT_EXTENDED_DUAL_LICENSE$ -** -****************************************************************************/ - -#include -#include "lexer.h" -#include "keywords.cpp" -#include - - -QT_BEGIN_NAMESPACE -QList tokenize(const char *text) -{ - QList rv; - - int lineNo = 0; - int charNo = 0; - int state = 0; - int tokenStart = 0; - bool other = false; - - const char *textprog = text; - - bool done = false; - while (!done) { - char textchar = *textprog; - done = !textchar; - - if (other) { - if (keywords[state].next[(int)textchar]) { - - // Do other token - LexerToken token; - token.token = OTHER; - token.start = tokenStart; - token.end = textprog - text - 1; - token.line = lineNo + 1; - token.offset = charNo - (token.end - token.start); - tokenStart = token.end + 1; - rv.append(token); - other = false; - - } else { - goto continue_loop; - } - } - - if (keywords[state].next[(int)textchar]) { - - state = keywords[state].next[(int)textchar]; - - } else if (0 == state || - keywords[state].token == INCOMPLETE) { - - other = true; - if (keywords[state].token == INCOMPLETE) { - state = 0; - continue; - } - - } else { - - // Token completed - Token tokenType = keywords[state].token; - bool tokenCollapsed = false; - if (tokenType == CHARACTER || - tokenType == DIGIT || - tokenType == WHITESPACE) { - - Token lastTokenType = - rv.isEmpty()?NOTOKEN:rv.last().token; - if (tokenType == lastTokenType) { - - rv.last().end = textprog - text - 1; - tokenStart = rv.last().end + 1; - - tokenCollapsed = true; - } - } - - if (!tokenCollapsed) { - LexerToken token; - token.token = keywords[state].token; - token.start = tokenStart; - token.end = textprog - text - 1; - token.line = lineNo + 1; - token.offset = charNo - (token.end - token.start); - tokenStart = token.end + 1; - rv.append(token); - } - - state = keywords[0].next[(int)textchar]; - if (0 == state) - other = true; - } - -continue_loop: - // Reset error reporting variables - if (textchar == '\n') { - ++lineNo; - charNo = 0; - } else { - charNo++; - } - - // Increment ptrs - ++textprog; - } - - if (other && ((textprog - text - 1) != tokenStart)) { - // Do other token - LexerToken token; - token.token = OTHER; - token.start = tokenStart; - token.end = textprog - text - 1; - token.line = lineNo + 1; - token.offset = charNo - (token.end - token.start); - tokenStart = token.end + 1; - rv.append(token); - other = false; - } - return rv; -} - -void dumpTokens(const char *text, const QList &tokens) -{ - for (int ii = 0; ii < tokens.count(); ++ii) { - QByteArray ba(text + tokens.at(ii).start, tokens.at(ii).end - tokens.at(ii).start + 1); - qWarning() << tokens.at(ii).line << ":" << tokens.at(ii).offset << tokenToString(tokens.at(ii).token) << "(" << tokens.at(ii).start << "-" << tokens.at(ii).end << ")" << ba; - } -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/script/lexer.h b/src/declarative/qml/script/lexer.h deleted file mode 100644 index 9de4afd..0000000 --- a/src/declarative/qml/script/lexer.h +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** This file is part of the $PACKAGE_NAME$. -** -** Copyright (C) $THISYEAR$ $COMPANY_NAME$. -** -** $QT_EXTENDED_DUAL_LICENSE$ -** -****************************************************************************/ - -#ifndef LEXER_H -#define LEXER_H - -#include -#include "tokens.h" - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) -struct LexerToken -{ - LexerToken() : token(NOTOKEN), start(-1), end(-1), line(-1), offset(-1) {} - LexerToken(const LexerToken &other) : token(other.token), - start(other.start), - end(other.end), - line(other.line), - offset(other.offset) {} - LexerToken &operator=(const LexerToken &other) { - token = other.token; - start = other.start; - end = other.end; - line = other.line; - offset = other.offset; - return *this; - } - - Token token; - int start; - int end; - int line; - int offset; -}; - -QList tokenize(const char *text); -void dumpTokens(const char *text, const QList &tokens); - - -QT_END_NAMESPACE - -QT_END_HEADER -#endif diff --git a/src/declarative/qml/script/qmlbasicscript.cpp b/src/declarative/qml/script/qmlbasicscript.cpp deleted file mode 100644 index 37a6678..0000000 --- a/src/declarative/qml/script/qmlbasicscript.cpp +++ /dev/null @@ -1,921 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -****************************************************************************/ - -#include "qmlbasicscript.h" -#include "qmlbasicscript_p.h" -#include "lexer.h" -#include -#include -#include -#include -#include -#include -#include - - -QT_BEGIN_NAMESPACE -DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); - -class QmlBasicScriptPrivate -{ -public: - enum Flags { OwnData = 0x00000001 }; - - int size; - int stateSize; - int instructionCount; - int exprLen; - - ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } - - const char *expr() const - { - return (const char *)(instructions() + instructionCount); - } - - const char *data() const - { - return (const char *)(instructions() + instructionCount) + exprLen + 1; - } - - static unsigned int alignRound(int s) - { - if (s % 4) - s += 4 - (s % 4); - return s; - } -}; - -QDebug operator<<(QDebug lhs, const QmlBasicScriptNodeCache &rhs) -{ - switch(rhs.type) { - case QmlBasicScriptNodeCache::Invalid: - lhs << "Invalid"; - break; - case QmlBasicScriptNodeCache::Core: - lhs << "Core" << rhs.object << rhs.core; - break; - case QmlBasicScriptNodeCache::Attached: - lhs << "Attached" << rhs.object << rhs.attached; - break; - case QmlBasicScriptNodeCache::Signal: - lhs << "Signal" << rhs.object << rhs.core; - break; - case QmlBasicScriptNodeCache::SignalProperty: - lhs << "SignalProperty" << rhs.object << rhs.core; - break; - case QmlBasicScriptNodeCache::Variant: - lhs << "Variant" << rhs.context; - break; - } - - return lhs; -} - -void QmlBasicScriptNodeCache::clear() -{ - object = 0; - metaObject = 0; - type = Invalid; -} - -static QVariant toObjectOrVariant(const QVariant &v) -{ - switch(v.type()) { - case QVariant::String: - case QVariant::UInt: - case QVariant::Int: - case 135: - case QVariant::Double: - case QVariant::Color: - case QVariant::Bool: - default: - return v; - case QVariant::UserType: - { - QObject *o = QmlMetaType::toQObject(v); - if (o) - return qVariantFromValue(o); - else - return v; - } - break; - } -} - -static QVariant fetch_value(QObject *o, int idx, int type) -{ - switch(type) { - case QVariant::String: - { - QString val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::UInt: - { - uint val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Int: - { - int val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case 135: - { - float val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Double: - { - double val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Color: - { - QColor val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - case QVariant::Bool: - { - bool val; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant(val); - } - break; - default: - { - if (QmlMetaType::isObject(type)) { - // NOTE: This assumes a cast to QObject does not alter the - // object pointer - QObject *val = 0; - void *args[] = { &val, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); - return QVariant::fromValue(val); - } else { - QVariant var = o->metaObject()->property(idx).read(o); - if (QmlMetaType::isObject(var.userType())) { - QObject *obj = 0; - obj = *(QObject **)var.data(); - var = QVariant::fromValue(obj); - } - return var; - } - } - break; - }; -} - -QVariant QmlBasicScriptNodeCache::value(const char *name) const -{ - //QFxPerfTimer pt; - switch(type) { - case Invalid: - break; - case Core: - return fetch_value(object, core, coreType); - break; - case Attached: - return qVariantFromValue(static_cast(attached)); - break; - case Signal: - // XXX - Q_ASSERT(!"Not implemented"); - break; - case SignalProperty: - break; - case Variant: - return context->propertyValues[contextIndex]; - }; - return QVariant(); -} - -struct QmlBasicScriptCompiler -{ - QmlBasicScriptCompiler() - : script(0), stateSize(0), src(0), idx(0) {} - QmlBasicScript *script; - QList tokens; - int stateSize; - const char *src; - int idx; - - bool compile(); - bool compileExpr(); - - bool parseFetch(); - bool parseName(); - bool parseConstant(); - void skipWhitespace(); - - QByteArray data; - QList bytecode; - - QByteArray string(int, int); - Token token() const; - bool atEnd() const; - void adv(); - int index() const; -}; - -/*! - \internal - \class QmlBasicScript - \brief The QmlBasicScript class provides a fast implementation of a limited subset of JavaScript bindings. - - QmlBasicScript instances are used to accelerate binding. Instead of using - the slower, fully fledged JavaScript engine, many simple bindings can be - evaluated using the QmlBasicScript engine. - - To see if the QmlBasicScript engine can handle a binding, call compile() - and check the return value, or isValid() afterwards. - - To evaluate the binding, the QmlBasicScript instance needs some memory in - which to cache state. This may be allocated by calling newScriptState() - and destroyed by calling deleteScriptState(). The state data is then passed - to the run() method when evaluating the binding. - - To further accelerate binding, QmlBasicScript can return a precompiled - version of itself that can be saved for future use. Call compileData() to - get an opaque pointer to the compiled state, and compileDataSize() for the - size of this data in bytes. This data can be saved and passed to future - instances of the QmlBasicScript constructor. The initial copy of compile - data is owned by the QmlBindScript instance on which compile() was called. -*/ - -/*! - Create a new QmlBasicScript instance. -*/ -QmlBasicScript::QmlBasicScript() -: flags(0), d(0), rc(0) -{ -} - -/*! - Create a new QmlBasicScript instance from saved \a data. - - \a data \b must be data previously acquired from calling compileData() on a - previously created QmlBasicScript instance. Any other data will almost - certainly cause the QmlBasicScript engine to crash. - - \a data must continue to be valid throughout the QmlBasicScript instance - life. It does not assume ownership of the memory. - - If \a owner is set, it is referenced on creation and dereferenced on - destruction of this instance. -*/ -QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) -: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) -{ - if (rc) rc->addref(); -} - -/*! - Return the text of the script expression. - */ -QByteArray QmlBasicScript::expression() const -{ - if (!d) - return QByteArray(); - else - return QByteArray(d->expr()); -} - -/*! - Destroy the script instance. -*/ -QmlBasicScript::~QmlBasicScript() -{ - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - if (rc) rc->release(); - d = 0; - rc = 0; -} - -/*! - Clear this script. The object will then be in its initial state, as though - it were freshly constructed with default constructor. -*/ -void QmlBasicScript::clear() -{ - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - if (rc) rc->release(); - d = 0; - rc = 0; - flags = 0; -} - -/*! - Return the script state memory for this script instance. This memory should - only be destroyed by calling deleteScriptState(). - */ -void *QmlBasicScript::newScriptState() -{ - if (!d) { - return 0; - } else { - void *rv = ::malloc(d->stateSize * sizeof(QmlBasicScriptNodeCache)); - ::memset(rv, 0, d->stateSize * sizeof(QmlBasicScriptNodeCache)); - return rv; - } -} - -/*! - Delete the \a data previously allocated by newScriptState(). - */ -void QmlBasicScript::deleteScriptState(void *data) -{ - if (!data) return; - Q_ASSERT(d); - clearCache(data); - free(data); -} - -/*! - Dump the script instructions to stderr for debugging. - */ -void QmlBasicScript::dump() -{ - if (!d) - return; - - qWarning() << d->instructionCount << "instructions:"; - const char *data = d->data(); - for (int ii = 0; ii < d->instructionCount; ++ii) { - const ScriptInstruction &instr = d->instructions()[ii]; - - switch(instr.type) { - case ScriptInstruction::Load: - qWarning().nospace() << "LOAD\t\t" << instr.fetch.idx << "\t\t" - << QByteArray(data + instr.fetch.idx); - break; - case ScriptInstruction::Fetch: - qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" - << QByteArray(data + instr.fetch.idx); - break; - case ScriptInstruction::Add: - qWarning().nospace() << "ADD"; - break; - case ScriptInstruction::Subtract: - qWarning().nospace() << "SUBTRACT"; - break; - case ScriptInstruction::Multiply: - qWarning().nospace() << "MULTIPLY"; - break; - case ScriptInstruction::Equals: - qWarning().nospace() << "EQUALS"; - break; - case ScriptInstruction::Int: - qWarning().nospace() << "INT\t\t" << instr.integer.value; - break; - case ScriptInstruction::Bool: - qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; - break; - default: - qWarning().nospace() << "UNKNOWN"; - break; - } - } -} - -/*! - Return true if this is a valid script binding, otherwise returns false. - */ -bool QmlBasicScript::isValid() const -{ - return d != 0; -} - -/*! - Compile \a src and return true if the compilation is successful, otherwise - returns false. - */ -bool QmlBasicScript::compile(const QByteArray &src) -{ - bool rv = compile(src.constData()); - return rv; -} - -/*! - \overload - - Compile \a src and return true if the compilation is successful, otherwise - returns false. - */ -bool QmlBasicScript::compile(const char *src) -{ - if (!src) return false; - - QmlBasicScriptCompiler bsc; - bsc.script = this; - bsc.tokens = tokenize(src); - bsc.src = src; - // dumpTokens(src, bsc.tokens); - - if (d) { - if (flags & QmlBasicScriptPrivate::OwnData) - free(d); - d = 0; - flags = 0; - } - - if (bsc.compile()) { - int len = ::strlen(src); - flags = QmlBasicScriptPrivate::OwnData; - int size = sizeof(QmlBasicScriptPrivate) + - bsc.bytecode.count() * sizeof(ScriptInstruction) + - QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); - d = (QmlBasicScriptPrivate *) malloc(size); - d->size = size; - d->stateSize = bsc.stateSize; - d->instructionCount = bsc.bytecode.count(); - d->exprLen = len; - ::memcpy((char *)d->expr(), src, len + 1); - for (int ii = 0; ii < d->instructionCount; ++ii) - d->instructions()[ii] = bsc.bytecode.at(ii); - ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); - } - - return d != 0; -} - -void QmlBasicScriptCompiler::skipWhitespace() -{ - while(idx < tokens.count() && tokens.at(idx).token == WHITESPACE) - ++idx; -} - -bool QmlBasicScriptCompiler::compile() -{ - if (!compileExpr()) - return false; - - skipWhitespace(); - - if (atEnd()) - return true; - - int t = token(); - if (t != AND) - return false; - - adv(); - skipWhitespace(); - if (!compileExpr()) - return false; - - ScriptInstruction instr; - instr.type = ScriptInstruction::And; - bytecode.append(instr); - - skipWhitespace(); - - return atEnd(); -} - -bool QmlBasicScriptCompiler::compileExpr() -{ - /* - EXPRESSION := [|] - */ - - if (!parseName()) - return false; - - skipWhitespace(); - - if (atEnd()) - return true; - - int t = token(); - switch(t) { - case PLUS: - case MINUS: - /* - case LANGLE: - case RANGLE: - */ - case STAR: - case EQUALS: - break; - default: - return true; - } - adv(); - - skipWhitespace(); - - if (!parseConstant() && - !parseName()) - return false; - - ScriptInstruction instr; - switch(t) { - case PLUS: - instr.type = ScriptInstruction::Add; - break; - case MINUS: - instr.type = ScriptInstruction::Subtract; - break; - case STAR: - instr.type = ScriptInstruction::Multiply; - break; - case EQUALS: - instr.type = ScriptInstruction::Equals; - break; - default: - break; - } - bytecode.append(instr); - - skipWhitespace(); - - return true; -} - -bool QmlBasicScriptCompiler::parseName() -{ - skipWhitespace(); - - bool named = false; - bool seenchar = false; - bool seendot = false; - int namestart = -1; - bool pushed = false; - while(!atEnd()) { - int t = token(); - if (t == CHARACTER) { - named = true; - seendot = false; - seenchar = true; - namestart = index(); - adv(); - } else if (t == DIGIT) { - if (!seenchar) break; - adv(); - } else if (t == DOT) { - seendot = true; - if (namestart == -1) - break; - - seenchar = false; - QByteArray name = string(namestart, index() - 1); - int nref = data.count(); - data.append(name); - data.append('\0'); - ScriptInstruction instr; - if (pushed) - instr.type = ScriptInstruction::Fetch; - else - instr.type = ScriptInstruction::Load; - pushed = true; - instr.fetch.idx = nref; - bytecode.append(instr); - ++stateSize; - namestart = -1; - adv(); - } else { - break; - } - } - - if (namestart != -1) { - QByteArray name = string(namestart, index() - 1); - int nref = data.count(); - data.append(name); - data.append('\0'); - ScriptInstruction instr; - if (pushed) - instr.type = ScriptInstruction::Fetch; - else - instr.type = ScriptInstruction::Load; - pushed = true; - instr.fetch.idx = nref; - bytecode.append(instr); - ++stateSize; - } - - if (seendot) - return false; - else - return named; -} - -bool QmlBasicScriptCompiler::parseConstant() -{ - switch(token()) { - case DIGIT: - { - ScriptInstruction instr; - instr.type = ScriptInstruction::Int; - instr.integer.value = string(index(), index()).toUInt(); - bytecode.append(instr); - adv(); - } - break; - case TOKEN_TRUE: - case TOKEN_FALSE: - { - ScriptInstruction instr; - instr.type = ScriptInstruction::Bool; - instr.boolean.value = (token() == TOKEN_TRUE); - bytecode.append(instr); - adv(); - } - break; - - default: - return false; - } - - return true; -} - -bool QmlBasicScriptCompiler::atEnd() const -{ - return idx >= tokens.count(); -} - -Token QmlBasicScriptCompiler::token() const -{ - return tokens.at(idx).token; -} - -void QmlBasicScriptCompiler::adv() -{ - ++idx; -} - -int QmlBasicScriptCompiler::index() const -{ - return idx; -} - -QByteArray QmlBasicScriptCompiler::string(int from, int to) -{ - QByteArray rv; - for (int ii = from; ii <= to; ++ii) { - const LexerToken &token = tokens.at(ii); - rv.append(QByteArray(src + token.start, token.end - token.start + 1)); - } - return rv; -} - -/*! - \internal -*/ -void QmlBasicScript::clearCache(void *voidCache) -{ - QmlBasicScriptNodeCache *dataCache = - reinterpret_cast(voidCache); - - for (int ii = 0; ii < d->stateSize; ++ii) { - if (!dataCache[ii].isCore() && !dataCache[ii].isVariant() && - dataCache[ii].object) { - QMetaObject::removeGuard(&dataCache[ii].object); - dataCache[ii].object = 0; - } - dataCache[ii].clear(); - } -} - -void QmlBasicScript::guard(QmlBasicScriptNodeCache &n) -{ - if (n.object) { - if (n.isVariant()) { - } else if (n.isCore()) { - n.metaObject = - n.object->metaObject(); - } else { - QMetaObject::addGuard(&n.object); - } - } -} - -bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) -{ - return n.object == obj && - (!n.isCore() || obj->metaObject() == n.metaObject); -} - - -/*! - \enum QmlBasicScript::CacheState - \value NoChange The query has not change. Any previous monitoring is still - valid. - \value Incremental The query has been incrementally changed. Any previous - monitoring is still valid, but needs to have the fresh properties added to - it. - \value Reset The entire query has been reset from the beginning. Any previous - monitoring is now invalid. -*/ - -/*! - Run the script in \a context and return the result. \a voidCache should - contain state memory previously acquired from newScript. - */ -QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) -{ - if (!isValid()) - return QVariant(); - - QmlBasicScriptNodeCache *dataCache = - reinterpret_cast(voidCache); - int dataCacheItem; - QStack stack; - - bool resetting = false; - bool hasReset = false; - - const char *data = d->data(); - - if (dataCache[0].type == QmlBasicScriptNodeCache::Invalid) { - resetting = true; - hasReset = true; - } - - CacheState state = NoChange; - - dataCacheItem = 0; - for (int idx = 0; idx < d->instructionCount; ++idx) { - const ScriptInstruction &instr = d->instructions()[idx]; - - switch(instr.type) { - case ScriptInstruction::Load: // either an object or a property - case ScriptInstruction::Fetch: // can only be a property - { - const char *id = data + instr.fetch.idx; - QmlBasicScriptNodeCache &n = dataCache[dataCacheItem]; - - if (instr.type == ScriptInstruction::Load) { - - if (n.type == QmlBasicScriptNodeCache::Invalid) { - context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast(context->d_ptr)); - state = Incremental; - } - - if(!n.isValid()) - qWarning("ReferenceError: %s is not defined", id); - - } else { // instr.type == ScriptInstruction::Fetch - - QVariant o = stack.pop(); - QObject *obj = qvariant_cast(o); - if (!obj) { - if (n.type == QmlBasicScriptNodeCache::Invalid) { - if (scriptWarnings()) - qWarning() << "QmlBasicScript: Unable to convert" << o; - *cached = state; - return QVariant(); - } else { - clearCache(dataCache); - *cached = Reset; - CacheState dummy; - return run(context, voidCache, &dummy); - } - } else if (n.type == QmlBasicScriptNodeCache::Invalid) { - context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); - guard(n); - state = Incremental; - } else if (!valid(n, obj)) { - clearCache(dataCache); - *cached = Reset; - CacheState dummy; - return run(context, voidCache, &dummy); - } - - } - - QVariant var = n.value(id); - stack.push(var); - ++dataCacheItem; - } - break; - case ScriptInstruction::Int: - stack.push(QVariant(instr.integer.value)); - break; - case ScriptInstruction::Bool: - stack.push(QVariant(instr.boolean.value)); - break; - case ScriptInstruction::Add: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toDouble() + lhs.toDouble()); - } - break; - case ScriptInstruction::Subtract: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(lhs.toDouble() - rhs.toDouble()); - } - break; - case ScriptInstruction::Multiply: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toDouble() * lhs.toDouble()); - } - break; - case ScriptInstruction::Equals: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs == lhs); - } - break; - case ScriptInstruction::And: - { - QVariant rhs = stack.pop(); - QVariant lhs = stack.pop(); - - stack.push(rhs.toBool() && lhs.toBool()); - } - break; - default: - break; - } - } - - *cached = state; - - if (stack.isEmpty()) - return QVariant(); - else - return stack.top(); -} - -/*! - Return a pointer to the script's compile data, or null if there is no data. - */ -const char *QmlBasicScript::compileData() const -{ - return (const char *)d; -} - -/*! - Return the size of the script's compile data, or zero if there is no data. - The size will always be a multiple of 4. - */ -unsigned int QmlBasicScript::compileDataSize() const -{ - if (d) - return d->size; - else - return 0; -} - -bool QmlBasicScript::isSingleLoad() const -{ - if (!d) - return false; - - return d->instructionCount == 1 && - d->instructions()[0].type == ScriptInstruction::Load; -} - -QByteArray QmlBasicScript::singleLoadTarget() const -{ - if (!isSingleLoad()) - return QByteArray(); - - // We know there is one instruction and it is a load - return QByteArray(d->data() + d->instructions()[0].fetch.idx); -} - - -QT_END_NAMESPACE diff --git a/src/declarative/qml/script/qmlbasicscript.h b/src/declarative/qml/script/qmlbasicscript.h deleted file mode 100644 index 5ef2148..0000000 --- a/src/declarative/qml/script/qmlbasicscript.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBASICSCRIPT_H -#define QMLBASICSCRIPT_H - -#include "instructions.h" -#include -#include -#include "lexer.h" -#include - - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) -class QmlRefCount; -class QmlContext; -class QmlBasicScriptPrivate; -class QmlBasicScriptNodeCache; -class QmlBasicScript -{ -public: - QmlBasicScript(); - QmlBasicScript(const char *, QmlRefCount * = 0); - ~QmlBasicScript(); - - // Always 4-byte aligned - const char *compileData() const; - unsigned int compileDataSize() const; - - QByteArray expression() const; - - bool compile(const QByteArray &); - bool compile(const char *); - bool isValid() const; - - void clear(); - - void dump(); - void *newScriptState(); - void deleteScriptState(void *); - - enum CacheState { NoChange, Incremental, Reset }; - QVariant run(QmlContext *, void *, CacheState *); - - // Optimization opportunities - bool isSingleLoad() const; - QByteArray singleLoadTarget() const; - -private: - int flags; - QmlBasicScriptPrivate *d; - QmlRefCount *rc; - - void clearCache(void *); - void guard(QmlBasicScriptNodeCache &); - bool valid(QmlBasicScriptNodeCache &, QObject *); -}; - -#endif // QMLBASICSCRIPT_H - - -QT_END_NAMESPACE - -QT_END_HEADER diff --git a/src/declarative/qml/script/qmlbasicscript_p.h b/src/declarative/qml/script/qmlbasicscript_p.h deleted file mode 100644 index 3b7e966..0000000 --- a/src/declarative/qml/script/qmlbasicscript_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -****************************************************************************/ - -#ifndef QMLBASICSCRIPT_P_H -#define QMLBASICSCRIPT_P_H - -QT_BEGIN_NAMESPACE - -class QObject; -class QmlContextPrivate; -class QDebug; -class QByteArray; - -class QmlBasicScriptNodeCache -{ -public: - QObject *object; - const QMetaObject *metaObject; - enum { Invalid, - Core, - Attached, - Signal, - SignalProperty, - Variant - } type; - union { - int core; - QObject *attached; - QmlContextPrivate *context; - }; - int coreType; - int contextIndex; - - bool isValid() const { return type != Invalid; } - bool isCore() const { return type == Core; } - bool isVariant() const { return type == Variant; } - void clear(); - QVariant value(const char *) const; -}; - -QDebug operator<<(QDebug, const QmlBasicScriptNodeCache &); - -#endif // QMLBASICSCRIPT_P_H - -QT_END_NAMESPACE diff --git a/src/declarative/qml/script/script.pri b/src/declarative/qml/script/script.pri deleted file mode 100644 index 6c43efe..0000000 --- a/src/declarative/qml/script/script.pri +++ /dev/null @@ -1,11 +0,0 @@ -SOURCES += \ - qml/script/tokens.cpp \ - qml/script/lexer.cpp \ - qml/script/qmlbasicscript.cpp - -HEADERS += \ - qml/script/tokens.h \ - qml/script/lexer.h \ - qml/script/instructions.h \ - qml/script/qmlbasicscript.h \ - qml/script/qmlbasicscript_p.h diff --git a/src/declarative/qml/script/tokens.cpp b/src/declarative/qml/script/tokens.cpp deleted file mode 100644 index a2fb100..0000000 --- a/src/declarative/qml/script/tokens.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** This file is part of the $PACKAGE_NAME$. -** -** Copyright (C) $THISYEAR$ $COMPANY_NAME$. -** -** $QT_EXTENDED_DUAL_LICENSE$ -** -****************************************************************************/ - -#include "tokens.h" - - -/*! - Returns a string representation of token \a tok. -*/ -const char *tokenToString(Token tok) -{ - switch(tok) { -#define CASE(X) case X: return #X; - CASE(NOTOKEN) - CASE(INCOMPLETE) - CASE(WHITESPACE) - CASE(LANGLE) - CASE(RANGLE) - CASE(PLUS) - CASE(MINUS) - CASE(STAR) - CASE(EQUALS) - CASE(DOT) - CASE(CHARACTER) - CASE(DIGIT) - CASE(OTHER) - CASE(AND) - case TOKEN_TRUE: - return "TRUE"; - case TOKEN_FALSE: - return "FALSE"; -#undef CASE - } - return 0; -} - diff --git a/src/declarative/qml/script/tokens.h b/src/declarative/qml/script/tokens.h deleted file mode 100644 index 753e40c..0000000 --- a/src/declarative/qml/script/tokens.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** This file is part of the $PACKAGE_NAME$. -** -** Copyright (C) $THISYEAR$ $COMPANY_NAME$. -** -** $QT_EXTENDED_DUAL_LICENSE$ -** -****************************************************************************/ - -#ifndef TOKENS_H -#define TOKENS_H - -enum Token { - // Lexer tokens - NOTOKEN, - INCOMPLETE, - WHITESPACE, - LANGLE, - RANGLE, - PLUS, - MINUS, - STAR, - EQUALS, - AND, - DOT, - CHARACTER, - DIGIT, - TOKEN_TRUE, - TOKEN_FALSE, - OTHER -}; - -const char *tokenToString(Token); - -#endif -- cgit v0.12 From 1090d5d1fad890d9f43e87e19277e1f624921d6d Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 28 May 2009 13:25:31 +1000 Subject: Delay the compilation of bindings until the end This way we have a better understanding of the complete context in which the binding will be executed. --- src/declarative/qml/qmlcompiler.cpp | 175 +++++++++++++++----------------- src/declarative/qml/qmlcompiler_p.h | 14 ++- src/declarative/qml/qmlparser.cpp | 17 ++-- src/declarative/qml/qmlparser_p.h | 3 + src/declarative/qml/qmlscriptparser.cpp | 1 + 5 files changed, 107 insertions(+), 103 deletions(-) diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 75d01c2..3029934 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -736,10 +736,8 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); + finalizeComponent(count); create.createComponent.count = output->bytecode.count() - count; - - int inc = finalizeComponent(count); - create.createComponent.count += inc; compileState = oldComponentCompileState; return true; } @@ -1125,9 +1123,7 @@ bool QmlCompiler::compileListProperty(QmlParser::Property *prop, COMPILE_EXCEPTION("Can only assign one binding to lists"); assignedBinding = true; - COMPILE_CHECK(compileBinding(v->value, prop, ctxt, - obj->metaObject(), - v->location.start.line)); + COMPILE_CHECK(compileBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; } else { COMPILE_EXCEPTION("Cannot assign primitives to lists"); @@ -1296,9 +1292,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, if (v->value.isScript()) { - COMPILE_CHECK(compileBinding(v->value, prop, ctxt, - obj->metaObject(), - v->location.start.line)); + COMPILE_CHECK(compileBinding(v, prop, ctxt)); v->type = Value::PropertyBinding; @@ -1403,46 +1397,27 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } -bool QmlCompiler::compileBinding(const QmlParser::Variant &bind, +bool QmlCompiler::compileBinding(QmlParser::Value *value, QmlParser::Property *prop, - int ctxt, const QMetaObject *mo, qint64 line) + int ctxt) { - Q_ASSERT(mo); Q_ASSERT(prop->index); + Q_ASSERT(prop->parent); + Q_ASSERT(prop->parent->metaObject()); - QMetaProperty mp = mo->property(prop->index); + QMetaProperty mp = prop->parent->metaObject()->property(prop->index); if (!mp.isWritable() && !QmlMetaType::isList(prop->type)) COMPILE_EXCEPTION2(prop, "Cannot assign binding to read-only property"); - QmlBasicScript bs; - bs.compile(bind); - - int bref; - if (bs.isValid()) { - bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); - } else { - bref = output->indexForString(bind.asScript()); - } - - QmlInstruction assign; - assign.assignBinding.context = ctxt; - assign.line = line; - - if (bs.isValid()) - assign.type = QmlInstruction::StoreCompiledBinding; - else - assign.type = QmlInstruction::StoreBinding; - - assign.assignBinding.property = prop->index; - assign.assignBinding.value = bref; - assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); BindingReference reference; - reference.expression = bind; + reference.expression = value->value; reference.property = prop; + reference.value = value; reference.instructionIdx = output->bytecode.count(); + reference.bindingContext = ctxt; compileState.bindings << reference; - output->bytecode << assign; + output->bytecode << QmlInstruction();; return true; } @@ -1490,81 +1465,95 @@ protected: // Update the init instruction with final data, and optimize some simple // bindings -int QmlCompiler::finalizeComponent(int patch) +void QmlCompiler::finalizeComponent(int patch) { - int saveCount = 0; - int newInstrs = 0; - for (int ii = 0; ii < compileState.bindings.count(); ++ii) { const BindingReference &binding = compileState.bindings.at(ii); + finalizeBinding(binding); + } - QmlInstruction &instr = output->bytecode[binding.instructionIdx]; - - if (instr.type == QmlInstruction::StoreCompiledBinding) { - QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); - - if (s.isSingleLoad()) { - QString slt = QLatin1String(s.singleLoadTarget()); - if (!slt.at(0).isUpper()) - continue; - - if (compileState.ids.contains(slt) && - instr.assignBinding.category == QmlMetaProperty::Object) { + output->bytecode[patch].init.dataSize = compileState.savedObjects;; + output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); + output->bytecode[patch].init.parserStatusSize = + compileState.parserStatusCount; +} - IdReference reference = - compileState.ids[slt]; +void QmlCompiler::finalizeBinding(const BindingReference &binding) +{ + QmlBasicScript bs; + bs.compile(binding.expression); - const QMetaObject *idMo = reference.object->metaObject(); - const QMetaObject *storeMo = QmlMetaType::rawMetaObjectForType(binding.property->type); + QmlInstruction &instr = output->bytecode[binding.instructionIdx]; + instr.line = binding.value->location.start.line; - Q_ASSERT(idMo); - Q_ASSERT(storeMo); + // Single load optimization + if (bs.isValid() && bs.isSingleLoad()) { - bool canAssign = false; - while (!canAssign && idMo) { - if (idMo == storeMo) - canAssign = true; - else - idMo = idMo->superClass(); - } + QString singleLoadTarget = QLatin1String(bs.singleLoadTarget()); - if (!canAssign) - continue; + if (singleLoadTarget.at(0).isUpper() && + compileState.ids.contains(singleLoadTarget) && + QmlMetaType::isObject(binding.property->type)) { - int saveId = -1; + IdReference reference = compileState.ids[singleLoadTarget]; - int instructionIdx = reference.instructionIdx; - if (output->bytecode.at(instructionIdx).setId.save != -1) { - saveId = output->bytecode.at(instructionIdx).setId.save; - } else { - output->bytecode[instructionIdx].setId.save = saveCount; - saveId = saveCount; - ++saveCount; - } + const QMetaObject *idMo = reference.object->metaObject(); + const QMetaObject *storeMo = + QmlMetaType::rawMetaObjectForType(binding.property->type); - int prop = instr.assignBinding.property; + Q_ASSERT(idMo); + Q_ASSERT(storeMo); - instr.type = QmlInstruction::PushProperty; - instr.pushProperty.property = prop; + bool canAssign = false; + while (!canAssign && idMo) { + if (idMo == storeMo) + canAssign = true; + else + idMo = idMo->superClass(); + } - QmlInstruction instr; - instr.type = QmlInstruction::StoreStackObject; - instr.line = 0; - instr.assignStackObject.property = newInstrs; - instr.assignStackObject.object = saveId; - output->bytecode << instr; - ++newInstrs; + if (canAssign) { + int instructionIdx = reference.instructionIdx; + if (output->bytecode.at(instructionIdx).setId.save == -1) { + output->bytecode[instructionIdx].setId.save = + compileState.savedObjects++; } + int saveId = output->bytecode.at(instructionIdx).setId.save; + + instr.type = QmlInstruction::PushProperty; + instr.pushProperty.property = binding.property->index; + + QmlInstruction store; + store.type = QmlInstruction::StoreStackObject; + store.line = 0; + store.assignStackObject.property = + compileState.pushedProperties++; + store.assignStackObject.object = saveId; + output->bytecode << store; + return; } - } + } } - output->bytecode[patch].init.dataSize = saveCount; - output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); - output->bytecode[patch].init.parserStatusSize = - compileState.parserStatusCount; + // General binding fallback + int bref; + if (bs.isValid()) { + bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); + } else { + bref = output->indexForString(binding.expression.asScript()); + } + + instr.assignBinding.context = binding.bindingContext; + + if (bs.isValid()) + instr.type = QmlInstruction::StoreCompiledBinding; + else + instr.type = QmlInstruction::StoreBinding; - return newInstrs; + instr.assignBinding.property = binding.property->index; + instr.assignBinding.value = bref; + QMetaProperty mp = binding.property->parent->metaObject()->property(binding.property->index); + instr.assignBinding.category = QmlMetaProperty::propertyCategory(mp); } QmlCompiledData::QmlCompiledData() diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index b1963da..eb24b91 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -158,10 +158,12 @@ private: QmlParser::Value *value); bool compileDynamicMeta(QmlParser::Object *obj); - bool compileBinding(const QmlParser::Variant &, QmlParser::Property *prop, - int ctxt, const QMetaObject *, qint64); + bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, + int ctxt); - int finalizeComponent(int patch); + void finalizeComponent(int patch); + class BindingReference; + void finalizeBinding(const BindingReference &); struct IdReference { QString id; @@ -172,14 +174,18 @@ private: struct BindingReference { QmlParser::Variant expression; QmlParser::Property *property; + QmlParser::Value *value; int instructionIdx; + int bindingContext; }; struct ComponentCompileState { - ComponentCompileState() : parserStatusCount(0) {} + ComponentCompileState() : parserStatusCount(0), savedObjects(0), pushedProperties(0) {} QHash ids; int parserStatusCount; + int savedObjects; + int pushedProperties; QList bindings; }; ComponentCompileState compileState; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index f262b5d..fadfbb1 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -83,18 +83,23 @@ const QMetaObject *Object::metaObject() const QmlParser::Property *Object::getDefaultProperty() { - if (!defaultProperty) + if (!defaultProperty) { defaultProperty = new Property; + defaultProperty->parent = this; + } return defaultProperty; } Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) { if (!properties.contains(name)) { - if (create) - properties.insert(name, new Property(name)); - else + if (create) { + Property *property = new Property(name); + property->parent = this; + properties.insert(name, property); + } else { return 0; + } } return properties[name]; } @@ -153,12 +158,12 @@ void QmlParser::Object::dump(int indent) const } QmlParser::Property::Property() -: type(0), index(-1), value(0), isDefault(true) +: parent(0), type(0), index(-1), value(0), isDefault(true) { } QmlParser::Property::Property(const QByteArray &n) -: type(0), index(-1), value(0), name(n), isDefault(false) +: parent(0), type(0), index(-1), value(0), name(n), isDefault(false) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index cb9b540..020cae5 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -252,6 +252,9 @@ namespace QmlParser Property(const QByteArray &n); virtual ~Property(); + // The Object to which this property is attached + Object *parent; + Object *getValue(); void addValue(Value *v); diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index b1ffc98..75c81a7 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -532,6 +532,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) if (node->expression) { // default value property.defaultValue = new Property; + property.defaultValue->parent = _stateStack.top().object; Value *value = new Value; value->location = location(node->expression->firstSourceLocation(), node->expression->lastSourceLocation()); -- cgit v0.12