forked from qt-creator/qt-creator
QmlJS: Introduce UnknownValue.
To distinguish known-to-be-undefined from a genuinely unknown value. Change-Id: I606b4ea4d726f94553400b8950d3c0a4e76564a8 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
@@ -325,7 +325,7 @@ bool Bind::visit(FunctionExpression *ast)
|
||||
// 1. Function formal arguments
|
||||
for (FormalParameterList *it = ast->formals; it; it = it->next) {
|
||||
if (!it->name.isEmpty())
|
||||
functionScope->setMember(it->name.toString(), _valueOwner.undefinedValue());
|
||||
functionScope->setMember(it->name.toString(), _valueOwner.unknownValue());
|
||||
}
|
||||
|
||||
// 2. Functions defined inside the function body
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
setMessage(ErrInvalidEnumValue);
|
||||
}
|
||||
} else if (! _rhsValue->asStringValue() && ! _rhsValue->asNumberValue()
|
||||
&& ! _rhsValue->asUndefinedValue()) {
|
||||
&& ! _rhsValue->asUnknownValue()) {
|
||||
setMessage(ErrEnumValueMustBeStringOrNumber);
|
||||
}
|
||||
} else {
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
|
||||
virtual void visit(const AnchorLineValue *)
|
||||
{
|
||||
if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUndefinedValue()))
|
||||
if (! (_rhsValue->asAnchorLineValue() || _rhsValue->asUnknownValue()))
|
||||
setMessage(ErrAnchorLineExpected);
|
||||
}
|
||||
|
||||
@@ -842,9 +842,8 @@ bool Check::visit(FunctionExpression *ast)
|
||||
|
||||
static bool shouldAvoidNonStrictEqualityCheck(const Value *lhs, const Value *rhs)
|
||||
{
|
||||
// we currently use undefined as a "we don't know" value
|
||||
if (lhs->asUndefinedValue() || rhs->asUndefinedValue())
|
||||
return true;
|
||||
if (lhs->asUnknownValue() || rhs->asUnknownValue())
|
||||
return true; // may coerce or not
|
||||
|
||||
if (lhs->asStringValue() && rhs->asNumberValue())
|
||||
return true; // coerces string to number
|
||||
@@ -855,7 +854,8 @@ static bool shouldAvoidNonStrictEqualityCheck(const Value *lhs, const Value *rhs
|
||||
if (lhs->asObjectValue() && rhs->asStringValue())
|
||||
return true; // coerces object to primitive
|
||||
|
||||
if (lhs->asBooleanValue() && !rhs->asBooleanValue())
|
||||
if (lhs->asBooleanValue() && (!rhs->asBooleanValue()
|
||||
&& !rhs->asUndefinedValue()))
|
||||
return true; // coerces bool to number
|
||||
|
||||
return false;
|
||||
@@ -1156,7 +1156,7 @@ bool Check::visit(NewMemberExpression *ast)
|
||||
if (ast->arguments && ast->arguments->expression && !ast->arguments->next) {
|
||||
Evaluate evaluate(&_scopeChain);
|
||||
const Value *arg = evaluate(ast->arguments->expression);
|
||||
if (arg->asNumberValue() || arg->asUndefinedValue())
|
||||
if (arg->asNumberValue() || arg->asUnknownValue())
|
||||
ok = true;
|
||||
}
|
||||
if (!ok)
|
||||
|
||||
@@ -69,8 +69,9 @@ const Value *Evaluate::value(AST::Node *ast)
|
||||
result = _context->lookupReference(ref);
|
||||
}
|
||||
|
||||
// if evaluation fails, return an unknown value
|
||||
if (! result)
|
||||
result = _valueOwner->undefinedValue();
|
||||
result = _valueOwner->unknownValue();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -123,21 +123,11 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual const Value *returnValue() const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
}
|
||||
|
||||
virtual int argumentCount() const
|
||||
{
|
||||
return _method.parameterNames().size();
|
||||
}
|
||||
|
||||
virtual const Value *argument(int) const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
}
|
||||
|
||||
virtual QString argumentName(int index) const
|
||||
{
|
||||
if (index < _method.parameterNames().size())
|
||||
@@ -153,7 +143,7 @@ public:
|
||||
|
||||
virtual const Value *invoke(const Activation *) const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->unknownValue();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -264,7 +254,7 @@ void CppComponentValue::processMembers(MemberProcessor *processor) const
|
||||
if (!explicitSignals.contains(signalName)) {
|
||||
// process the generated slot
|
||||
const QString &slotName = generatedSlotName(signalName);
|
||||
processor->processGeneratedSlot(slotName, valueOwner()->undefinedValue());
|
||||
processor->processGeneratedSlot(slotName, valueOwner()->unknownValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +327,8 @@ const Value *CppComponentValue::valueForCppName(const QString &typeName) const
|
||||
return value;
|
||||
}
|
||||
|
||||
return valueOwner()->undefinedValue();
|
||||
// may still be a cpp based value
|
||||
return valueOwner()->unknownValue();
|
||||
}
|
||||
|
||||
const CppComponentValue *CppComponentValue::prototype() const
|
||||
@@ -566,6 +557,10 @@ void ValueVisitor::visit(const UndefinedValue *)
|
||||
{
|
||||
}
|
||||
|
||||
void ValueVisitor::visit(const UnknownValue *)
|
||||
{
|
||||
}
|
||||
|
||||
void ValueVisitor::visit(const NumberValue *)
|
||||
{
|
||||
}
|
||||
@@ -624,6 +619,11 @@ const UndefinedValue *Value::asUndefinedValue() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
const UnknownValue *Value::asUnknownValue() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NumberValue *Value::asNumberValue() const
|
||||
{
|
||||
return 0;
|
||||
@@ -727,11 +727,20 @@ const UndefinedValue *UndefinedValue::asUndefinedValue() const
|
||||
return this;
|
||||
}
|
||||
|
||||
void UndefinedValue::accept(ValueVisitor *visitor) const
|
||||
void UnknownValue::accept(ValueVisitor *visitor) const
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
|
||||
const UnknownValue *UnknownValue::asUnknownValue() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void UndefinedValue::accept(ValueVisitor *visitor) const
|
||||
{
|
||||
visitor->visit(this);
|
||||
}
|
||||
const NumberValue *NumberValue::asNumberValue() const
|
||||
{
|
||||
return this;
|
||||
@@ -1168,7 +1177,7 @@ const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList
|
||||
|
||||
const Value *FunctionValue::returnValue() const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->unknownValue();
|
||||
}
|
||||
|
||||
int FunctionValue::argumentCount() const
|
||||
@@ -1178,7 +1187,7 @@ int FunctionValue::argumentCount() const
|
||||
|
||||
const Value *FunctionValue::argument(int) const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->unknownValue();
|
||||
}
|
||||
|
||||
QString FunctionValue::argumentName(int index) const
|
||||
@@ -1812,8 +1821,9 @@ ASTVariableReference::~ASTVariableReference()
|
||||
|
||||
const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const
|
||||
{
|
||||
// may be assigned to later
|
||||
if (!_ast->expression)
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->unknownValue();
|
||||
|
||||
Document::Ptr doc = _doc->ptr();
|
||||
ScopeChain scopeChain(doc, referenceContext->context());
|
||||
@@ -1850,21 +1860,11 @@ FunctionExpression *ASTFunctionValue::ast() const
|
||||
return _ast;
|
||||
}
|
||||
|
||||
const Value *ASTFunctionValue::returnValue() const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
}
|
||||
|
||||
int ASTFunctionValue::argumentCount() const
|
||||
{
|
||||
return _argumentNames.size();
|
||||
}
|
||||
|
||||
const Value *ASTFunctionValue::argument(int) const
|
||||
{
|
||||
return valueOwner()->undefinedValue();
|
||||
}
|
||||
|
||||
QString ASTFunctionValue::argumentName(int index) const
|
||||
{
|
||||
if (index < _argumentNames.size()) {
|
||||
@@ -1876,11 +1876,6 @@ QString ASTFunctionValue::argumentName(int index) const
|
||||
return FunctionValue::argumentName(index);
|
||||
}
|
||||
|
||||
bool ASTFunctionValue::isVariadic() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTFunctionValue::getSourceLocation(QString *fileName, int *line, int *column) const
|
||||
{
|
||||
*fileName = _doc->fileName();
|
||||
@@ -1963,10 +1958,7 @@ const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) con
|
||||
return evaluator(_ast->statement);
|
||||
}
|
||||
|
||||
if (!_ast->memberType.isEmpty())
|
||||
return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString());
|
||||
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->defaultValueForBuiltinType(_ast->memberType.toString());
|
||||
}
|
||||
|
||||
ASTSignal::ASTSignal(UiPublicMember *ast, const Document *doc, ValueOwner *valueOwner)
|
||||
@@ -2006,7 +1998,7 @@ const Value *ASTSignal::argument(int index) const
|
||||
for (int i = 0; param && i < index; ++i)
|
||||
param = param->next;
|
||||
if (!param || param->type.isEmpty())
|
||||
return valueOwner()->undefinedValue();
|
||||
return valueOwner()->unknownValue();
|
||||
return valueOwner()->defaultValueForBuiltinType(param->type.toString());
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ class ValueOwner;
|
||||
class Value;
|
||||
class NullValue;
|
||||
class UndefinedValue;
|
||||
class UnknownValue;
|
||||
class NumberValue;
|
||||
class IntValue;
|
||||
class RealValue;
|
||||
@@ -95,6 +96,7 @@ public:
|
||||
|
||||
virtual void visit(const NullValue *);
|
||||
virtual void visit(const UndefinedValue *);
|
||||
virtual void visit(const UnknownValue *);
|
||||
virtual void visit(const NumberValue *);
|
||||
virtual void visit(const BooleanValue *);
|
||||
virtual void visit(const StringValue *);
|
||||
@@ -119,6 +121,7 @@ public:
|
||||
|
||||
virtual const NullValue *asNullValue() const;
|
||||
virtual const UndefinedValue *asUndefinedValue() const;
|
||||
virtual const UnknownValue *asUnknownValue() const;
|
||||
virtual const NumberValue *asNumberValue() const;
|
||||
virtual const IntValue *asIntValue() const;
|
||||
virtual const RealValue *asRealValue() const;
|
||||
@@ -161,6 +164,12 @@ template <> Q_INLINE_TEMPLATE const UndefinedValue *value_cast(const Value *v)
|
||||
else return 0;
|
||||
}
|
||||
|
||||
template <> Q_INLINE_TEMPLATE const UnknownValue *value_cast(const Value *v)
|
||||
{
|
||||
if (v) return v->asUnknownValue();
|
||||
else return 0;
|
||||
}
|
||||
|
||||
template <> Q_INLINE_TEMPLATE const NumberValue *value_cast(const Value *v)
|
||||
{
|
||||
if (v) return v->asNumberValue();
|
||||
@@ -280,6 +289,13 @@ public:
|
||||
virtual void accept(ValueVisitor *visitor) const;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT UnknownValue: public Value
|
||||
{
|
||||
public:
|
||||
virtual const UnknownValue *asUnknownValue() const;
|
||||
virtual void accept(ValueVisitor *) const;
|
||||
};
|
||||
|
||||
class QMLJS_EXPORT NumberValue: public Value
|
||||
{
|
||||
public:
|
||||
@@ -793,11 +809,8 @@ public:
|
||||
|
||||
AST::FunctionExpression *ast() const;
|
||||
|
||||
virtual const Value *returnValue() const;
|
||||
virtual int argumentCount() const;
|
||||
virtual const Value *argument(int) const;
|
||||
virtual QString argumentName(int index) const;
|
||||
virtual bool isVariadic() const;
|
||||
|
||||
virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
|
||||
};
|
||||
|
||||
@@ -165,7 +165,7 @@ Link::Link(const Snapshot &snapshot, const QStringList &importPaths, const Libra
|
||||
if (!cppTypeName.isEmpty())
|
||||
value = d->valueOwner->cppQmlTypes().objectByCppName(cppTypeName);
|
||||
if (!value)
|
||||
value = d->valueOwner->undefinedValue();
|
||||
value = d->valueOwner->unknownValue();
|
||||
global->setMember(it.key(), value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@ const Value * ScopeChain::lookup(const QString &name, const ObjectValue **foundI
|
||||
|
||||
if (foundInScope)
|
||||
*foundInScope = 0;
|
||||
|
||||
// we're confident to implement global lookup correctly, so return 'undefined'
|
||||
return m_context->valueOwner()->undefinedValue();
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +292,11 @@ const UndefinedValue *ValueOwner::undefinedValue() const
|
||||
return &_undefinedValue;
|
||||
}
|
||||
|
||||
const UnknownValue *ValueOwner::unknownValue() const
|
||||
{
|
||||
return &_unknownValue;
|
||||
}
|
||||
|
||||
const NumberValue *ValueOwner::numberValue() const
|
||||
{
|
||||
return &_numberValue;
|
||||
@@ -488,7 +493,7 @@ Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, cons
|
||||
Function *function = newFunction();
|
||||
function->setReturnValue(result);
|
||||
for (int i = 0; i < argumentCount; ++i)
|
||||
function->addArgument(undefinedValue()); // ### introduce unknownValue
|
||||
function->addArgument(unknownValue());
|
||||
object->setMember(name, function);
|
||||
return function;
|
||||
}
|
||||
@@ -497,7 +502,7 @@ Function *ValueOwner::addFunction(ObjectValue *object, const QString &name, int
|
||||
{
|
||||
Function *function = newFunction();
|
||||
for (int i = 0; i < argumentCount; ++i)
|
||||
function->addArgument(undefinedValue()); // ### introduce unknownValue
|
||||
function->addArgument(unknownValue());
|
||||
object->setMember(name, function);
|
||||
return function;
|
||||
}
|
||||
@@ -775,7 +780,7 @@ void ValueOwner::initializePrototypes()
|
||||
f->addArgument(stringValue(), "header");
|
||||
f->addArgument(stringValue(), "value");
|
||||
f = addFunction(xmlHttpRequest, "send");
|
||||
f->addArgument(undefinedValue(), "data");
|
||||
f->addArgument(unknownValue(), "data");
|
||||
f = addFunction(xmlHttpRequest, "abort");
|
||||
xmlHttpRequest->setMember("status", numberValue());
|
||||
xmlHttpRequest->setMember("statusText", stringValue());
|
||||
@@ -783,7 +788,7 @@ void ValueOwner::initializePrototypes()
|
||||
f->addArgument(stringValue(), "header");
|
||||
f = addFunction(xmlHttpRequest, "getAllResponseHeaders");
|
||||
xmlHttpRequest->setMember("responseText", stringValue());
|
||||
xmlHttpRequest->setMember("responseXML", undefinedValue());
|
||||
xmlHttpRequest->setMember("responseXML", unknownValue());
|
||||
|
||||
f = addFunction(_globalObject, "XMLHttpRequest", xmlHttpRequest);
|
||||
f->setMember("prototype", xmlHttpRequest);
|
||||
@@ -814,9 +819,9 @@ void ValueOwner::initializePrototypes()
|
||||
f->addArgument(stringValue(), "text");
|
||||
f->addArgument(functionPrototype(), "reviver");
|
||||
f = addFunction(json, "stringify", stringValue());
|
||||
f->addArgument(undefinedValue(), "value");
|
||||
f->addArgument(undefinedValue(), "replacer");
|
||||
f->addArgument(undefinedValue(), "space");
|
||||
f->addArgument(unknownValue(), "value");
|
||||
f->addArgument(unknownValue(), "replacer");
|
||||
f->addArgument(unknownValue(), "space");
|
||||
_globalObject->setMember("JSON", json);
|
||||
|
||||
// global Qt object, in alphabetic order
|
||||
@@ -864,8 +869,8 @@ void ValueOwner::initializePrototypes()
|
||||
_qmlFontObject = newObject(/*prototype =*/ 0);
|
||||
_qmlFontObject->setClassName(QLatin1String("Font"));
|
||||
_qmlFontObject->setMember("family", stringValue());
|
||||
_qmlFontObject->setMember("weight", undefinedValue()); // ### make me an object
|
||||
_qmlFontObject->setMember("capitalization", undefinedValue()); // ### make me an object
|
||||
_qmlFontObject->setMember("weight", unknownValue()); // ### make me an object
|
||||
_qmlFontObject->setMember("capitalization", unknownValue()); // ### make me an object
|
||||
_qmlFontObject->setMember("bold", booleanValue());
|
||||
_qmlFontObject->setMember("italic", booleanValue());
|
||||
_qmlFontObject->setMember("underline", booleanValue());
|
||||
@@ -948,7 +953,9 @@ const Value *ValueOwner::defaultValueForBuiltinType(const QString &name) const
|
||||
return colorValue();
|
||||
} else if (name == QLatin1String("date")) {
|
||||
return datePrototype();
|
||||
} else if (name == QLatin1String("var")
|
||||
|| name == QLatin1String("variant")) {
|
||||
return unknownValue();
|
||||
}
|
||||
// ### variant or var
|
||||
return undefinedValue();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace QmlJS {
|
||||
class Value;
|
||||
class NullValue;
|
||||
class UndefinedValue;
|
||||
class UnknownValue;
|
||||
class NumberValue;
|
||||
class IntValue;
|
||||
class RealValue;
|
||||
@@ -72,6 +73,7 @@ public:
|
||||
|
||||
const NullValue *nullValue() const;
|
||||
const UndefinedValue *undefinedValue() const;
|
||||
const UnknownValue *unknownValue() const;
|
||||
const NumberValue *numberValue() const;
|
||||
const RealValue *realValue() const;
|
||||
const IntValue *intValue() const;
|
||||
@@ -174,6 +176,7 @@ private:
|
||||
|
||||
NullValue _nullValue;
|
||||
UndefinedValue _undefinedValue;
|
||||
UnknownValue _unknownValue;
|
||||
NumberValue _numberValue;
|
||||
RealValue _realValue;
|
||||
IntValue _intValue;
|
||||
|
||||
Reference in New Issue
Block a user