}
QML_V4_END_INSTR(ConvertStringToReal, unaryop)
+ QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QString tmp(*src.getstringptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupString();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.geturlptr()) QUrl(tmp);
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ output.setbool(!tmp.isEmpty());
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
+
+ QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ // ### NaN
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ output.cleanupUrl();
+ MARK_CLEAN_REGISTER(instr->unaryop.output);
+ }
+ new (output.getstringptr()) QString(tmp.toString());
+ STRING_REGISTER(instr->unaryop.output);
+ }
+ }
+ QML_V4_END_INSTR(ConvertUrlToString, unaryop)
+
+ QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
+ {
+ const Register &src = registers[instr->unaryop.src];
+ Register &output = registers[instr->unaryop.output];
+ if (src.isUndefined()) {
+ output.setUndefined();
+ } else {
+ const QUrl tmp(*src.geturlptr());
+ if (instr->unaryop.src == instr->unaryop.output) {
+ *output.geturlptr() = context->resolvedUrl(tmp);
+ } else {
+ new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
+ URL_REGISTER(instr->unaryop.output);
+ }
+ }
+ }
+ QML_V4_END_INSTR(ResolveUrl, unaryop)
+
QML_V4_BEGIN_INSTR(MathSinReal, unaryop)
{
const Register &src = registers[instr->unaryop.src];
case QMetaType::QString:
regType = QStringType;
break;
+ case QMetaType::QUrl:
+ regType = QUrlType;
+ break;
default:
if (propTy == qMetaTypeId<QDeclarative1AnchorLine>()) {
traceExpression(s->source, dest);
V4Instr::Type opcode = V4Instr::Noop;
- if (target->type == IR::BoolType) {
- switch (s->source->type) {
+ IR::Type targetTy = s->target->type;
+ IR::Type sourceTy = s->source->type;
+
+ if (sourceTy == IR::UrlType) {
+ switch (targetTy) {
+ case IR::BoolType:
+ case IR::StringType:
+ // nothing to do. V4 will generate optimized
+ // url-to-xxx conversions.
+ break;
+ default: {
+ // generate a UrlToString conversion and fix
+ // the type of the source expression.
+ V4Instr conv;
+ conv.unaryop.output = V4Instr::ConvertUrlToString;
+ conv.unaryop.src = src;
+ gen(opcode, conv);
+
+ sourceTy = IR::StringType;
+ break;
+ }
+ } // switch
+ }
+
+ if (targetTy == IR::BoolType) {
+ switch (sourceTy) {
case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
case IR::RealType: opcode = V4Instr::ConvertRealToBool; break;
case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
default: break;
} // switch
- } else if (target->type == IR::IntType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::IntType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
case IR::RealType: {
if (s->isMoveForReturn)
case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
default: break;
} // switch
- } else if (target->type == IR::RealType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::RealType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToReal; break;
case IR::IntType: opcode = V4Instr::ConvertIntToReal; break;
case IR::StringType: opcode = V4Instr::ConvertStringToReal; break;
default: break;
} // switch
- } else if (target->type == IR::StringType) {
- switch (s->source->type) {
+ } else if (targetTy == IR::StringType) {
+ switch (sourceTy) {
case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
case IR::RealType: opcode = V4Instr::ConvertRealToString; break;
+ case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
+ default: break;
+ } // switch
+ } else if (targetTy == IR::UrlType) {
+ V4Instr convToString;
+ convToString.unaryop.output = dest;
+ convToString.unaryop.src = src;
+
+ // try to convert the source expression to a string.
+ switch (sourceTy) {
+ case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
+ case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
+ case IR::RealType: gen(V4Instr::ConvertRealToString, convToString); sourceTy = IR::StringType; break;
default: break;
} // switch
+
+ if (sourceTy == IR::StringType)
+ opcode = V4Instr::ConvertStringToUrl;
}
if (opcode != V4Instr::Noop) {
V4Instr conv;
conv.unaryop.output = dest;
conv.unaryop.src = src;
gen(opcode, conv);
+
+ if (s->isMoveForReturn && opcode == V4Instr::ConvertStringToUrl) {
+ V4Instr resolveUrl;
+ resolveUrl.unaryop.output = dest;
+ resolveUrl.unaryop.src = dest;
+ gen(V4Instr::ResolveUrl, resolveUrl);
+ }
} else {
discard();
}
case V4Instr::ConvertStringToReal:
INSTR_DUMP << "\t" << "ConvertStringToReal" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
+ case V4Instr::ConvertStringToUrl:
+ INSTR_DUMP << "\t" << "ConvertStringToUrl" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToBool:
+ INSTR_DUMP << "\t" << "ConvertUrlToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ConvertUrlToString:
+ INSTR_DUMP << "\t" << "ConvertUrlToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
+ case V4Instr::ResolveUrl:
+ INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
+ break;
case V4Instr::MathSinReal:
INSTR_DUMP << "\t" << "MathSinReal" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")";
break;
F(ConvertStringToBool, unaryop) \
F(ConvertStringToInt, unaryop) \
F(ConvertStringToReal, unaryop) \
+ F(ConvertStringToUrl, unaryop) \
+ F(ConvertUrlToBool, unaryop) \
+ F(ConvertUrlToString, unaryop) \
+ F(ResolveUrl, unaryop) \
F(MathSinReal, unaryop) \
F(MathCosReal, unaryop) \
F(MathRoundReal, unaryop) \
}
}
+inline bool isNumberType(IR::Type ty)
+{
+ return ty >= IR::FirstNumberType;
+}
+
+inline bool isStringType(IR::Type ty)
+{
+ return ty == IR::StringType || ty == IR::UrlType;
+}
+
IR::Type maxType(IR::Type left, IR::Type right)
{
- if (left == right)
+ if (isStringType(left) && isStringType(right)) {
+ // String promotions (url to string) are more specific than
+ // identity conversions (AKA left == right). That's because
+ // we want to ensure we convert urls to strings in binary
+ // expressions.
+ return IR::StringType;
+ } else if (left == right)
return left;
- else if (left >= IR::FirstNumberType && right >= IR::FirstNumberType)
+ else if (isNumberType(left) && isNumberType(right))
return qMax(left, right);
- else if ((left >= IR::FirstNumberType && right == IR::StringType) ||
- (right >= IR::FirstNumberType && left == IR::StringType))
+ else if ((isNumberType(left) && isStringType(right)) ||
+ (isNumberType(right) && isStringType(left)))
return IR::StringType;
else
return IR::InvalidType;
--- /dev/null
+import QtQuick 2.0
+import Qt.test 1.0
+
+MyQmlObject {
+ property bool result
+ urlProperty: stringProperty + "/index.html"
+ intProperty: if (urlProperty) 123; else 321
+ value: urlProperty == stringProperty + "/index.html"
+ result: urlProperty == urlProperty
+}
Q_PROPERTY(int value READ value WRITE setValue)
Q_PROPERTY(int console READ console CONSTANT)
Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
+ Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlChanged)
Q_PROPERTY(QObject *objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectChanged)
Q_PROPERTY(QDeclarativeListProperty<QObject> objectListProperty READ objectListProperty CONSTANT)
Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty)
emit stringChanged();
}
+ QUrl urlProperty() const { return m_url; }
+ void setUrlProperty(const QUrl &url)
+ {
+ if (url == m_url)
+ return;
+ m_url = url;
+ emit urlChanged();
+ }
+
QObject *objectProperty() const { return m_object; }
void setObjectProperty(QObject *obj) {
if (obj == m_object)
void basicSignal();
void argumentSignal(int a, QString b, qreal c, MyEnum2 d, Qt::MouseButtons e);
void stringChanged();
+ void urlChanged();
void objectChanged();
void anotherBasicSignal();
void thirdBasicSignal();
QObject *m_object;
QString m_string;
+ QUrl m_url;
QList<QObject *> m_objectQList;
int m_value;
int m_resetProperty;
void aliasWritesOverrideBindings();
void aliasToCompositeElement();
void realToInt();
+ void urlProperty();
void dynamicString();
void include();
void signalHandlers();
QMetaObject::invokeMethod(object, "test2");
QCOMPARE(object->value(), int(8));
}
+
+void tst_qdeclarativeecmascript::urlProperty()
+{
+ {
+ QDeclarativeComponent component(&engine, TEST_FILE("urlProperty.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
+ QCOMPARE(object->intProperty(), 123);
+ QCOMPARE(object->value(), 1);
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
void tst_qdeclarativeecmascript::dynamicString()
{
QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));