Commit f0674aa7 authored by Christian Kamm's avatar Christian Kamm
Browse files

Add check for anchor line, changed value assignment checks into visitor.

Done-with: Erik Verbruggen
parent 04d90d95
......@@ -62,6 +62,108 @@ using namespace QmlJS;
using namespace QmlJS::AST;
using namespace QmlJS::Interpreter;
namespace {
class AssignmentCheck : public ValueVisitor
{
public:
DiagnosticMessage operator()(
const SourceLocation &location,
const Interpreter::Value *lhsValue,
const Interpreter::Value *rhsValue,
ExpressionNode *ast)
{
_message = DiagnosticMessage(DiagnosticMessage::Error, location, QString());
_rhsValue = rhsValue;
_ast = ast;
if (lhsValue)
lhsValue->accept(this);
return _message;
}
virtual void visit(const NumberValue *)
{
// ### Consider enums: elide: "ElideLeft" is valid, but currently elide is a NumberValue.
if (/*cast<StringLiteral *>(_ast)
||*/ _ast->kind == Node::Kind_TrueLiteral
|| _ast->kind == Node::Kind_FalseLiteral) {
_message.message = QCoreApplication::translate("QmlJS::Check", "numerical value expected");
}
}
virtual void visit(const BooleanValue *)
{
UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(_ast);
if (cast<StringLiteral *>(_ast)
|| cast<NumericLiteral *>(_ast)
|| (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression))) {
_message.message = QCoreApplication::translate("QmlJS::Check", "boolean value expected");
}
}
virtual void visit(const StringValue *)
{
UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(_ast);
if (cast<NumericLiteral *>(_ast)
|| (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression))
|| _ast->kind == Node::Kind_TrueLiteral
|| _ast->kind == Node::Kind_FalseLiteral) {
_message.message = QCoreApplication::translate("QmlJS::Check", "string value expected");
}
}
virtual void visit(const EasingCurveNameValue *)
{
if (StringLiteral *stringLiteral = cast<StringLiteral *>(_ast)) {
const QString curveName = stringLiteral->value->asString();
// ### update when easing changes hit master
if (!EasingCurveNameValue::curveNames().contains(curveName)) {
_message.message = tr(Messages::unknown_easing_curve_name);
}
} else if (_rhsValue->asUndefinedValue()) {
_message.kind = DiagnosticMessage::Warning;
_message.message = tr(Messages::value_might_be_undefined);
} else if (! _rhsValue->asStringValue()) {
_message.message = tr(Messages::easing_curve_not_a_string);
}
}
virtual void visit(const ColorValue *)
{
if (StringLiteral *stringLiteral = cast<StringLiteral *>(_ast)) {
const QString colorString = stringLiteral->value->asString();
#ifndef NO_DECLARATIVE_BACKEND
bool ok = false;
QmlStringConverters::colorFromString(colorString, &ok);
if (!ok)
_message.message = QCoreApplication::translate("QmlJS::Check", "not a valid color");
#endif
} else {
visit((StringValue *)0);
}
}
virtual void visit(const AnchorLineValue *)
{
if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUndefinedValue()))
_message.message = QCoreApplication::translate("QmlJS::Check", "expected anchor line");
}
DiagnosticMessage _message;
const Value *_rhsValue;
ExpressionNode *_ast;
};
} // end of anonymous namespace
Check::Check(Document::Ptr doc, const Snapshot &snapshot)
: _doc(doc)
, _snapshot(snapshot)
......@@ -131,17 +233,6 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
_scopeBuilder.pop();
}
void Check::errorOnWrongRhs(const SourceLocation &loc, const Value *lhsValue)
{
if (lhsValue->asBooleanValue()) {
error(loc, QCoreApplication::translate("QmlJS::Check", "boolean value expected"));
} else if (lhsValue->asNumberValue()) {
error(loc, QCoreApplication::translate("QmlJS::Check", "numerical value expected"));
} else if (lhsValue->asStringValue()) {
error(loc, QCoreApplication::translate("QmlJS::Check", "string value expected"));
}
}
bool Check::visit(UiScriptBinding *ast)
{
// special case for id property
......@@ -181,7 +272,10 @@ bool Check::visit(UiScriptBinding *ast)
const SourceLocation loc = locationFromRange(expStmt->firstSourceLocation(),
expStmt->lastSourceLocation());
checkPropertyAssignment(loc, lhsValue, rhsValue, expr);
AssignmentCheck assignmentCheck;
DiagnosticMessage message = assignmentCheck(loc, lhsValue, rhsValue, expr);
if (! message.message.isEmpty())
_messages += message;
}
}
......@@ -189,62 +283,6 @@ bool Check::visit(UiScriptBinding *ast)
return true;
}
void Check::checkPropertyAssignment(const SourceLocation &location,
const Interpreter::Value *lhsValue,
const Interpreter::Value *rhsValue,
ExpressionNode *ast)
{
UnaryMinusExpression *unaryMinus = cast<UnaryMinusExpression *>(ast);
// Qml is particularly strict with literals
if (StringLiteral *stringLiteral = cast<StringLiteral *>(ast)) {
const QString string = stringLiteral->value->asString();
if (lhsValue->asStringValue()) {
// okay
} else if (lhsValue->asColorValue()) {
#ifndef NO_DECLARATIVE_BACKEND
bool ok = false;
QmlStringConverters::colorFromString(string, &ok);
if (!ok)
error(location, QCoreApplication::translate("QmlJS::Check", "not a valid color"));
#endif
} else if (lhsValue->asEasingCurveNameValue()) {
// ### 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 = string.left(string.indexOf(QLatin1Char('(')));
if (!EasingCurveNameValue::curveNames().contains(curveName)) {
error(location, tr(Messages::unknown_easing_curve_name));
}
} else {
errorOnWrongRhs(location, lhsValue);
}
} else if ((ast->kind == Node::Kind_TrueLiteral
|| ast->kind == Node::Kind_FalseLiteral)
&& ! lhsValue->asBooleanValue()) {
errorOnWrongRhs(location, lhsValue);
} else if (cast<NumericLiteral *>(ast)
&& ! lhsValue->asNumberValue()) {
errorOnWrongRhs(location, lhsValue);
} else if (unaryMinus && cast<NumericLiteral *>(unaryMinus->expression)
&& ! lhsValue->asNumberValue()) {
errorOnWrongRhs(location, lhsValue);
} else {
// rhs is not a literal
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;
}
}
}
}
bool Check::visit(UiArrayBinding *ast)
{
checkScopeObjectMember(ast->qualifiedId);
......
......@@ -57,11 +57,6 @@ private:
void visitQmlObject(AST::Node *ast, AST::UiQualifiedId *typeId,
AST::UiObjectInitializer *initializer);
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 errorOnWrongRhs(const AST::SourceLocation &loc, const Interpreter::Value *lhsValue);
void warning(const AST::SourceLocation &loc, const QString &message);
void error(const AST::SourceLocation &loc, const QString &message);
......
......@@ -336,9 +336,7 @@ const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
const QString typeName = prop.typeName();
if (typeName == QLatin1String("QmlGraphicsAnchorLine")) {
ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
object->setClassName(QLatin1String("AnchorLine"));
value = object;
value = engine()->anchorLineValue();
}
if (value->asStringValue() && prop.name() == QLatin1String("easing")
&& isDerivedFrom(&QmlPropertyAnimation::staticMetaObject)) {
......@@ -618,6 +616,10 @@ void ValueVisitor::visit(const ColorValue *)
{
}
void ValueVisitor::visit(const AnchorLineValue *)
{
}
////////////////////////////////////////////////////////////////////////////////
// Value
////////////////////////////////////////////////////////////////////////////////
......@@ -684,6 +686,11 @@ const ColorValue *Value::asColorValue() const
return 0;
}
const AnchorLineValue *Value::asAnchorLineValue() const
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Values
////////////////////////////////////////////////////////////////////////////////
......@@ -1000,6 +1007,16 @@ const ColorValue *ColorValue::asColorValue() const
return this;
}
void AnchorLineValue::accept(ValueVisitor *visitor) const
{
visitor->visit(this);
}
const AnchorLineValue *AnchorLineValue::asAnchorLineValue() const
{
return this;
}
MemberProcessor::MemberProcessor()
{
}
......@@ -1577,6 +1594,21 @@ void TypeId::visit(const FunctionValue *object)
_result = QLatin1String("Function");
}
void TypeId::visit(const EasingCurveNameValue *)
{
_result = QLatin1String("string");
}
void TypeId::visit(const ColorValue *)
{
_result = QLatin1String("string");
}
void TypeId::visit(const AnchorLineValue *)
{
_result = QLatin1String("AnchorLine");
}
Engine::Engine()
: _objectPrototype(0),
_functionPrototype(0),
......@@ -1649,6 +1681,11 @@ const ColorValue *Engine::colorValue() const
return &_colorValue;
}
const AnchorLineValue *Engine::anchorLineValue() const
{
return &_anchorLineValue;
}
const Value *Engine::newArray()
{
return arrayCtor()->construct();
......
......@@ -62,6 +62,7 @@ class FunctionValue;
class Reference;
class EasingCurveNameValue;
class ColorValue;
class AnchorLineValue;
typedef QList<const Value *> ValueList;
......@@ -84,6 +85,7 @@ public:
virtual void visit(const Reference *);
virtual void visit(const EasingCurveNameValue *);
virtual void visit(const ColorValue *);
virtual void visit(const AnchorLineValue *);
};
////////////////////////////////////////////////////////////////////////////////
......@@ -108,6 +110,7 @@ public:
virtual const Reference *asReference() const;
virtual const EasingCurveNameValue *asEasingCurveNameValue() const;
virtual const ColorValue *asColorValue() const;
virtual const AnchorLineValue *asAnchorLineValue() const;
virtual void accept(ValueVisitor *) const = 0;
......@@ -176,6 +179,12 @@ template <> Q_INLINE_TEMPLATE const ColorValue *value_cast(const Value *v)
else return 0;
}
template <> Q_INLINE_TEMPLATE const AnchorLineValue *value_cast(const Value *v)
{
if (v) return v->asAnchorLineValue();
else return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Value nodes
////////////////////////////////////////////////////////////////////////////////
......@@ -343,6 +352,14 @@ public:
virtual void accept(ValueVisitor *) const;
};
class QMLJS_EXPORT AnchorLineValue: public Value
{
public:
// Value interface
virtual const AnchorLineValue *asAnchorLineValue() const;
virtual void accept(ValueVisitor *) const;
};
class QMLJS_EXPORT ObjectValue: public Value
{
public:
......@@ -585,6 +602,9 @@ protected:
virtual void visit(const StringValue *);
virtual void visit(const ObjectValue *object);
virtual void visit(const FunctionValue *object);
virtual void visit(const EasingCurveNameValue *);
virtual void visit(const ColorValue *);
virtual void visit(const AnchorLineValue *);
};
class QMLJS_EXPORT Engine
......@@ -603,6 +623,7 @@ public:
const StringValue *stringValue() const;
const EasingCurveNameValue *easingCurveNameValue() const;
const ColorValue *colorValue() const;
const AnchorLineValue *anchorLineValue() const;
ObjectValue *newObject(const ObjectValue *prototype);
ObjectValue *newObject();
......@@ -693,6 +714,7 @@ private:
StringValue _stringValue;
EasingCurveNameValue _easingCurveNameValue;
ColorValue _colorValue;
AnchorLineValue _anchorLineValue;
QList<Value *> _registeredValues;
ConvertToNumber _convertToNumber;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment