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
|
status_t
|
||||||
SourceLanguage::EvaluateExpression(const BString& expression,
|
SourceLanguage::EvaluateExpression(const BString& expression,
|
||||||
ValueNodeManager* manager, TeamTypeInformation* info,
|
ValueNodeManager* manager, TeamTypeInformation* info,
|
||||||
|
|||||||
@@ -29,10 +29,6 @@ public:
|
|||||||
// returns a reference,
|
// returns a reference,
|
||||||
// may return NULL, if not available
|
// 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,
|
virtual status_t EvaluateExpression(const BString& expression,
|
||||||
ValueNodeManager* manager,
|
ValueNodeManager* manager,
|
||||||
TeamTypeInformation* info,
|
TeamTypeInformation* info,
|
||||||
|
|||||||
@@ -23,13 +23,3 @@ CLanguage::Name() const
|
|||||||
{
|
{
|
||||||
return "C";
|
return "C";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CLanguage::IsModifierValid(char modifier) const
|
|
||||||
{
|
|
||||||
if (modifier == '*')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ public:
|
|||||||
virtual ~CLanguage();
|
virtual ~CLanguage();
|
||||||
|
|
||||||
virtual const char* Name() const;
|
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
|
status_t
|
||||||
CLanguageFamily::EvaluateExpression(const BString& expression,
|
CLanguageFamily::EvaluateExpression(const BString& expression,
|
||||||
ValueNodeManager* manager, TeamTypeInformation* info,
|
ValueNodeManager* manager, TeamTypeInformation* info,
|
||||||
|
|||||||
@@ -17,18 +17,11 @@ public:
|
|||||||
|
|
||||||
virtual SyntaxHighlighter* GetSyntaxHighlighter() const;
|
virtual SyntaxHighlighter* GetSyntaxHighlighter() const;
|
||||||
|
|
||||||
virtual status_t ParseTypeExpression(const BString& expression,
|
|
||||||
TeamTypeInformation* lookup,
|
|
||||||
Type*& _resultType) const;
|
|
||||||
|
|
||||||
virtual status_t EvaluateExpression(const BString& expression,
|
virtual status_t EvaluateExpression(const BString& expression,
|
||||||
ValueNodeManager* manager,
|
ValueNodeManager* manager,
|
||||||
TeamTypeInformation* info,
|
TeamTypeInformation* info,
|
||||||
ExpressionResult*& _output,
|
ExpressionResult*& _output,
|
||||||
ValueNode*& _neededNode);
|
ValueNode*& _neededNode);
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool IsModifierValid(char modifier) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,3 @@ CppLanguage::Name() const
|
|||||||
{
|
{
|
||||||
return "C++";
|
return "C++";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CppLanguage::IsModifierValid(char modifier) const
|
|
||||||
{
|
|
||||||
if (modifier == '*' || modifier == '&')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ public:
|
|||||||
virtual ~CppLanguage();
|
virtual ~CppLanguage();
|
||||||
|
|
||||||
virtual const char* Name() const;
|
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
|
// #pragma mark - VariableValueColumn
|
||||||
|
|
||||||
|
|
||||||
@@ -1708,6 +1736,7 @@ VariablesView::VariablesView(Listener* listener)
|
|||||||
fExpressions(NULL),
|
fExpressions(NULL),
|
||||||
fExpressionChildren(10, false),
|
fExpressionChildren(10, false),
|
||||||
fTableCellContextMenuTracker(NULL),
|
fTableCellContextMenuTracker(NULL),
|
||||||
|
fPendingTypecastInfo(NULL),
|
||||||
fFrameClearPending(false),
|
fFrameClearPending(false),
|
||||||
fListener(listener)
|
fListener(listener)
|
||||||
{
|
{
|
||||||
@@ -1730,6 +1759,8 @@ VariablesView::~VariablesView()
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete fContainerListener;
|
delete fContainerListener;
|
||||||
|
if (fPendingTypecastInfo != NULL)
|
||||||
|
fPendingTypecastInfo->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1848,44 +1879,27 @@ VariablesView::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* type = NULL;
|
BString typeExpression;
|
||||||
BString typeExpression = message->FindString("text");
|
if (message->FindString("text", &typeExpression) == B_OK) {
|
||||||
if (typeExpression.Length() == 0)
|
if (typeExpression.IsEmpty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
FileSourceCode* code = fStackFrame->Function()->GetFunction()
|
if (fPendingTypecastInfo != NULL)
|
||||||
->GetSourceCode();
|
fPendingTypecastInfo->ReleaseReference();
|
||||||
if (code == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
SourceLanguage* language = code->GetSourceLanguage();
|
fPendingTypecastInfo = new(std::nothrow)
|
||||||
if (language == NULL)
|
VariablesExpressionInfo(typeExpression, node);
|
||||||
break;
|
if (fPendingTypecastInfo == NULL) {
|
||||||
|
// TODO: notify user
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (language->ParseTypeExpression(typeExpression,
|
fPendingTypecastInfo->AddListener(this);
|
||||||
fThread->GetTeam()->DebugInfo(), type) != B_OK) {
|
fListener->ExpressionEvaluationRequested(fPendingTypecastInfo,
|
||||||
BString errorMessage;
|
fStackFrame, fThread);
|
||||||
errorMessage.SetToFormat("Failed to resolve type %s",
|
|
||||||
typeExpression.String());
|
|
||||||
BAlert* alert = new(std::nothrow) BAlert("Error",
|
|
||||||
errorMessage.String(), "Close");
|
|
||||||
if (alert != NULL)
|
|
||||||
alert->Go();
|
|
||||||
break;
|
break;
|
||||||
}
|
} else
|
||||||
|
|
||||||
BReference<Type> typeRef(type, true);
|
|
||||||
ValueNode* valueNode = NULL;
|
|
||||||
if (TypeHandlerRoster::Default()->CreateValueNode(
|
|
||||||
node->NodeChild(), type, valueNode) != B_OK) {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
typeRef.Detach();
|
|
||||||
node->NodeChild()->SetNode(valueNode);
|
|
||||||
node->SetCastedType(type);
|
|
||||||
fVariableTableModel->NotifyNodeChanged(node);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case MSG_TYPECAST_TO_ARRAY:
|
case MSG_TYPECAST_TO_ARRAY:
|
||||||
{
|
{
|
||||||
@@ -2071,7 +2085,17 @@ VariablesView::MessageReceived(BMessage* message)
|
|||||||
valueReference.SetTo(value, true);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case MSG_VALUE_NODE_CHANGED:
|
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
|
status_t
|
||||||
VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
|
VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ private:
|
|||||||
class VariableTableModel;
|
class VariableTableModel;
|
||||||
class ContextMenu;
|
class ContextMenu;
|
||||||
class TableCellContextMenuTracker;
|
class TableCellContextMenuTracker;
|
||||||
|
class VariablesExpressionInfo;
|
||||||
typedef BObjectList<ActionMenuItem> ContextActionList;
|
typedef BObjectList<ActionMenuItem> ContextActionList;
|
||||||
typedef BObjectList<ExpressionInfo> ExpressionInfoList;
|
typedef BObjectList<ExpressionInfo> ExpressionInfoList;
|
||||||
typedef BObjectList<ValueNodeChild> ExpressionChildList;
|
typedef BObjectList<ValueNodeChild> ExpressionChildList;
|
||||||
@@ -121,6 +122,9 @@ private:
|
|||||||
void _AddExpressionNode(ExpressionInfo* info,
|
void _AddExpressionNode(ExpressionInfo* info,
|
||||||
status_t result, ExpressionResult* value);
|
status_t result, ExpressionResult* value);
|
||||||
|
|
||||||
|
void _HandleTypecastResult(status_t result,
|
||||||
|
ExpressionResult* value);
|
||||||
|
|
||||||
status_t _GetTypeForTypeCode(int32 typeCode,
|
status_t _GetTypeForTypeCode(int32 typeCode,
|
||||||
Type*& _resultType) const;
|
Type*& _resultType) const;
|
||||||
|
|
||||||
@@ -135,6 +139,7 @@ private:
|
|||||||
ExpressionInfoTable* fExpressions;
|
ExpressionInfoTable* fExpressions;
|
||||||
ExpressionChildList fExpressionChildren;
|
ExpressionChildList fExpressionChildren;
|
||||||
TableCellContextMenuTracker* fTableCellContextMenuTracker;
|
TableCellContextMenuTracker* fTableCellContextMenuTracker;
|
||||||
|
VariablesExpressionInfo* fPendingTypecastInfo;
|
||||||
bool fFrameClearPending;
|
bool fFrameClearPending;
|
||||||
Listener* fListener;
|
Listener* fListener;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user