hrev48361 adds 2 changesets to branch 'master' old head: 8d48eb9311edaabd52ef4f6ba9ff22fd89de413f new head: b4a861136b9249eefc78a47528e5f4e515c633c6 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=b4a8611+%5E8d48eb9 ---------------------------------------------------------------------------- 81c848a: Debugger: Rework expression parsing API. ExpressionInfo: - No longer stores an explicit result type (this is inferred from evaluation of the expression itself now). - Introduce class ExpressionResult for returning the result of an expression computation. This can currently take the form of either a primitive value, or a value node object. - Adjust UserInterfaceListener and ExpressionInfo::Listener to take the above changes into account, and correspondingly adjust all callers/listeners. CLanguageExpressionEvaluator: - Introduce child class Operand. This subsumes the functionality that was previously in the separate Number class, and can represent a primitive value, a value node or a type. Also has functionality to implicity handle type promotion/inferring when performing calculations between operands. - Adjust expression parser to operate in terms of Operands rather than Numbers. This allows a number of improvements, most notably that an expression can now return a value node as a result rather than only a primitive number. This capability isn't yet fully used, but paves the way for future uses such as an expression that evaluates to a data member, a global variable, or an arbitrary pointer of a particular type. - Various cleanups/simplifications that were possible as a result of the above changes. ExpressionEvaluationWindow/ExpressionPromptWindow: - Remove type menu field, since the expression API no longer uses it. Adding/removing expressions in the VariablesView is temporarily disabled, pending some further rework there to properly handle the new result object. b4a8611: Debugger: Adjust VariablesView for new expression API. - Simplify handling of expression nodes. For primitive results, we now construct a Variable object that represents the expression result, and then add that as we would any other local variable. This simplifies handling, and also allows saving/restoration of their view state to be handled the same as other nodes. Complex expression results aren't yet handled properly, pending some further work in progress on the evaluator. [ Rene Gollent <rene@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 30 files changed, 1982 insertions(+), 1890 deletions(-) src/apps/debugger/Jamfile | 1 - src/apps/debugger/controllers/ThreadHandler.cpp | 54 +- src/apps/debugger/controllers/ThreadHandler.h | 7 +- .../debugger/jobs/ExpressionEvaluationJob.cpp | 5 +- src/apps/debugger/jobs/Jobs.h | 5 +- src/apps/debugger/model/ExpressionInfo.cpp | 118 +- src/apps/debugger/model/ExpressionInfo.h | 53 +- .../debugger/source_language/CLanguageFamily.cpp | 52 +- .../debugger/source_language/CLanguageFamily.h | 5 +- .../debugger/source_language/SourceLanguage.cpp | 2 +- .../debugger/source_language/SourceLanguage.h | 7 +- .../CLanguageExpressionEvaluator.cpp | 1739 +++++++++++++++--- .../CLanguageExpressionEvaluator.h | 24 +- src/apps/debugger/types/Number.cpp | 1008 ---------- src/apps/debugger/types/Number.h | 58 - .../debugger/user_interface/cli/CliContext.cpp | 11 +- .../debugger/user_interface/cli/CliContext.h | 6 +- .../cli/commands/CliDumpMemoryCommand.cpp | 38 +- .../gui/inspector_window/InspectorWindow.cpp | 35 +- .../gui/inspector_window/InspectorWindow.h | 2 +- .../team_window/ExpressionEvaluationWindow.cpp | 108 +- .../gui/team_window/ExpressionEvaluationWindow.h | 9 +- .../gui/team_window/ExpressionPromptWindow.cpp | 59 +- .../gui/team_window/ExpressionPromptWindow.h | 6 - .../gui/team_window/TeamWindow.cpp | 3 - .../gui/team_window/VariablesView.cpp | 386 ++-- .../gui/team_window/VariablesView.h | 12 +- .../gui/team_window/WatchPromptWindow.cpp | 55 +- .../gui/team_window/WatchPromptWindow.h | 2 +- .../debugger/user_interface/util/UiUtils.cpp | 2 + ############################################################################ Commit: 81c848a14a380679a439cccb9e10b60d05bd6fbc URL: http://cgit.haiku-os.org/haiku/commit/?id=81c848a Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Sat Nov 15 05:31:17 2014 UTC Debugger: Rework expression parsing API. ExpressionInfo: - No longer stores an explicit result type (this is inferred from evaluation of the expression itself now). - Introduce class ExpressionResult for returning the result of an expression computation. This can currently take the form of either a primitive value, or a value node object. - Adjust UserInterfaceListener and ExpressionInfo::Listener to take the above changes into account, and correspondingly adjust all callers/listeners. CLanguageExpressionEvaluator: - Introduce child class Operand. This subsumes the functionality that was previously in the separate Number class, and can represent a primitive value, a value node or a type. Also has functionality to implicity handle type promotion/inferring when performing calculations between operands. - Adjust expression parser to operate in terms of Operands rather than Numbers. This allows a number of improvements, most notably that an expression can now return a value node as a result rather than only a primitive number. This capability isn't yet fully used, but paves the way for future uses such as an expression that evaluates to a data member, a global variable, or an arbitrary pointer of a particular type. - Various cleanups/simplifications that were possible as a result of the above changes. ExpressionEvaluationWindow/ExpressionPromptWindow: - Remove type menu field, since the expression API no longer uses it. Adding/removing expressions in the VariablesView is temporarily disabled, pending some further rework there to properly handle the new result object. ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index cb3317a..15787ae 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -222,7 +222,6 @@ Application Debugger : # types ArrayIndexPath.cpp - Number.cpp TargetAddressRangeList.cpp ValueLocation.cpp diff --git a/src/apps/debugger/controllers/ThreadHandler.cpp b/src/apps/debugger/controllers/ThreadHandler.cpp index 18c5ecc..f513d71 100644 --- a/src/apps/debugger/controllers/ThreadHandler.cpp +++ b/src/apps/debugger/controllers/ThreadHandler.cpp @@ -35,6 +35,7 @@ #include "Team.h" #include "Tracing.h" #include "Value.h" +#include "ValueLocation.h" #include "Worker.h" @@ -63,7 +64,7 @@ public: } virtual void ExpressionEvaluated(ExpressionInfo* info, status_t result, - Value* value) + ExpressionResult* value) { fHandler->_HandleBreakpointConditionEvaluated(value); } @@ -888,14 +889,8 @@ ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState) if (listener == NULL) return false; - Type* type = new(std::nothrow) SyntheticPrimitiveType(B_UINT64_TYPE); - if (type == NULL) - return false; - - BReference<Type> typeReference(type, true); - ExpressionInfo* expressionInfo = new(std::nothrow) ExpressionInfo( - userBreakpoint->Condition(), type); + userBreakpoint->Condition()); if (expressionInfo == NULL) return false; @@ -921,23 +916,13 @@ ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState) teamLocker.Lock(); - bool stop = false; - if (fConditionResult == NULL) - stop = true; - else { - BVariant value; - if (!fConditionResult->ToVariant(value)) - stop = true; - if (!value.TypeIsInteger(value.Type())) - stop = true; - stop = value.ToBool(); - fConditionResult->ReleaseReference(); - fConditionResult = NULL; - } - - if (stop) + if (_CheckStopCondition()) { + if (fConditionResult != NULL) { + fConditionResult->ReleaseReference(); + fConditionResult = NULL; + } return false; - else { + } else { _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN, BString()); fDebuggerInterface->ContinueThread(fThread->ID()); @@ -951,7 +936,7 @@ ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState) void -ThreadHandler::_HandleBreakpointConditionEvaluated(Value* value) +ThreadHandler::_HandleBreakpointConditionEvaluated(ExpressionResult* value) { fConditionResult = value; if (fConditionResult != NULL) @@ -961,6 +946,25 @@ ThreadHandler::_HandleBreakpointConditionEvaluated(Value* value) bool +ThreadHandler::_CheckStopCondition() +{ + // if we we're unable to properly assess the expression result + // in any way, fall back to behaving like an unconditional breakpoint. + if (fConditionResult == NULL) + return true; + + if (fConditionResult->Kind() != EXPRESSION_RESULT_KIND_PRIMITIVE) + return true; + + BVariant value; + if (!fConditionResult->PrimitiveValue()->ToVariant(value)) + return true; + + return value.ToBool(); +} + + +bool ThreadHandler::_HasExitedFrame(target_addr_t framePointer) const { return fDebuggerInterface->GetArchitecture()->StackGrowthDirection() diff --git a/src/apps/debugger/controllers/ThreadHandler.h b/src/apps/debugger/controllers/ThreadHandler.h index 86b5307..eb34741 100644 --- a/src/apps/debugger/controllers/ThreadHandler.h +++ b/src/apps/debugger/controllers/ThreadHandler.h @@ -18,10 +18,10 @@ class BreakpointManager; class DebuggerInterface; +class ExpressionResult; class ImageDebugInfoJobListener; class StackFrame; class Statement; -class Value; class Worker; @@ -102,7 +102,8 @@ private: bool _HandleBreakpointConditionIfNeeded( CpuState* cpuState); void _HandleBreakpointConditionEvaluated( - Value* value); + ExpressionResult* value); + bool _CheckStopCondition(); bool _HandleBreakpointHitStep(CpuState* cpuState); bool _HandleSingleStepStep(CpuState* cpuState); @@ -124,7 +125,7 @@ private: target_addr_t fPreviousFrameAddress; bool fSingleStepping; sem_id fConditionWaitSem; - Value* fConditionResult; + ExpressionResult* fConditionResult; public: ThreadHandler* fNext; diff --git a/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp b/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp index a65879d..52b5cc1 100644 --- a/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp +++ b/src/apps/debugger/jobs/ExpressionEvaluationJob.cpp @@ -19,6 +19,7 @@ #include "Value.h" #include "ValueNode.h" #include "ValueNodeManager.h" +#include "Variable.h" ExpressionEvaluationJob::ExpressionEvaluationJob(Team* team, @@ -89,10 +90,8 @@ ExpressionEvaluationJob::Do() } ValueNode* neededNode = NULL; - PrimitiveType* type = dynamic_cast<PrimitiveType*>( - fExpressionInfo->ResultType()); result = fLanguage->EvaluateExpression(fExpressionInfo->Expression(), - type->TypeConstant(), fManager, fResultValue, neededNode); + fManager, fResultValue, neededNode); if (neededNode != NULL) { result = ResolveNodeValue(neededNode); if (State() == JOB_STATE_WAITING) diff --git a/src/apps/debugger/jobs/Jobs.h b/src/apps/debugger/jobs/Jobs.h index 2c8db45..65a0ab0 100644 --- a/src/apps/debugger/jobs/Jobs.h +++ b/src/apps/debugger/jobs/Jobs.h @@ -19,6 +19,7 @@ class BVariant; class CpuState; class DebuggerInterface; class ExpressionInfo; +class ExpressionResult; class Function; class FunctionInstance; class Image; @@ -245,7 +246,7 @@ public: virtual const JobKey& Key() const; virtual status_t Do(); - Value* GetResultValue() const { return fResultValue; } + ExpressionResult* GetResult() const { return fResultValue; } private: status_t ResolveNodeValue(ValueNode* node); @@ -261,7 +262,7 @@ private: StackFrame* fFrame; Thread* fThread; ValueNodeManager* fManager; - Value* fResultValue; + ExpressionResult* fResultValue; }; diff --git a/src/apps/debugger/model/ExpressionInfo.cpp b/src/apps/debugger/model/ExpressionInfo.cpp index bdbfab7..9aaf0d6 100644 --- a/src/apps/debugger/model/ExpressionInfo.cpp +++ b/src/apps/debugger/model/ExpressionInfo.cpp @@ -6,67 +6,120 @@ #include "ExpressionInfo.h" -#include "Type.h" +#include "Value.h" +#include "ValueNode.h" -ExpressionInfo::ExpressionInfo() +// #pragma mark - ExpressionResult + + +ExpressionResult::ExpressionResult() : - fExpression(), - fResultType(NULL) + fResultKind(EXPRESSION_RESULT_KIND_UNKNOWN), + fPrimitiveValue(NULL), + fValueNodeValue(NULL) { } -ExpressionInfo::ExpressionInfo(const ExpressionInfo& other) - : - fExpression(other.fExpression), - fResultType(other.fResultType) +ExpressionResult::~ExpressionResult() { - if (fResultType != NULL) - fResultType->AcquireReference(); + if (fPrimitiveValue != NULL) + fPrimitiveValue->ReleaseReference(); + + if (fValueNodeValue != NULL) + fValueNodeValue->ReleaseReference(); } -ExpressionInfo::~ExpressionInfo() +void +ExpressionResult::SetToPrimitive(Value* value) { - SetResultType(NULL); + _Unset(); + + fPrimitiveValue = value; + if (fPrimitiveValue != NULL) { + fPrimitiveValue->AcquireReference(); + fResultKind = EXPRESSION_RESULT_KIND_PRIMITIVE; + } } -ExpressionInfo::ExpressionInfo(const BString& expression, Type* resultType) - : - fExpression(expression), - fResultType(resultType) +void +ExpressionResult::SetToValueNode(ValueNodeChild* child) { - if (resultType != NULL) - resultType->AcquireReference(); + _Unset(); + + fValueNodeValue = child; + if (fValueNodeValue != NULL) { + fValueNodeValue->AcquireReference(); + fResultKind = EXPRESSION_RESULT_KIND_VALUE_NODE; + } + + // if the child has a node with a resolved value, store + // it as a primitive, so the consumer of the expression + // can use it as-is if desired. + + ValueNode* node = child->Node(); + if (node == NULL) + return; + + fPrimitiveValue = node->GetValue(); + if (fPrimitiveValue != NULL) + fPrimitiveValue->AcquireReference(); } void -ExpressionInfo::SetTo(const BString& expression, Type* resultType) +ExpressionResult::_Unset() { - SetExpression(expression); - SetResultType(resultType); + if (fPrimitiveValue != NULL) { + fPrimitiveValue->ReleaseReference(); + fPrimitiveValue = NULL; + } + + if (fValueNodeValue != NULL) { + fValueNodeValue->ReleaseReference(); + fValueNodeValue = NULL; + } + + fResultKind = EXPRESSION_RESULT_KIND_UNKNOWN; } -void -ExpressionInfo::SetExpression(const BString& expression) +// #pragma mark - ExpressionInfo + + +ExpressionInfo::ExpressionInfo() + : + fExpression() { - fExpression = expression; } -void -ExpressionInfo::SetResultType(Type* resultType) +ExpressionInfo::ExpressionInfo(const ExpressionInfo& other) + : + fExpression(other.fExpression) +{ +} + + +ExpressionInfo::~ExpressionInfo() { - if (fResultType != NULL) - fResultType->ReleaseReference(); +} + - fResultType = resultType; - if (fResultType != NULL) - fResultType->AcquireReference(); +ExpressionInfo::ExpressionInfo(const BString& expression) + : + fExpression(expression) +{ +} + + +void +ExpressionInfo::SetTo(const BString& expression) +{ + fExpression = expression; } @@ -85,7 +138,8 @@ ExpressionInfo::RemoveListener(Listener* listener) void -ExpressionInfo::NotifyExpressionEvaluated(status_t result, Value* value) +ExpressionInfo::NotifyExpressionEvaluated(status_t result, + ExpressionResult* value) { for (ListenerList::Iterator it = fListeners.GetIterator(); Listener* listener = it.Next();) { diff --git a/src/apps/debugger/model/ExpressionInfo.h b/src/apps/debugger/model/ExpressionInfo.h index 33c5e8b..feab5c4 100644 --- a/src/apps/debugger/model/ExpressionInfo.h +++ b/src/apps/debugger/model/ExpressionInfo.h @@ -10,9 +10,44 @@ #include <Referenceable.h> #include <util/DoublyLinkedList.h> +#include <Variant.h> + -class Type; class Value; +class ValueNodeChild; + + +enum expression_result_kind { + EXPRESSION_RESULT_KIND_UNKNOWN = 0, + EXPRESSION_RESULT_KIND_PRIMITIVE, + EXPRESSION_RESULT_KIND_VALUE_NODE +}; + + +class ExpressionResult : public BReferenceable { +public: + ExpressionResult(); + virtual ~ExpressionResult(); + + + expression_result_kind Kind() const { return fResultKind; } + + Value* PrimitiveValue() const + { return fPrimitiveValue; } + ValueNodeChild* ValueNodeValue() const + { return fValueNodeValue; } + + void SetToPrimitive(Value* value); + void SetToValueNode(ValueNodeChild* child); + +private: + void _Unset(); + +private: + expression_result_kind fResultKind; + Value* fPrimitiveValue; + ValueNodeChild* fValueNodeValue; +}; class ExpressionInfo : public BReferenceable { @@ -22,31 +57,24 @@ public: public: ExpressionInfo(); ExpressionInfo(const ExpressionInfo& other); - ExpressionInfo(const BString& expression, - Type* resultType); + ExpressionInfo(const BString& expression); virtual ~ExpressionInfo(); - void SetTo(const BString& expression, - Type* resultType); + void SetTo(const BString& expression); const BString& Expression() const { return fExpression; } - void SetExpression(const BString& expression); - - Type* ResultType() const { return fResultType; } - void SetResultType(Type* resultType); void AddListener(Listener* listener); void RemoveListener(Listener* listener); void NotifyExpressionEvaluated(status_t result, - Value* value); + ExpressionResult* value); private: typedef DoublyLinkedList<Listener> ListenerList; private: BString fExpression; - Type* fResultType; ListenerList fListeners; }; @@ -56,7 +84,8 @@ public: virtual ~Listener(); virtual void ExpressionEvaluated(ExpressionInfo* info, - status_t result, Value* value) = 0; + status_t result, + ExpressionResult* value) = 0; }; diff --git a/src/apps/debugger/source_language/CLanguageFamily.cpp b/src/apps/debugger/source_language/CLanguageFamily.cpp index 88c6be7..96f7937 100644 --- a/src/apps/debugger/source_language/CLanguageFamily.cpp +++ b/src/apps/debugger/source_language/CLanguageFamily.cpp @@ -11,11 +11,9 @@ #include <stdlib.h> #include "CLanguageExpressionEvaluator.h" -#include "FloatValue.h" -#include "IntegerValue.h" -#include "Number.h" -#include "StringValue.h" +#include "ExpressionInfo.h" #include "TeamTypeInformation.h" +#include "StringValue.h" #include "Type.h" #include "TypeLookupConstraints.h" @@ -167,46 +165,28 @@ CLanguageFamily::ParseTypeExpression(const BString& expression, status_t -CLanguageFamily::EvaluateExpression(const BString& expression, type_code type, - ValueNodeManager* manager, Value*& _output, ValueNode*& _neededNode) +CLanguageFamily::EvaluateExpression(const BString& expression, + ValueNodeManager* manager, ExpressionResult*& _output, + ValueNode*& _neededNode) { _output = NULL; _neededNode = NULL; CLanguageExpressionEvaluator evaluator; - Number result; try { - result = evaluator.Evaluate(expression, type, manager); - BVariant resultValue = result.GetValue(); - switch (type) { - case B_INT8_TYPE: - case B_UINT8_TYPE: - case B_INT16_TYPE: - case B_UINT16_TYPE: - case B_INT32_TYPE: - case B_UINT32_TYPE: - case B_INT64_TYPE: - case B_UINT64_TYPE: - _output = new(std::nothrow) IntegerValue(resultValue); - break; - - case B_FLOAT_TYPE: - _output = new(std::nothrow) FloatValue(resultValue.ToFloat()); - break; - - case B_DOUBLE_TYPE: - _output = new(std::nothrow) FloatValue(resultValue.ToDouble()); - break; - } - - if (_output == NULL) - return B_NO_MEMORY; - + _output = evaluator.Evaluate(expression, manager); return B_OK; } catch (ParseException ex) { - BString stringValue; - stringValue.SetToFormat("Parse error at position %" B_PRId32 ": %s", + BString error; + error.SetToFormat("Parse error at position %" B_PRId32 ": %s", ex.position, ex.message.String()); - _output = new(std::nothrow) StringValue(stringValue); + StringValue* value = new(std::nothrow) StringValue(error.String()); + if (value == NULL) + return B_NO_MEMORY; + BReference<Value> valueReference(value, true); + _output = new(std::nothrow) ExpressionResult(); + if (_output == NULL) + return B_NO_MEMORY; + _output->SetToPrimitive(value); return B_BAD_DATA; } catch (ValueNeededException ex) { _neededNode = ex.value; diff --git a/src/apps/debugger/source_language/CLanguageFamily.h b/src/apps/debugger/source_language/CLanguageFamily.h index 7159df0..62fa17c 100644 --- a/src/apps/debugger/source_language/CLanguageFamily.h +++ b/src/apps/debugger/source_language/CLanguageFamily.h @@ -22,8 +22,9 @@ public: Type*& _resultType) const; virtual status_t EvaluateExpression(const BString& expression, - type_code type, ValueNodeManager* manager, - Value*& _output, ValueNode*& _neededNode); + ValueNodeManager* manager, + ExpressionResult*& _output, + ValueNode*& _neededNode); protected: virtual bool IsModifierValid(char modifier) const = 0; diff --git a/src/apps/debugger/source_language/SourceLanguage.cpp b/src/apps/debugger/source_language/SourceLanguage.cpp index 7f16327..5d7e6ec 100644 --- a/src/apps/debugger/source_language/SourceLanguage.cpp +++ b/src/apps/debugger/source_language/SourceLanguage.cpp @@ -30,7 +30,7 @@ SourceLanguage::ParseTypeExpression(const BString& expression, status_t SourceLanguage::EvaluateExpression(const BString& expression, - type_code type, ValueNodeManager* manager, Value*& _resultValue, + ValueNodeManager* manager, ExpressionResult*& _resultValue, ValueNode*& _neededNode) { return B_NOT_SUPPORTED; diff --git a/src/apps/debugger/source_language/SourceLanguage.h b/src/apps/debugger/source_language/SourceLanguage.h index c732b3b..2133100 100644 --- a/src/apps/debugger/source_language/SourceLanguage.h +++ b/src/apps/debugger/source_language/SourceLanguage.h @@ -11,10 +11,10 @@ class BString; +class ExpressionResult; class SyntaxHighlighter; class TeamTypeInformation; class Type; -class Value; class ValueNode; class ValueNodeManager; @@ -34,8 +34,9 @@ public: Type*& _resultType) const; virtual status_t EvaluateExpression(const BString& expression, - type_code type, ValueNodeManager* manager, - Value*& _output, ValueNode*& _neededNode); + ValueNodeManager* manager, + ExpressionResult*& _output, + ValueNode*& _neededNode); }; diff --git a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp index 4d6574e..f4d5067 100644 --- a/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp +++ b/src/apps/debugger/source_language/expression_evaluators/CLanguageExpressionEvaluator.cpp @@ -11,6 +11,8 @@ #include "CLanguageExpressionEvaluator.h" +#include <algorithm> + #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -18,7 +20,9 @@ #include "AutoLocker.h" -#include "Number.h" +#include "ExpressionInfo.h" +#include "FloatValue.h" +#include "IntegerValue.h" #include "StackFrame.h" #include "Thread.h" #include "Type.h" @@ -26,143 +30,1402 @@ #include "ValueNode.h" #include "ValueNodeManager.h" #include "Variable.h" +#include "VariableValueNodeChild.h" + + +enum { + TOKEN_NONE = 0, + TOKEN_IDENTIFIER, + TOKEN_CONSTANT, + TOKEN_END_OF_LINE, + + TOKEN_PLUS, + TOKEN_MINUS, + + TOKEN_STAR, + TOKEN_SLASH, + TOKEN_MODULO, + + TOKEN_POWER, + + TOKEN_OPENING_BRACKET, + TOKEN_CLOSING_BRACKET, + + TOKEN_LOGICAL_AND, + TOKEN_LOGICAL_OR, + TOKEN_LOGICAL_NOT, + TOKEN_BITWISE_AND, + TOKEN_BITWISE_OR, + TOKEN_BITWISE_NOT, + TOKEN_BITWISE_XOR, + TOKEN_EQ, + TOKEN_NE, + TOKEN_GT, + TOKEN_GE, + TOKEN_LT, + TOKEN_LE, + + TOKEN_MEMBER_PTR +}; + + +enum operand_kind { + OPERAND_KIND_UNKNOWN = 0, + OPERAND_KIND_PRIMITIVE, + OPERAND_KIND_TYPE, + OPERAND_KIND_VALUE_NODE +}; + + +static BString TokenTypeToString(int32 type) +{ + BString token; + + switch (type) { + case TOKEN_PLUS: + token = "+"; + break; + + case TOKEN_MINUS: + token = "-"; + break; + + case TOKEN_STAR: + token = "*"; + break; + + case TOKEN_SLASH: + token = "/"; + break; + + case TOKEN_MODULO: + token = "%"; + break; + + case TOKEN_POWER: + token = "**"; + break; + + case TOKEN_OPENING_BRACKET: + token = "("; + break; + + case TOKEN_CLOSING_BRACKET: + token = ")"; + break; + + case TOKEN_LOGICAL_AND: + token = "&&"; + break; + + case TOKEN_LOGICAL_OR: + token = "||"; + break; + + case TOKEN_LOGICAL_NOT: + token = "!"; + break; + + case TOKEN_BITWISE_AND: + token = "&"; + break; + + case TOKEN_BITWISE_OR: + token = "|"; + break; + + case TOKEN_BITWISE_NOT: + token = "~"; + break; + + case TOKEN_BITWISE_XOR: + token = "^"; + break; + + case TOKEN_EQ: + token = "=="; + break; + + case TOKEN_NE: + token = "!="; + break; + + case TOKEN_GT: + token = ">"; + break; + + case TOKEN_GE: + token = ">="; + break; + + case TOKEN_LT: + token = "<"; + break; + + case TOKEN_LE: + token = "<="; + break; + + case TOKEN_MEMBER_PTR: + token = "->"; + break; + + default: + token.SetToFormat("Unknown token type %" B_PRId32, type); + break; + } + + return token; +} + + +// #pragma mark - CLanguageExpressionEvaluator::Operand + + +class CLanguageExpressionEvaluator::Operand { +public: + Operand() + : + fPrimitive(), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_UNKNOWN) + { + } + + Operand(int64 value) + : + fPrimitive(value), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_PRIMITIVE) + { + } + + Operand(double value) + : + fPrimitive(value), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_PRIMITIVE) + { + } + + Operand(ValueNode* node) + : + fPrimitive(), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_UNKNOWN) + { + SetTo(node); + } + + Operand(Type* type) + : + fPrimitive(), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_UNKNOWN) + { + SetTo(type); + } + + Operand(const Operand& X) + : + fPrimitive(), + fValueNode(NULL), + fType(NULL), + fKind(OPERAND_KIND_UNKNOWN) + { + *this = X; + } + + + virtual ~Operand() + { + Unset(); + } + + Operand& operator=(const Operand& X) + { + switch (X.fKind) { + case OPERAND_KIND_UNKNOWN: + Unset(); + break; + + case OPERAND_KIND_PRIMITIVE: + SetTo(X.fPrimitive); + break; + + case OPERAND_KIND_VALUE_NODE: + SetTo(X.fValueNode); + break; + + case OPERAND_KIND_TYPE: + SetTo(X.fType); + break; + } + + return *this; + } + + void SetTo(const BVariant& value) + { + Unset(); + fPrimitive = value; + fKind = OPERAND_KIND_PRIMITIVE; + } + + void SetTo(ValueNode* node) + { + Unset(); + fValueNode = node; + fValueNode->AcquireReference(); + + Value* value = node->GetValue(); + if (value != NULL) + value->ToVariant(fPrimitive); + + fKind = OPERAND_KIND_VALUE_NODE; + } + + void SetTo(Type* type) + { + Unset(); + fType = type; + fType->AcquireReference(); + + fKind = OPERAND_KIND_TYPE; + } + + void Unset() + { + if (fValueNode != NULL) + fValueNode->ReleaseReference(); + + if (fType != NULL) + fType->ReleaseReference(); + + fValueNode = NULL; + fType = NULL; + fKind = OPERAND_KIND_UNKNOWN; + } + + inline operand_kind Kind() const + { + return fKind; + } + + inline const BVariant& PrimitiveValue() const + { + return fPrimitive; + } + + inline ValueNode* GetValueNode() const + { + return fValueNode; + + } + + inline Type* GetType() const + { + return fType; + } + + Operand& operator+=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + + temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + + temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + + temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + + temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + + temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + + temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + + temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + + temp.fPrimitive.ToUInt64()); + break; + } + + case B_FLOAT_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToFloat() + + temp.fPrimitive.ToFloat()); + break; + } + + case B_DOUBLE_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToDouble() + + temp.fPrimitive.ToDouble()); + break; + } + } + + return *this; + } + + Operand& operator-=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + - temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + - temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + - temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + - temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + - temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + - temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + - temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + - temp.fPrimitive.ToUInt64()); + break; + } + + case B_FLOAT_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToFloat() + - temp.fPrimitive.ToFloat()); + break; + } + + case B_DOUBLE_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToDouble() + - temp.fPrimitive.ToDouble()); + break; + } + } + + return *this; + } + + Operand& operator/=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + / temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + / temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + / temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + / temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + / temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + / temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + / temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + / temp.fPrimitive.ToUInt64()); + break; + } + + case B_FLOAT_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToFloat() + / temp.fPrimitive.ToFloat()); + break; + } + + case B_DOUBLE_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToDouble() + / temp.fPrimitive.ToDouble()); + break; + } + } + + return *this; + } + + Operand& operator*=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + * temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + * temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + * temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + * temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + * temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + * temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + * temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + * temp.fPrimitive.ToUInt64()); + break; + } + + case B_FLOAT_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToFloat() + * temp.fPrimitive.ToFloat()); + break; + } + + case B_DOUBLE_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToDouble() + * temp.fPrimitive.ToDouble()); + break; + } + } + + return *this; + } + + Operand& operator%=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + % temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + % temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + % temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + % temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + % temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + % temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + % temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + % temp.fPrimitive.ToUInt64()); + break; + } + } + + return *this; + } + + Operand& operator&=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + & temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + & temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + & temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + & temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + & temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + & temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + & temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + & temp.fPrimitive.ToUInt64()); + break; + } + } + + return *this; + } + + Operand& operator|=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + | temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + | temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + | temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + | temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + | temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + | temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + | temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + | temp.fPrimitive.ToUInt64()); + break; + } + } + + return *this; + } + + Operand& operator^=(const Operand& rhs) + { + Operand temp = rhs; + _ResolveTypesIfNeeded(temp); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + fPrimitive.SetTo((int8)(fPrimitive.ToInt8() + ^ temp.fPrimitive.ToInt8())); + break; + } + + case B_UINT8_TYPE: + { + fPrimitive.SetTo((uint8)(fPrimitive.ToUInt8() + ^ temp.fPrimitive.ToUInt8())); + break; + } + + case B_INT16_TYPE: + { + fPrimitive.SetTo((int16)(fPrimitive.ToInt16() + ^ temp.fPrimitive.ToInt16())); + break; + } + + case B_UINT16_TYPE: + { + fPrimitive.SetTo((uint16)(fPrimitive.ToUInt16() + ^ temp.fPrimitive.ToUInt16())); + break; + } + + case B_INT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt32() + ^ temp.fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt32() + ^ temp.fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToInt64() + ^ temp.fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + fPrimitive.SetTo(fPrimitive.ToUInt64() + ^ temp.fPrimitive.ToUInt64()); + break; + } + } + + return *this; + } + + Operand operator-() const + { + Operand value(*this); + value._ResolveToPrimitive(); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + value.fPrimitive.SetTo((int8)-fPrimitive.ToInt8()); + break; + } + + case B_UINT8_TYPE: + { + value.fPrimitive.SetTo((uint8)-fPrimitive.ToUInt8()); + break; + } + + case B_INT16_TYPE: + { + value.fPrimitive.SetTo((int16)-fPrimitive.ToInt16()); + break; + } + + case B_UINT16_TYPE: + { + value.fPrimitive.SetTo((uint16)-fPrimitive.ToUInt16()); + break; + } + + case B_INT32_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToUInt64()); + break; + } + + case B_FLOAT_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToFloat()); + break; + } + + case B_DOUBLE_TYPE: + { + value.fPrimitive.SetTo(-fPrimitive.ToDouble()); + break; + } + } + + return value; + } + + Operand operator~() const + { + Operand value(*this); + value._ResolveToPrimitive(); + + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + value.fPrimitive.SetTo((int8)~fPrimitive.ToInt8()); + break; + } + + case B_UINT8_TYPE: + { + value.fPrimitive.SetTo((uint8)~fPrimitive.ToUInt8()); + break; + } + + case B_INT16_TYPE: + { + value.fPrimitive.SetTo((int16)~fPrimitive.ToInt16()); + break; + } + + case B_UINT16_TYPE: + { + value.fPrimitive.SetTo((uint16)~fPrimitive.ToUInt16()); + break; + } + + case B_INT32_TYPE: + { + value.fPrimitive.SetTo(~fPrimitive.ToInt32()); + break; + } + + case B_UINT32_TYPE: + { + value.fPrimitive.SetTo(~fPrimitive.ToUInt32()); + break; + } + + case B_INT64_TYPE: + { + value.fPrimitive.SetTo(~fPrimitive.ToInt64()); + break; + } + + case B_UINT64_TYPE: + { + value.fPrimitive.SetTo(~fPrimitive.ToUInt64()); + break; + } + } + + return value; + } + + int operator<(const Operand& rhs) const + { + Operand lhs = *this; + Operand temp = rhs; + + lhs._ResolveTypesIfNeeded(temp); + + int result = 0; + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + result = lhs.fPrimitive.ToInt8() < temp.fPrimitive.ToInt8(); + break; + } + + case B_UINT8_TYPE: + { + result = lhs.fPrimitive.ToUInt8() < temp.fPrimitive.ToUInt8(); + break; + } + + case B_INT16_TYPE: + { + result = lhs.fPrimitive.ToInt16() < temp.fPrimitive.ToInt16(); + break; + } + + case B_UINT16_TYPE: + { + result = lhs.fPrimitive.ToUInt16() + < temp.fPrimitive.ToUInt16(); + break; + } + + case B_INT32_TYPE: + { + result = lhs.fPrimitive.ToInt32() < temp.fPrimitive.ToInt32(); + break; + } + + case B_UINT32_TYPE: + { + result = lhs.fPrimitive.ToUInt32() + < temp.fPrimitive.ToUInt32(); + break; + } + + case B_INT64_TYPE: + { + result = lhs.fPrimitive.ToInt64() < temp.fPrimitive.ToInt64(); + break; + } + + case B_UINT64_TYPE: + { + result = lhs.fPrimitive.ToUInt64() + < temp.fPrimitive.ToUInt64(); + break; + } + + case B_FLOAT_TYPE: + { + result = lhs.fPrimitive.ToFloat() < temp.fPrimitive.ToFloat(); + break; + } + + case B_DOUBLE_TYPE: + { + result = lhs.fPrimitive.ToDouble() + < temp.fPrimitive.ToDouble(); + break; + } + } + + return result; + } + + int operator<=(const Operand& rhs) const + { + return (*this < rhs) || (*this == rhs); + } + + int operator>(const Operand& rhs) const + { + Operand lhs = *this; + Operand temp = rhs; + lhs._ResolveTypesIfNeeded(temp); + + int result = 0; + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + result = lhs.fPrimitive.ToInt8() > temp.fPrimitive.ToInt8(); + break; + } + + case B_UINT8_TYPE: + { + result = lhs.fPrimitive.ToUInt8() > temp.fPrimitive.ToUInt8(); + break; + } + + case B_INT16_TYPE: + { + result = lhs.fPrimitive.ToInt16() > temp.fPrimitive.ToInt16(); + break; + } + + case B_UINT16_TYPE: + { + result = lhs.fPrimitive.ToUInt16() + > temp.fPrimitive.ToUInt16(); + break; + } + + case B_INT32_TYPE: + { + result = lhs.fPrimitive.ToInt32() > temp.fPrimitive.ToInt32(); + break; + } + + case B_UINT32_TYPE: + { + result = lhs.fPrimitive.ToUInt32() + > temp.fPrimitive.ToUInt32(); + break; + } + + case B_INT64_TYPE: + { + result = lhs.fPrimitive.ToInt64() > temp.fPrimitive.ToInt64(); + break; + } + + case B_UINT64_TYPE: + { + result = lhs.fPrimitive.ToUInt64() + > temp.fPrimitive.ToUInt64(); + break; + } + + case B_FLOAT_TYPE: + { + result = lhs.fPrimitive.ToFloat() > temp.fPrimitive.ToFloat(); + break; + } + case B_DOUBLE_TYPE: + { + result = lhs.fPrimitive.ToDouble() + > temp.fPrimitive.ToDouble(); + break; + } + } -enum { - TOKEN_NONE = 0, - TOKEN_IDENTIFIER, - TOKEN_CONSTANT, - TOKEN_END_OF_LINE, + return result; + } - TOKEN_PLUS, - TOKEN_MINUS, + int operator>=(const Operand& rhs) const + { + return (*this > rhs) || (*this == rhs); + } - TOKEN_STAR, - TOKEN_SLASH, - TOKEN_MODULO, + int operator==(const Operand& rhs) const + { + Operand lhs = *this; + Operand temp = rhs; + lhs._ResolveTypesIfNeeded(temp); - TOKEN_POWER, + int result = 0; + switch (fPrimitive.Type()) { + case B_INT8_TYPE: + { + result = lhs.fPrimitive.ToInt8() == temp.fPrimitive.ToInt8(); + break; + } - TOKEN_OPENING_BRACKET, - TOKEN_CLOSING_BRACKET, + case B_UINT8_TYPE: + { + result = lhs.fPrimitive.ToUInt8() == temp.fPrimitive.ToUInt8(); + break; + } - TOKEN_LOGICAL_AND, - TOKEN_LOGICAL_OR, - TOKEN_LOGICAL_NOT, - TOKEN_BITWISE_AND, - TOKEN_BITWISE_OR, - TOKEN_BITWISE_NOT, - TOKEN_BITWISE_XOR, - TOKEN_EQ, - TOKEN_NE, - TOKEN_GT, - TOKEN_GE, - TOKEN_LT, - TOKEN_LE, + case B_INT16_TYPE: + { + result = lhs.fPrimitive.ToInt16() == temp.fPrimitive.ToInt16(); + break; + } - TOKEN_MEMBER_PTR -}; + case B_UINT16_TYPE: + { + result = lhs.fPrimitive.ToUInt16() + == temp.fPrimitive.ToUInt16(); + break; + } -static BString TokenTypeToString(int32 type) -{ - BString token; + case B_INT32_TYPE: + { + result = lhs.fPrimitive.ToInt32() == temp.fPrimitive.ToInt32(); + break; + } - switch (type) { - case TOKEN_PLUS: - token = "+"; - break; + case B_UINT32_TYPE: + { + result = lhs.fPrimitive.ToUInt32() + == temp.fPrimitive.ToUInt32(); + break; + } - case TOKEN_MINUS: - token = "-"; - break; + case B_INT64_TYPE: + { + result = lhs.fPrimitive.ToInt64() == temp.fPrimitive.ToInt64(); + break; + } - case TOKEN_STAR: - token = "*"; - break; + case B_UINT64_TYPE: + { + result = lhs.fPrimitive.ToUInt64() + == temp.fPrimitive.ToUInt64(); + break; + } - case TOKEN_SLASH: - token = "/"; - break; + case B_FLOAT_TYPE: + { + result = lhs.fPrimitive.ToFloat() == temp.fPrimitive.ToFloat(); + break; + } - case TOKEN_MODULO: - token = "%"; - break; + case B_DOUBLE_TYPE: + { + result = lhs.fPrimitive.ToDouble() + == temp.fPrimitive.ToDouble(); + break; + } + } - case TOKEN_POWER: - token = "**"; - break; + return result; + } - case TOKEN_OPENING_BRACKET: - token = "("; - break; + int operator!=(const Operand& rhs) const + { + return !(*this == rhs); + } - case TOKEN_CLOSING_BRACKET: - token = ")"; - break; +private: + void _GetAsType(type_code type) + { + switch (type) { + case B_INT8_TYPE: + fPrimitive.SetTo(fPrimitive.ToInt8()); + break; + case B_UINT8_TYPE: + fPrimitive.SetTo(fPrimitive.ToUInt8()); + break; + case B_INT16_TYPE: + fPrimitive.SetTo(fPrimitive.ToInt16()); + break; + case B_UINT16_TYPE: + fPrimitive.SetTo(fPrimitive.ToUInt16()); + break; + case B_INT32_TYPE: + fPrimitive.SetTo(fPrimitive.ToInt32()); + break; + case B_UINT32_TYPE: + fPrimitive.SetTo(fPrimitive.ToUInt32()); + break; + case B_INT64_TYPE: + fPrimitive.SetTo(fPrimitive.ToInt64()); + break; + case B_UINT64_TYPE: + fPrimitive.SetTo(fPrimitive.ToUInt64()); + break; + case B_FLOAT_TYPE: + fPrimitive.SetTo(fPrimitive.ToFloat()); + break; + case B_DOUBLE_TYPE: + fPrimitive.SetTo(fPrimitive.ToDouble()); + break; + } + } - case TOKEN_LOGICAL_AND: - token = "&&"; - break; + void _ResolveTypesIfNeeded(Operand& other) + { + _ResolveToPrimitive(); + other._ResolveToPrimitive(); - case TOKEN_LOGICAL_OR: - token = "||"; - break; + if (!fPrimitive.IsNumber() || !other.fPrimitive.IsNumber()) { + throw ParseException("Cannot perform mathematical operations " + "between non-numerical objects.", 0); + } - case TOKEN_LOGICAL_NOT: - token = "!"; - break; + type_code thisType = fPrimitive.Type(); + type_code otherType = other.fPrimitive.Type(); - case TOKEN_BITWISE_AND: - token = "&"; - break; + if (thisType == otherType) + return; - case TOKEN_BITWISE_OR: - token = "|"; - break; + type_code resolvedType = _ResolvePriorityType(thisType, otherType); + if (thisType != resolvedType) + _GetAsType(resolvedType); - case TOKEN_BITWISE_NOT: - token = "~"; - break; + if (otherType != resolvedType) + other._GetAsType(resolvedType); + } - case TOKEN_BITWISE_XOR: - token = "^"; - break; + void _ResolveToPrimitive() + { + if (Kind() == OPERAND_KIND_PRIMITIVE) + return; + else if (Kind() == OPERAND_KIND_TYPE) { + throw ParseException("Cannot perform mathematical operations " + "between type objects.", 0); + } - case TOKEN_EQ: - token = "=="; - break; + status_t error = fValueNode->LocationAndValueResolutionState(); + if (error != B_OK) { + BString errorMessage; + errorMessage.SetToFormat("Failed to resolve value of %s: %" + B_PRId32 ".", fValueNode->Name().String(), error); + throw ParseException(errorMessage.String(), 0); + } - case TOKEN_NE: - token = "!="; - break; + Value* value = fValueNode->GetValue(); + BVariant tempValue; + if (value->ToVariant(tempValue)) + SetTo(tempValue); + else { + BString error; + error.SetToFormat("Failed to retrieve value of %s.", + fValueNode->Name().String()); + throw ParseException(error.String(), 0); + } + } - case TOKEN_GT: - token = ">"; - break; + type_code _ResolvePriorityType(type_code lhs, type_code rhs) const + { + size_t byteSize = std::max(BVariant::SizeOfType(lhs), + BVariant::SizeOfType(rhs)); + bool isFloat = BVariant::TypeIsFloat(lhs) + || BVariant::TypeIsFloat(rhs); + bool isSigned = isFloat; + if (!isFloat) { + BVariant::TypeIsInteger(lhs, &isSigned); + if (!isSigned) + BVariant::TypeIsInteger(rhs, &isSigned); + } - case TOKEN_GE: - token = ">="; - break; + if (isFloat) { + if (byteSize == sizeof(float)) + return B_FLOAT_TYPE; + return B_DOUBLE_TYPE; + } - case TOKEN_LT: - token = "<"; - break; + switch (byteSize) { + case 1: + return isSigned ? B_INT8_TYPE : B_UINT8_TYPE; + case 2: + return isSigned ? B_INT16_TYPE : B_UINT16_TYPE; + case 4: + return isSigned ? B_INT32_TYPE : B_UINT32_TYPE; + case 8: + return isSigned ? B_INT64_TYPE : B_UINT64_TYPE; + default: + break; + } - case TOKEN_LE: - token = "<="; - break; + BString error; + error.SetToFormat("Unable to reconcile types %#" B_PRIx32 + " and %#" B_PRIx32, lhs, rhs); + throw ParseException(error.String(), 0); + } - case TOKEN_MEMBER_PTR: - token = "->"; - break; +private: + BVariant fPrimitive; + ValueNode* fValueNode; + Type* fType; + operand_kind fKind; +}; - default: - token.SetToFormat("Unknown token type %" B_PRId32, type); - break; - } - return token; -} +// #pragma mark - CLanguageExpressionEvaluator::Token struct CLanguageExpressionEvaluator::Token { @@ -201,20 +1464,22 @@ struct CLanguageExpressionEvaluator::Token { BString string; int32 type; - Number value; + BVariant value; int32 position; }; +// #pragma mark - CLanguageExpressionEvaluator::Tokenizer + + class CLanguageExpressionEvaluator::Tokenizer { - public: +public: Tokenizer() : fString(""), fCurrentChar(NULL), fCurrentToken(), - fReuseToken(false), - fType(B_INT32_TYPE) + fReuseToken(false) { } @@ -226,11 +1491,6 @@ class CLanguageExpressionEvaluator::Tokenizer { fReuseToken = false; } - void SetType(type_code type) - { - fType = type; - } - const Token& NextToken() { if (fCurrentToken.type == TOKEN_END_OF_LINE) @@ -252,7 +1512,7 @@ class CLanguageExpressionEvaluator::Tokenizer { if (decimal || isdigit(*fCurrentChar)) { if (*fCurrentChar == '0' && fCurrentChar[1] == 'x') - return _ParseHexNumber(); + return _ParseHexOperand(); BString temp; @@ -267,6 +1527,7 @@ class CLanguageExpressionEvaluator::Tokenizer { // optional post comma part // (required if there are no digits before the comma) if (*fCurrentChar == '.' || *fCurrentChar == ',') { + decimal = true; temp << '.'; fCurrentChar++; @@ -277,29 +1538,6 @@ class CLanguageExpressionEvaluator::Tokenizer { } } - // optional exponent part - if (*fCurrentChar == 'E') { - temp << *fCurrentChar; - fCurrentChar++; - - // optional exponent sign - if (*fCurrentChar == '+' || *fCurrentChar == '-') { - temp << *fCurrentChar; - fCurrentChar++; - } - - // required exponent digits - if (!isdigit(*fCurrentChar)) { - throw ParseException("missing exponent in constant", - fCurrentChar - begin); - } - - while (isdigit(*fCurrentChar)) { - temp << *fCurrentChar; - fCurrentChar++; - } - } - int32 length = fCurrentChar - begin; if (length == 1 && decimal) { // check for . operator @@ -324,7 +1562,13 @@ class CLanguageExpressionEvaluator::Tokenizer { fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT); - fCurrentToken.value.SetTo(fType, temp.String()); + if (decimal) + fCurrentToken.value.SetTo(value); + else { + fCurrentToken.value.SetTo((int64)strtoll(temp.String(), NULL, + 10)); + } + } else if (isalpha(*fCurrentChar)) { const char* begin = fCurrentChar; while (*fCurrentChar != 0 && (isalpha(*fCurrentChar) @@ -510,7 +1754,7 @@ class CLanguageExpressionEvaluator::Tokenizer { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } - Token& _ParseHexNumber() + Token& _ParseHexOperand() { const char* begin = fCurrentChar; fCurrentChar += 2; @@ -527,7 +1771,8 @@ class CLanguageExpressionEvaluator::Tokenizer { fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT); - fCurrentToken.value.SetTo(fType, fCurrentToken.string.String(), 16); + fCurrentToken.value.SetTo((int64)strtoull( + fCurrentToken.string.String(), NULL, 16)); return fCurrentToken; } @@ -540,14 +1785,15 @@ class CLanguageExpressionEvaluator::Tokenizer { const char* fCurrentChar; Token fCurrentToken; bool fReuseToken; - type_code fType; }; +// #pragma mark - CLanguageExpressionEvaluator + + CLanguageExpressionEvaluator::CLanguageExpressionEvaluator() : fTokenizer(new Tokenizer()), - fCurrentType(B_INT64_TYPE), fNodeManager(NULL) { } @@ -559,28 +1805,53 @@ CLanguageExpressionEvaluator::~CLanguageExpressionEvaluator() } -Number +ExpressionResult* CLanguageExpressionEvaluator::Evaluate(const char* expressionString, - type_code type, ValueNodeManager* manager) + ValueNodeManager* manager) { - fCurrentType = type; fNodeManager = manager; - fTokenizer->SetType(type); fTokenizer->SetTo(expressionString); - Number value = _ParseSum(); + Operand value = _ParseSum(); Token token = fTokenizer->NextToken(); if (token.type != TOKEN_END_OF_LINE) throw ParseException("parse error", token.position); - return value; + ExpressionResult* result = new(std::nothrow)ExpressionResult; + if (result != NULL) { + BReference<ExpressionResult> resultReference(result, true); + Value* outputValue = NULL; + BVariant primitive = value.PrimitiveValue(); + if (primitive.IsInteger()) + outputValue = new(std::nothrow) IntegerValue(primitive); + else if (primitive.IsFloat()) { + outputValue = new(std::nothrow) FloatValue( + primitive.ToDouble()); + } + + BReference<Value> valueReference; + if (outputValue != NULL) + valueReference.SetTo(outputValue, true); + + if (value.Kind() == OPERAND_KIND_PRIMITIVE) { + if (outputValue == NULL) + return NULL; + + result->SetToPrimitive(outputValue); + } else if (value.Kind() == OPERAND_KIND_VALUE_NODE) + result->SetToValueNode(value.GetValueNode()->NodeChild()); + + resultReference.Detach(); + } + + return result; } -Number +CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseSum() { - Number value = _ParseProduct(); + Operand value = _ParseProduct(); while (true) { Token token = fTokenizer->NextToken(); @@ -600,10 +1871,12 @@ CLanguageExpressionEvaluator::_ParseSum() } -Number +CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseProduct() { - Number value = _ParsePower(); + static Operand zero(int64(0LL)); + + Operand value = _ParsePower(); while (true) { Token token = fTokenizer->NextToken(); @@ -613,8 +1886,8 @@ CLanguageExpressionEvaluator::_ParseProduct() break; case TOKEN_SLASH: { - Number rhs = _ParsePower(); - if (rhs == Number(fCurrentType, 0)) + Operand rhs = _ParsePower(); + if (rhs == zero) throw ParseException("division by zero", token.position); value /= rhs; break; @@ -622,8 +1895,8 @@ CLanguageExpressionEvaluator::_ParseProduct() case TOKEN_MODULO: { - Number rhs = _ParsePower(); - if (rhs == Number()) + Operand rhs = _ParsePower(); + if (rhs == zero) throw ParseException("modulo by zero", token.position); value %= rhs; break; @@ -631,18 +1904,16 @@ CLanguageExpressionEvaluator::_ParseProduct() case TOKEN_LOGICAL_AND: { - Number zero(BVariant(0L)); - value.SetTo(BVariant((int32)((value != zero) - && (_ParsePower() != zero)))); + value.SetTo((value != zero) + && (_ParsePower() != zero)); break; } case TOKEN_LOGICAL_OR: { - Number zero(BVariant(0L)); - value.SetTo(BVariant((int32)((value != zero) - || (_ParsePower() != zero)))); + value.SetTo((value != zero) + || (_ParsePower() != zero)); break; } @@ -659,27 +1930,27 @@ CLanguageExpressionEvaluator::_ParseProduct() break; case TOKEN_EQ: - value.SetTo(BVariant((int32)(value == _ParsePower()))); + value.SetTo((int64)(value == _ParsePower())); break; case TOKEN_NE: - value.SetTo(BVariant((int32)(value != _ParsePower()))); + value.SetTo((int64)(value != _ParsePower())); break; case TOKEN_GT: - value.SetTo(BVariant((int32)(value > _ParsePower()))); + value.SetTo((int64)(value > _ParsePower())); break; case TOKEN_GE: - value.SetTo(BVariant((int32)(value >= _ParsePower()))); + value.SetTo((int64)(value >= _ParsePower())); break; case TOKEN_LT: - value.SetTo(BVariant((int32)(value < _ParsePower()))); + value.SetTo((int64)(value < _ParsePower())); break; case TOKEN_LE: - value.SetTo(BVariant((int32)(value <= _ParsePower()))); + value.SetTo((int64)(value <= _ParsePower())); break; default: @@ -690,10 +1961,10 @@ CLanguageExpressionEvaluator::_ParseProduct() } -Number +CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParsePower() { - Number value = _ParseUnary(); + Operand value = _ParseUnary(); while (true) { Token token = fTokenizer->NextToken(); @@ -702,9 +1973,9 @@ CLanguageExpressionEvaluator::_ParsePower() return value; } - Number power = _ParseUnary(); - Number temp = value; - int32 powerValue = power.GetValue().ToInt32(); + Operand power = _ParseUnary(); + Operand temp = value; + int64 powerValue = power.PrimitiveValue().ToInt64(); bool handleNegativePower = false; if (powerValue < 0) { powerValue = abs(powerValue); @@ -712,14 +1983,14 @@ CLanguageExpressionEvaluator::_ParsePower() } if (powerValue == 0) - value.SetTo(fCurrentType, "1"); + value.SetTo((int64)1); else { for (; powerValue > 1; powerValue--) value *= temp; } if (handleNegativePower) { - temp.SetTo(fCurrentType, "1"); + temp.SetTo((int64)1); temp /= value; value = temp; } @@ -727,7 +1998,7 @@ CLanguageExpressionEvaluator::_ParsePower() } -Number +CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseUnary() { Token token = fTokenizer->NextToken(); @@ -745,7 +2016,10 @@ CLanguageExpressionEvaluator::_ParseUnary() return ~_ParseUnary(); case TOKEN_LOGICAL_NOT: - return Number((int32)(_ParseUnary() == Number(BVariant(0L)))); + { + Operand zero((int64)0); + return Operand((int64)(_ParseUnary() == zero)); + } case TOKEN_IDENTIFIER: fTokenizer->RewindToken(); @@ -756,15 +2030,14 @@ CLanguageExpressionEvaluator::_ParseUnary() return _ParseAtom(); } - return Number(); + return Operand(); } -Number +CLanguageExpressionEvaluator::Operand [ *** diff truncated: 2204 lines dropped *** ] ############################################################################ Revision: hrev48361 Commit: b4a861136b9249eefc78a47528e5f4e515c633c6 URL: http://cgit.haiku-os.org/haiku/commit/?id=b4a8611 Author: Rene Gollent <rene@xxxxxxxxxxx> Date: Sat Nov 22 04:31:46 2014 UTC Debugger: Adjust VariablesView for new expression API. - Simplify handling of expression nodes. For primitive results, we now construct a Variable object that represents the expression result, and then add that as we would any other local variable. This simplifies handling, and also allows saving/restoration of their view state to be handled the same as other nodes. Complex expression results aren't yet handled properly, pending some further work in progress on the evaluator. ----------------------------------------------------------------------------