Debugger: Cleanups.
SourceLanguage and friends: - Remove ParseTypeExpression from SourceLanguage, as its functionality can now properly be subsumed by the general expression parser, and simply becomes another result type thereof. CLanguageFamily/CLanguage/CppLanguage: - Remove IsModifierValid() hook, as this is all now handled internally in the expression parser. VariablesView: - Refactor to handle typecast requests via expression evaluation. Since this is done asynchronously, rework the logic to handle recognizing expression evaluation results that correspond to a requested cast, and handle accordingly.
This commit is contained in:
@@ -20,14 +20,6 @@ SourceLanguage::GetSyntaxHighlighter() const
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SourceLanguage::ParseTypeExpression(const BString& expression,
|
||||
TeamTypeInformation* info, Type*& _resultType) const
|
||||
{
|
||||
return B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SourceLanguage::EvaluateExpression(const BString& expression,
|
||||
ValueNodeManager* manager, TeamTypeInformation* info,
|
||||
|
||||
@@ -29,10 +29,6 @@ public:
|
||||
// returns a reference,
|
||||
// may return NULL, if not available
|
||||
|
||||
virtual status_t ParseTypeExpression(const BString& expression,
|
||||
TeamTypeInformation* info,
|
||||
Type*& _resultType) const;
|
||||
|
||||
virtual status_t EvaluateExpression(const BString& expression,
|
||||
ValueNodeManager* manager,
|
||||
TeamTypeInformation* info,
|
||||
|
||||
@@ -23,13 +23,3 @@ CLanguage::Name() const
|
||||
{
|
||||
return "C";
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CLanguage::IsModifierValid(char modifier) const
|
||||
{
|
||||
if (modifier == '*')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ public:
|
||||
virtual ~CLanguage();
|
||||
|
||||
virtual const char* Name() const;
|
||||
|
||||
protected:
|
||||
virtual bool IsModifierValid(char modifier) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -40,133 +40,6 @@ CLanguageFamily::GetSyntaxHighlighter() const
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CLanguageFamily::ParseTypeExpression(const BString& expression,
|
||||
TeamTypeInformation* info, Type*& _resultType) const
|
||||
{
|
||||
status_t result = B_OK;
|
||||
Type* baseType = NULL;
|
||||
|
||||
BString parsedName = expression;
|
||||
BString baseTypeName;
|
||||
BString arraySpecifier;
|
||||
parsedName.RemoveAll(" ");
|
||||
|
||||
int32 modifierIndex = -1;
|
||||
modifierIndex = parsedName.FindFirst('*');
|
||||
if (modifierIndex == -1)
|
||||
modifierIndex = parsedName.FindFirst('&');
|
||||
if (modifierIndex == -1)
|
||||
modifierIndex = parsedName.FindFirst('[');
|
||||
if (modifierIndex == -1)
|
||||
modifierIndex = parsedName.Length();
|
||||
|
||||
parsedName.MoveInto(baseTypeName, 0, modifierIndex);
|
||||
|
||||
modifierIndex = parsedName.FindFirst('[');
|
||||
if (modifierIndex >= 0) {
|
||||
parsedName.MoveInto(arraySpecifier, modifierIndex,
|
||||
parsedName.Length() - modifierIndex);
|
||||
}
|
||||
|
||||
result = info->LookupTypeByName(baseTypeName, TypeLookupConstraints(),
|
||||
baseType);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
BReference<Type> typeRef;
|
||||
typeRef.SetTo(baseType, true);
|
||||
|
||||
if (!parsedName.IsEmpty()) {
|
||||
AddressType* derivedType = NULL;
|
||||
// walk the list of modifiers trying to add each.
|
||||
for (int32 i = 0; i < parsedName.Length(); i++) {
|
||||
if (!IsModifierValid(parsedName[i]))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
address_type_kind typeKind;
|
||||
switch (parsedName[i]) {
|
||||
case '*':
|
||||
{
|
||||
typeKind = DERIVED_TYPE_POINTER;
|
||||
break;
|
||||
}
|
||||
case '&':
|
||||
{
|
||||
typeKind = DERIVED_TYPE_REFERENCE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (derivedType == NULL) {
|
||||
result = baseType->CreateDerivedAddressType(typeKind,
|
||||
derivedType);
|
||||
} else {
|
||||
result = derivedType->CreateDerivedAddressType(typeKind,
|
||||
derivedType);
|
||||
}
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
typeRef.SetTo(derivedType, true);
|
||||
}
|
||||
|
||||
_resultType = derivedType;
|
||||
} else
|
||||
_resultType = baseType;
|
||||
|
||||
|
||||
if (!arraySpecifier.IsEmpty()) {
|
||||
ArrayType* arrayType = NULL;
|
||||
|
||||
int32 startIndex = 1;
|
||||
do {
|
||||
int32 size = strtoul(arraySpecifier.String() + startIndex,
|
||||
NULL, 10);
|
||||
if (size < 0)
|
||||
return B_ERROR;
|
||||
|
||||
if (arrayType == NULL) {
|
||||
result = _resultType->CreateDerivedArrayType(0, size, true,
|
||||
arrayType);
|
||||
} else {
|
||||
result = arrayType->CreateDerivedArrayType(0, size, true,
|
||||
arrayType);
|
||||
}
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
typeRef.SetTo(arrayType, true);
|
||||
|
||||
startIndex = arraySpecifier.FindFirst('[', startIndex + 1);
|
||||
|
||||
} while (startIndex >= 0);
|
||||
|
||||
// since a C/C++ array is essentially pointer math,
|
||||
// the resulting array has to be wrapped in a pointer to
|
||||
// ensure the element addresses wind up being against the
|
||||
// correct address.
|
||||
AddressType* addressType = NULL;
|
||||
result = arrayType->CreateDerivedAddressType(DERIVED_TYPE_POINTER,
|
||||
addressType);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
_resultType = addressType;
|
||||
}
|
||||
|
||||
typeRef.Detach();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CLanguageFamily::EvaluateExpression(const BString& expression,
|
||||
ValueNodeManager* manager, TeamTypeInformation* info,
|
||||
|
||||
@@ -17,18 +17,11 @@ public:
|
||||
|
||||
virtual SyntaxHighlighter* GetSyntaxHighlighter() const;
|
||||
|
||||
virtual status_t ParseTypeExpression(const BString& expression,
|
||||
TeamTypeInformation* lookup,
|
||||
Type*& _resultType) const;
|
||||
|
||||
virtual status_t EvaluateExpression(const BString& expression,
|
||||
ValueNodeManager* manager,
|
||||
TeamTypeInformation* info,
|
||||
ExpressionResult*& _output,
|
||||
ValueNode*& _neededNode);
|
||||
|
||||
protected:
|
||||
virtual bool IsModifierValid(char modifier) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -23,13 +23,3 @@ CppLanguage::Name() const
|
||||
{
|
||||
return "C++";
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CppLanguage::IsModifierValid(char modifier) const
|
||||
{
|
||||
if (modifier == '*' || modifier == '&')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ public:
|
||||
virtual ~CppLanguage();
|
||||
|
||||
virtual const char* Name() const;
|
||||
|
||||
protected:
|
||||
virtual bool IsModifierValid(char modifier) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -544,6 +544,34 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - VariablesExpressionInfo
|
||||
|
||||
|
||||
class VariablesView::VariablesExpressionInfo : public ExpressionInfo {
|
||||
public:
|
||||
VariablesExpressionInfo(const BString& expression, ModelNode* node)
|
||||
:
|
||||
ExpressionInfo(expression),
|
||||
fTargetNode(node)
|
||||
{
|
||||
fTargetNode->AcquireReference();
|
||||
}
|
||||
|
||||
virtual ~VariablesExpressionInfo()
|
||||
{
|
||||
fTargetNode->ReleaseReference();
|
||||
}
|
||||
|
||||
inline ModelNode* TargetNode() const
|
||||
{
|
||||
return fTargetNode;
|
||||
}
|
||||
|
||||
private:
|
||||
ModelNode* fTargetNode;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - VariableValueColumn
|
||||
|
||||
|
||||
@@ -1708,6 +1736,7 @@ VariablesView::VariablesView(Listener* listener)
|
||||
fExpressions(NULL),
|
||||
fExpressionChildren(10, false),
|
||||
fTableCellContextMenuTracker(NULL),
|
||||
fPendingTypecastInfo(NULL),
|
||||
fFrameClearPending(false),
|
||||
fListener(listener)
|
||||
{
|
||||
@@ -1730,6 +1759,8 @@ VariablesView::~VariablesView()
|
||||
}
|
||||
|
||||
delete fContainerListener;
|
||||
if (fPendingTypecastInfo != NULL)
|
||||
fPendingTypecastInfo->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
@@ -1848,44 +1879,27 @@ VariablesView::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
Type* type = NULL;
|
||||
BString typeExpression = message->FindString("text");
|
||||
if (typeExpression.Length() == 0)
|
||||
break;
|
||||
BString typeExpression;
|
||||
if (message->FindString("text", &typeExpression) == B_OK) {
|
||||
if (typeExpression.IsEmpty())
|
||||
break;
|
||||
|
||||
FileSourceCode* code = fStackFrame->Function()->GetFunction()
|
||||
->GetSourceCode();
|
||||
if (code == NULL)
|
||||
break;
|
||||
if (fPendingTypecastInfo != NULL)
|
||||
fPendingTypecastInfo->ReleaseReference();
|
||||
|
||||
SourceLanguage* language = code->GetSourceLanguage();
|
||||
if (language == NULL)
|
||||
break;
|
||||
fPendingTypecastInfo = new(std::nothrow)
|
||||
VariablesExpressionInfo(typeExpression, node);
|
||||
if (fPendingTypecastInfo == NULL) {
|
||||
// TODO: notify user
|
||||
break;
|
||||
}
|
||||
|
||||
if (language->ParseTypeExpression(typeExpression,
|
||||
fThread->GetTeam()->DebugInfo(), type) != B_OK) {
|
||||
BString errorMessage;
|
||||
errorMessage.SetToFormat("Failed to resolve type %s",
|
||||
typeExpression.String());
|
||||
BAlert* alert = new(std::nothrow) BAlert("Error",
|
||||
errorMessage.String(), "Close");
|
||||
if (alert != NULL)
|
||||
alert->Go();
|
||||
fPendingTypecastInfo->AddListener(this);
|
||||
fListener->ExpressionEvaluationRequested(fPendingTypecastInfo,
|
||||
fStackFrame, fThread);
|
||||
break;
|
||||
}
|
||||
|
||||
BReference<Type> typeRef(type, true);
|
||||
ValueNode* valueNode = NULL;
|
||||
if (TypeHandlerRoster::Default()->CreateValueNode(
|
||||
node->NodeChild(), type, valueNode) != B_OK) {
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
typeRef.Detach();
|
||||
node->NodeChild()->SetNode(valueNode);
|
||||
node->SetCastedType(type);
|
||||
fVariableTableModel->NotifyNodeChanged(node);
|
||||
break;
|
||||
}
|
||||
case MSG_TYPECAST_TO_ARRAY:
|
||||
{
|
||||
@@ -2071,7 +2085,17 @@ VariablesView::MessageReceived(BMessage* message)
|
||||
valueReference.SetTo(value, true);
|
||||
}
|
||||
|
||||
_AddExpressionNode(info, result, value);
|
||||
VariablesExpressionInfo* variableInfo
|
||||
= dynamic_cast<VariablesExpressionInfo*>(info);
|
||||
if (variableInfo != NULL) {
|
||||
if (fPendingTypecastInfo == variableInfo) {
|
||||
_HandleTypecastResult(result, value);
|
||||
fPendingTypecastInfo->ReleaseReference();
|
||||
fPendingTypecastInfo = NULL;
|
||||
}
|
||||
} else
|
||||
_AddExpressionNode(info, result, value);
|
||||
|
||||
break;
|
||||
}
|
||||
case MSG_VALUE_NODE_CHANGED:
|
||||
@@ -2985,6 +3009,60 @@ VariablesView::_AddExpressionNode(ExpressionInfo* info, status_t result,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VariablesView::_HandleTypecastResult(status_t result, ExpressionResult* value)
|
||||
{
|
||||
BString errorMessage;
|
||||
if (value == NULL) {
|
||||
errorMessage.SetToFormat("Failed to evaluate expression \"%s\": %s (%"
|
||||
B_PRId32 ")", fPendingTypecastInfo->Expression().String(),
|
||||
strerror(result), result);
|
||||
} else if (result != B_OK) {
|
||||
BVariant valueData;
|
||||
value->PrimitiveValue()->ToVariant(valueData);
|
||||
|
||||
// usually, the evaluation can give us back an error message to
|
||||
// specifically indicate why it failed. If it did, simply use
|
||||
// the message directly, otherwise fall back to generating an error
|
||||
// message based on the error code
|
||||
if (valueData.Type() == B_STRING_TYPE)
|
||||
errorMessage = valueData.ToString();
|
||||
else {
|
||||
errorMessage.SetToFormat("Failed to evaluate expression \"%s\":"
|
||||
" %s (%" B_PRId32 ")",
|
||||
fPendingTypecastInfo->Expression().String(), strerror(result),
|
||||
result);
|
||||
}
|
||||
|
||||
} else if (value->Kind() != EXPRESSION_RESULT_KIND_TYPE) {
|
||||
errorMessage.SetToFormat("Expression \"%s\" does not evaluate to a"
|
||||
" type.", fPendingTypecastInfo->Expression().String());
|
||||
}
|
||||
|
||||
if (!errorMessage.IsEmpty()) {
|
||||
BAlert* alert = new(std::nothrow) BAlert("Typecast error",
|
||||
errorMessage, "Close");
|
||||
if (alert != NULL)
|
||||
alert->Go();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Type* type = value->GetType();
|
||||
BReference<Type> typeRef(type);
|
||||
ValueNode* valueNode = NULL;
|
||||
ModelNode* node = fPendingTypecastInfo->TargetNode();
|
||||
if (TypeHandlerRoster::Default()->CreateValueNode(node->NodeChild(), type,
|
||||
valueNode) != B_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->NodeChild()->SetNode(valueNode);
|
||||
node->SetCastedType(type);
|
||||
fVariableTableModel->NotifyNodeChanged(node);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
|
||||
{
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
class VariableTableModel;
|
||||
class ContextMenu;
|
||||
class TableCellContextMenuTracker;
|
||||
class VariablesExpressionInfo;
|
||||
typedef BObjectList<ActionMenuItem> ContextActionList;
|
||||
typedef BObjectList<ExpressionInfo> ExpressionInfoList;
|
||||
typedef BObjectList<ValueNodeChild> ExpressionChildList;
|
||||
@@ -121,6 +122,9 @@ private:
|
||||
void _AddExpressionNode(ExpressionInfo* info,
|
||||
status_t result, ExpressionResult* value);
|
||||
|
||||
void _HandleTypecastResult(status_t result,
|
||||
ExpressionResult* value);
|
||||
|
||||
status_t _GetTypeForTypeCode(int32 typeCode,
|
||||
Type*& _resultType) const;
|
||||
|
||||
@@ -135,6 +139,7 @@ private:
|
||||
ExpressionInfoTable* fExpressions;
|
||||
ExpressionChildList fExpressionChildren;
|
||||
TableCellContextMenuTracker* fTableCellContextMenuTracker;
|
||||
VariablesExpressionInfo* fPendingTypecastInfo;
|
||||
bool fFrameClearPending;
|
||||
Listener* fListener;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user