aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs
diff options
context:
space:
mode:
authorErik Verbruggen <[email protected]>2010-02-19 15:10:39 +0100
committerErik Verbruggen <[email protected]>2010-02-19 15:11:03 +0100
commit78b31454778977c2fbdf2b98a0cbf188e852c3f1 (patch)
tree2ccf123549f32aa0e205e7de6d84f044aefa2dcf /src/libs
parent5e449a80c448db05b49122f3a046e37056ee509d (diff)
Semantic checking for easing curve names.
Done-with: Christian Kamm
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/qmljs/qmljscheck.cpp71
-rw-r--r--src/libs/qmljs/qmljscheck.h8
-rw-r--r--src/libs/qmljs/qmljsinterpreter.cpp97
-rw-r--r--src/libs/qmljs/qmljsinterpreter.h24
4 files changed, 190 insertions, 10 deletions
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index c757752d7f6..7a794cb03ba 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -42,6 +42,9 @@ static const char *invalid_property_name = QT_TRANSLATE_NOOP("QmlJS::Check", "'
static const char *unknown_type = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown type");
static const char *has_no_members = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' does not have members");
static const char *is_not_a_member = QT_TRANSLATE_NOOP("QmlJS::Check", "'%1' is not a member of '%2'");
+static const char *easing_curve_not_a_string = QT_TRANSLATE_NOOP("QmlJS::Check", "easing-curve name is not a string");
+static const char *unknown_easing_curve_name = QT_TRANSLATE_NOOP("QmlJS::Check", "unknown easing-curve name");
+static const char *value_might_be_undefined = QT_TRANSLATE_NOOP("QmlJS::Check", "value might be 'undefined'");
} // namespace Messages
static inline QString tr(const char *msg)
@@ -176,11 +179,50 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
bool Check::visit(UiScriptBinding *ast)
{
- checkScopeObjectMember(ast->qualifiedId);
+ const Value *lhsValue = checkScopeObjectMember(ast->qualifiedId);
+ if (lhsValue) {
+ // ### Fix the evaluator to accept statements!
+ if (ExpressionStatement *expStmt = cast<ExpressionStatement *>(ast->statement)) {
+ Evaluate evaluator(&_context);
+ const Value *rhsValue = evaluator(expStmt->expression);
+
+ const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(), expStmt->lastSourceLocation());
+ checkPropertyAssignment(loc, lhsValue, rhsValue, expStmt->expression);
+ }
+
+ }
return true;
}
+void Check::checkPropertyAssignment(const SourceLocation &location,
+ const Interpreter::Value *lhsValue,
+ const Interpreter::Value *rhsValue,
+ ExpressionNode *ast)
+{
+ if (lhsValue->asEasingCurveNameValue()) {
+ const StringValue *rhsStringValue = rhsValue->asStringValue();
+ if (!rhsStringValue) {
+ if (rhsValue->asUndefinedValue())
+ warning(location, tr(Messages::value_might_be_undefined));
+ else
+ error(location, tr(Messages::easing_curve_not_a_string));
+ return;
+ }
+
+ if (StringLiteral *string = cast<StringLiteral *>(ast)) {
+ const QString value = string->value->asString();
+ // ### do something with easing-curve attributes.
+ // ### Incomplete documentation at: http://qt.nokia.com/doc/4.7-snapshot/qml-propertyanimation.html#easing-prop
+ // ### The implementation is at: src/declarative/util/qmlanimation.cpp
+ const QString curveName = value.left(value.indexOf(QLatin1Char('(')));
+ if (!EasingCurveNameValue::curveNames().contains(curveName)) {
+ error(location, tr(Messages::unknown_easing_curve_name));
+ }
+ }
+ }
+}
+
bool Check::visit(UiArrayBinding *ast)
{
checkScopeObjectMember(ast->qualifiedId);
@@ -188,20 +230,20 @@ bool Check::visit(UiArrayBinding *ast)
return true;
}
-void Check::checkScopeObjectMember(const UiQualifiedId *id)
+const Value *Check::checkScopeObjectMember(const UiQualifiedId *id)
{
if (_allowAnyProperty)
- return;
+ return 0;
const ObjectValue *scopeObject = _context.qmlScopeObject();
if (! id)
- return; // ### error?
+ return 0; // ### error?
QString propertyName = id->name->asString();
if (propertyName == QLatin1String("id") && ! id->next)
- return;
+ return 0; // ### should probably be a special value
// attached properties
bool isAttachedProperty = false;
@@ -211,7 +253,7 @@ void Check::checkScopeObjectMember(const UiQualifiedId *id)
}
if (! scopeObject)
- return;
+ return 0;
// global lookup for first part of id
const Value *value = scopeObject->lookupMember(propertyName, &_context);
@@ -224,7 +266,7 @@ void Check::checkScopeObjectMember(const UiQualifiedId *id)
// can't look up members for attached properties
if (isAttachedProperty)
- return;
+ return 0;
// member lookup
const UiQualifiedId *idPart = id;
@@ -233,7 +275,7 @@ void Check::checkScopeObjectMember(const UiQualifiedId *id)
if (! objectValue) {
error(idPart->identifierToken,
tr(Messages::has_no_members).arg(propertyName));
- return;
+ return 0;
}
idPart = idPart->next;
@@ -244,9 +286,11 @@ void Check::checkScopeObjectMember(const UiQualifiedId *id)
error(idPart->identifierToken,
tr(Messages::is_not_a_member).arg(propertyName,
objectValue->className()));
- return;
+ return 0;
}
}
+
+ return value;
}
void Check::error(const AST::SourceLocation &loc, const QString &message)
@@ -258,3 +302,12 @@ void Check::warning(const AST::SourceLocation &loc, const QString &message)
{
_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, loc, message));
}
+
+SourceLocation Check::locationFromRange(const SourceLocation &start,
+ const SourceLocation &end)
+{
+ return SourceLocation(start.offset,
+ end.end() - start.begin(),
+ start.startLine,
+ start.startColumn);
+}
diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h
index dea80974179..56ec5c0c83c 100644
--- a/src/libs/qmljs/qmljscheck.h
+++ b/src/libs/qmljs/qmljscheck.h
@@ -55,10 +55,16 @@ protected:
private:
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
AST::UiObjectInitializer *initializer);
- void checkScopeObjectMember(const AST::UiQualifiedId *id);
+ const Interpreter::Value *checkScopeObjectMember(const AST::UiQualifiedId *id);
+ void checkPropertyAssignment(const AST::SourceLocation &location,
+ const Interpreter::Value *lhsValue,
+ const Interpreter::Value *rhsValue,
+ QmlJS::AST::ExpressionNode *ast);
void warning(const AST::SourceLocation &loc, const QString &message);
void error(const AST::SourceLocation &loc, const QString &message);
+ static AST::SourceLocation locationFromRange(const AST::SourceLocation &start,
+ const AST::SourceLocation &end);
Document::Ptr _doc;
Snapshot _snapshot;
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 7caee728108..20b1f47dbe7 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -41,6 +41,7 @@
# include <QtDeclarative/private/qmlgraphicsanchors_p.h> // ### remove me
# include <QtDeclarative/private/qmlgraphicsrectangle_p.h> // ### remove me
# include <QtDeclarative/private/qmlvaluetype_p.h> // ### remove me
+# include <QtDeclarative/private/qmlanimation_p.h> // ### remove me
#endif
using namespace QmlJS::Interpreter;
@@ -329,8 +330,29 @@ const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
break;
} // end of switch
+ const QString typeName = prop.typeName();
+ if (typeName == QLatin1String("QmlGraphicsAnchorLine")) {
+ ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
+ object->setClassName(QLatin1String("AnchorLine"));
+ value = object;
+ }
+ if (value->asStringValue() && prop.name() == QLatin1String("easing")
+ && isDerivedFrom(&QmlPropertyAnimation::staticMetaObject)) {
+ value = engine()->easingCurveNameValue();
+ }
+
return value;
}
+
+bool QmlObjectValue::isDerivedFrom(const QMetaObject *base) const
+{
+ for (const QMetaObject *iter = _metaObject; iter; iter = iter->superClass()) {
+ if (iter == base)
+ return true;
+ }
+ return false;
+}
+
#endif
namespace {
@@ -584,6 +606,10 @@ void ValueVisitor::visit(const Reference *)
{
}
+void ValueVisitor::visit(const EasingCurveNameValue *)
+{
+}
+
////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
@@ -640,6 +666,11 @@ const Reference *Value::asReference() const
return 0;
}
+const EasingCurveNameValue *Value::asEasingCurveNameValue() const
+{
+ return 0;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Values
////////////////////////////////////////////////////////////////////////////////
@@ -860,6 +891,67 @@ const Value *Reference::value(Context *) const
return _engine->undefinedValue();
}
+void EasingCurveNameValue::accept(ValueVisitor *visitor) const
+{
+ visitor->visit(this);
+}
+
+QSet<QString> EasingCurveNameValue::_curveNames;
+QSet<QString> EasingCurveNameValue::curveNames()
+{
+ if (_curveNames.isEmpty()) {
+ _curveNames = QSet<QString>()
+ << "easeLinear"
+ << "easeInQuad"
+ << "easeOutQuad"
+ << "easeInOutQuad"
+ << "easeOutInQuad"
+ << "easeInCubic"
+ << "easeOutCubic"
+ << "easeInOutCubic"
+ << "easeOutInCubic"
+ << "easeInQuart"
+ << "easeOutQuart"
+ << "easeInOutQuart"
+ << "easeOutInQuart"
+ << "easeInQuint"
+ << "easeOutQuint"
+ << "easeInOutQuint"
+ << "easeOutInQuint"
+ << "easeInSine"
+ << "easeOutSine"
+ << "easeInOutSine"
+ << "easeOutInSine"
+ << "easeInExpo"
+ << "easeOutExpo"
+ << "easeInOutExpo"
+ << "easeOutInExpo"
+ << "easeInCirc"
+ << "easeOutCirc"
+ << "easeInOutCirc"
+ << "easeOutInCirc"
+ << "easeInElastic"
+ << "easeOutElastic"
+ << "easeInOutElastic"
+ << "easeOutInElastic"
+ << "easeInBack"
+ << "easeOutBack"
+ << "easeInOutBack"
+ << "easeOutInBack"
+ << "easeInBounce"
+ << "easeOutBounce"
+ << "easeInOutBounce"
+ << "easeOutInBounce";
+ }
+
+ return _curveNames;
+}
+
+const EasingCurveNameValue *EasingCurveNameValue::asEasingCurveNameValue() const
+{
+ return this;
+}
+
MemberProcessor::MemberProcessor()
{
}
@@ -1499,6 +1591,11 @@ const StringValue *Engine::stringValue() const
return &_stringValue;
}
+const EasingCurveNameValue *Engine::easingCurveNameValue() const
+{
+ return &_easingCurveNameValue;
+}
+
const Value *Engine::newArray()
{
return arrayCtor()->construct();
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 8f0fa51532f..a1fac700ec8 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -60,6 +60,7 @@ class StringValue;
class ObjectValue;
class FunctionValue;
class Reference;
+class EasingCurveNameValue;
typedef QList<const Value *> ValueList;
@@ -80,6 +81,7 @@ public:
virtual void visit(const ObjectValue *);
virtual void visit(const FunctionValue *);
virtual void visit(const Reference *);
+ virtual void visit(const EasingCurveNameValue *);
};
////////////////////////////////////////////////////////////////////////////////
@@ -102,6 +104,7 @@ public:
virtual const ObjectValue *asObjectValue() const;
virtual const FunctionValue *asFunctionValue() const;
virtual const Reference *asReference() const;
+ virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
virtual void accept(ValueVisitor *) const = 0;
@@ -158,6 +161,12 @@ template <> Q_INLINE_TEMPLATE const Reference *value_cast(const Value *v)
else return 0;
}
+template <> Q_INLINE_TEMPLATE const EasingCurveNameValue *value_cast(const Value *v)
+{
+ if (v) return v->asEasingCurveNameValue();
+ else return 0;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Value nodes
////////////////////////////////////////////////////////////////////////////////
@@ -280,6 +289,18 @@ private:
Engine *_engine;
};
+class QMLJS_EXPORT EasingCurveNameValue: public Value
+{
+ static QSet<QString> _curveNames;
+
+public:
+ static QSet<QString> curveNames();
+
+ // Value interface
+ virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
+ virtual void accept(ValueVisitor *) const;
+};
+
class QMLJS_EXPORT ObjectValue: public Value
{
public:
@@ -339,6 +360,7 @@ public:
protected:
const Value *findOrCreateSignature(int index, const QMetaMethod &method, QString *methodName) const;
+ bool isDerivedFrom(const QMetaObject *base) const;
private:
const QMetaObject *_metaObject;
@@ -537,6 +559,7 @@ public:
const NumberValue *numberValue() const;
const BooleanValue *booleanValue() const;
const StringValue *stringValue() const;
+ const EasingCurveNameValue *easingCurveNameValue() const;
ObjectValue *newObject(const ObjectValue *prototype);
ObjectValue *newObject();
@@ -625,6 +648,7 @@ private:
NumberValue _numberValue;
BooleanValue _booleanValue;
StringValue _stringValue;
+ EasingCurveNameValue _easingCurveNameValue;
QList<Value *> _registeredValues;
ConvertToNumber _convertToNumber;