/* * Copyright 2006-2014 Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Stephan Aßmus * Rene Gollent * John Scipione * Ingo Weinhold */ #include "CLanguageExpressionEvaluator.h" #include #include "AutoLocker.h" #include "CLanguageTokenizer.h" #include "ExpressionInfo.h" #include "FloatValue.h" #include "IntegerFormatter.h" #include "IntegerValue.h" #include "ObjectID.h" #include "StackFrame.h" #include "SyntheticPrimitiveType.h" #include "TeamTypeInformation.h" #include "Thread.h" #include "Type.h" #include "TypeHandlerRoster.h" #include "TypeLookupConstraints.h" #include "Value.h" #include "ValueLocation.h" #include "ValueNode.h" #include "ValueNodeManager.h" #include "Variable.h" #include "VariableValueNodeChild.h" using namespace CLanguage; 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_OPENING_PAREN: token = "("; break; case TOKEN_CLOSING_PAREN: 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::InternalVariableID class CLanguageExpressionEvaluator::InternalVariableID : public ObjectID { public: InternalVariableID(const BVariant& value) : fValue(value) { } virtual ~InternalVariableID() { } virtual bool operator==(const ObjectID& other) const { const InternalVariableID* otherID = dynamic_cast(&other); if (otherID == NULL) return false; return fValue == otherID->fValue; } protected: virtual uint32 ComputeHashValue() const { return *(uint32*)(&fValue); } private: BVariant fValue; }; // #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; } } 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; } } return result; } int operator!=(const Operand& rhs) const { return !(*this == rhs); } 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; } } void _ResolveTypesIfNeeded(Operand& other) { _ResolveToPrimitive(); other._ResolveToPrimitive(); if (!fPrimitive.IsNumber() || !other.fPrimitive.IsNumber()) { throw ParseException("Cannot perform mathematical operations " "between non-numerical objects.", 0); } type_code thisType = fPrimitive.Type(); type_code otherType = other.fPrimitive.Type(); if (thisType == otherType) return; type_code resolvedType = _ResolvePriorityType(thisType, otherType); if (thisType != resolvedType) _GetAsType(resolvedType); if (otherType != resolvedType) other._GetAsType(resolvedType); } void _ResolveToPrimitive() { if (Kind() == OPERAND_KIND_PRIMITIVE) return; else if (Kind() == OPERAND_KIND_TYPE) { throw ParseException("Cannot perform mathematical operations " "between type objects.", 0); } 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); } 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); } } 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); } if (isFloat) { if (byteSize == sizeof(float)) return B_FLOAT_TYPE; return B_DOUBLE_TYPE; } 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; } BString error; error.SetToFormat("Unable to reconcile types %#" B_PRIx32 " and %#" B_PRIx32, lhs, rhs); throw ParseException(error.String(), 0); } private: BVariant fPrimitive; ValueNode* fValueNode; Type* fType; operand_kind fKind; }; // #pragma mark - CLanguageExpressionEvaluator CLanguageExpressionEvaluator::CLanguageExpressionEvaluator() : fTokenizer(new Tokenizer()), fTypeInfo(NULL), fNodeManager(NULL) { } CLanguageExpressionEvaluator::~CLanguageExpressionEvaluator() { delete fTokenizer; } ExpressionResult* CLanguageExpressionEvaluator::Evaluate(const char* expressionString, ValueNodeManager* manager, TeamTypeInformation* info) { fNodeManager = manager; fTypeInfo = info; fTokenizer->SetTo(expressionString); Operand value = _ParseSum(); Token token = fTokenizer->NextToken(); if (token.type != TOKEN_END_OF_LINE) throw ParseException("parse error", token.position); ExpressionResult* result = new(std::nothrow)ExpressionResult; if (result != NULL) { BReference resultReference(result, true); if (value.Kind() == OPERAND_KIND_PRIMITIVE) { 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 valueReference; if (outputValue != NULL) { valueReference.SetTo(outputValue, true); result->SetToPrimitive(outputValue); } else return NULL; } else if (value.Kind() == OPERAND_KIND_VALUE_NODE) result->SetToValueNode(value.GetValueNode()->NodeChild()); else if (value.Kind() == OPERAND_KIND_TYPE) result->SetToType(value.GetType()); resultReference.Detach(); } return result; } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseSum() { Operand value = _ParseProduct(); while (true) { Token token = fTokenizer->NextToken(); switch (token.type) { case TOKEN_PLUS: value += _ParseProduct(); break; case TOKEN_MINUS: value -= _ParseProduct(); break; default: fTokenizer->RewindToken(); return value; } } } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseProduct() { static Operand zero(int64(0LL)); Operand value = _ParseUnary(); while (true) { Token token = fTokenizer->NextToken(); switch (token.type) { case TOKEN_STAR: value *= _ParseUnary(); break; case TOKEN_SLASH: { Operand rhs = _ParseUnary(); if (rhs == zero) throw ParseException("division by zero", token.position); value /= rhs; break; } case TOKEN_MODULO: { Operand rhs = _ParseUnary(); if (rhs == zero) throw ParseException("modulo by zero", token.position); value %= rhs; break; } case TOKEN_LOGICAL_AND: { value.SetTo((value != zero) && (_ParseUnary() != zero)); break; } case TOKEN_LOGICAL_OR: { value.SetTo((value != zero) || (_ParseUnary() != zero)); break; } case TOKEN_BITWISE_AND: value &= _ParseUnary(); break; case TOKEN_BITWISE_OR: value |= _ParseUnary(); break; case TOKEN_BITWISE_XOR: value ^= _ParseUnary(); break; case TOKEN_EQ: value.SetTo((int64)(value == _ParseUnary())); break; case TOKEN_NE: value.SetTo((int64)(value != _ParseUnary())); break; case TOKEN_GT: value.SetTo((int64)(value > _ParseUnary())); break; case TOKEN_GE: value.SetTo((int64)(value >= _ParseUnary())); break; case TOKEN_LT: value.SetTo((int64)(value < _ParseUnary())); break; case TOKEN_LE: value.SetTo((int64)(value <= _ParseUnary())); break; default: fTokenizer->RewindToken(); return value; } } } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseUnary() { Token token = fTokenizer->NextToken(); if (token.type == TOKEN_END_OF_LINE) throw ParseException("unexpected end of expression", token.position); switch (token.type) { case TOKEN_PLUS: return _ParseUnary(); case TOKEN_MINUS: return -_ParseUnary(); case TOKEN_BITWISE_NOT: return ~_ParseUnary(); case TOKEN_LOGICAL_NOT: { Operand zero((int64)0); return Operand((int64)(_ParseUnary() == zero)); } case TOKEN_IDENTIFIER: fTokenizer->RewindToken(); return _ParseIdentifier(); default: fTokenizer->RewindToken(); return _ParseAtom(); } return Operand(); } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseIdentifier(ValueNode* parentNode) { Token token = fTokenizer->NextToken(); const BString& identifierName = token.string; ValueNodeChild* child = NULL; if (fNodeManager != NULL) { ValueNodeContainer* container = fNodeManager->GetContainer(); AutoLocker containerLocker(container); if (parentNode == NULL) { ValueNodeChild* thisChild = NULL; for (int32 i = 0; i < container->CountChildren(); i++) { ValueNodeChild* current = container->ChildAt(i); const BString& nodeName = current->Name(); if (nodeName == identifierName) { child = current; break; } else if (nodeName == "this") thisChild = current; } if (child == NULL && thisChild != NULL) { // the name was not found in the variables or parameters, // but we have a class pointer. Try to find the name in the // list of members. _RequestValueIfNeeded(token, thisChild); ValueNode* thisNode = thisChild->Node(); fTokenizer->RewindToken(); return _ParseIdentifier(thisNode); } } else { // skip intermediate address nodes if (parentNode->GetType()->Kind() == TYPE_ADDRESS && parentNode->CountChildren() == 1) { child = parentNode->ChildAt(0); _RequestValueIfNeeded(token, child); parentNode = child->Node(); fTokenizer->RewindToken(); return _ParseIdentifier(parentNode); } for (int32 i = 0; i < parentNode->CountChildren(); i++) { ValueNodeChild* current = parentNode->ChildAt(i); const BString& nodeName = current->Name(); if (nodeName == identifierName) { child = current; break; } } } } if (child == NULL && fTypeInfo != NULL) { Type* resultType = NULL; status_t error = fTypeInfo->LookupTypeByName(identifierName, TypeLookupConstraints(), resultType); if (error == B_OK) { BReference typeReference(resultType, true); return _ParseType(resultType); } else if (error != B_ENTRY_NOT_FOUND) { BString errorMessage; errorMessage.SetToFormat("Failed to look up type name '%s': %" B_PRId32 ".", identifierName.String(), error); throw ParseException(errorMessage.String(), token.position); } } BString errorMessage; if (child == NULL) { errorMessage.SetToFormat("Unable to resolve variable name: '%s'", identifierName.String()); throw ParseException(errorMessage, token.position); } _RequestValueIfNeeded(token, child); ValueNode* node = child->Node(); token = fTokenizer->NextToken(); if (token.type == TOKEN_MEMBER_PTR) { token = fTokenizer->NextToken(); if (token.type == TOKEN_IDENTIFIER) { fTokenizer->RewindToken(); return _ParseIdentifier(node); } else { throw ParseException("Expected identifier after member " "dereference.", token.position); } } else fTokenizer->RewindToken(); return Operand(node); } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseAtom() { Token token = fTokenizer->NextToken(); if (token.type == TOKEN_END_OF_LINE) throw ParseException("Unexpected end of expression", token.position); Operand value; if (token.type == TOKEN_CONSTANT) value.SetTo(token.value); else { fTokenizer->RewindToken(); _EatToken(TOKEN_OPENING_PAREN); value = _ParseSum(); _EatToken(TOKEN_CLOSING_PAREN); } if (value.Kind() == OPERAND_KIND_TYPE) { token = fTokenizer->NextToken(); if (token.type == TOKEN_END_OF_LINE) return value; Type* castType = value.GetType(); // if our evaluated result was a type, and there still remain // further tokens to evaluate, then this is a typecast for // a subsequent expression. Attempt to evaluate it, and then // apply the cast to the result. fTokenizer->RewindToken(); value = _ParseSum(); ValueNodeChild* child = NULL; if (value.Kind() != OPERAND_KIND_PRIMITIVE && value.Kind() != OPERAND_KIND_VALUE_NODE) { throw ParseException("Expected value or variable expression after" " typecast.", token.position); } if (value.Kind() == OPERAND_KIND_VALUE_NODE) child = value.GetValueNode()->NodeChild(); else if (value.Kind() == OPERAND_KIND_PRIMITIVE) _GetNodeChildForPrimitive(token, value.PrimitiveValue(), child); ValueNode* newNode = NULL; status_t error = TypeHandlerRoster::Default()->CreateValueNode(child, castType, NULL, newNode); if (error != B_OK) { throw ParseException("Unable to create value node for typecast" " operation.", token.position); } child->SetNode(newNode); value.SetTo(newNode); } return value; } void CLanguageExpressionEvaluator::_EatToken(int32 type) { Token token = fTokenizer->NextToken(); if (token.type != type) { BString expected; switch (type) { case TOKEN_IDENTIFIER: expected = "an identifier"; break; case TOKEN_CONSTANT: expected = "a constant"; break; case TOKEN_SLASH: expected = "'/', '\\', or ':'"; break; case TOKEN_END_OF_LINE: expected = "'\\n'"; break; default: expected << "'" << TokenTypeToString(type) << "'"; break; } BString temp; temp << "Expected " << expected.String() << " got '" << token.string << "'"; throw ParseException(temp.String(), token.position); } } CLanguageExpressionEvaluator::Operand CLanguageExpressionEvaluator::_ParseType(Type* baseType) { BReference typeReference; Type* finalType = baseType; bool arraySpecifierEncountered = false; status_t error; for (;;) { Token token = fTokenizer->NextToken(); if (token.type == TOKEN_STAR || token.type == TOKEN_BITWISE_AND) { if (arraySpecifierEncountered) break; address_type_kind addressKind = (token.type == TOKEN_STAR) ? DERIVED_TYPE_POINTER : DERIVED_TYPE_REFERENCE; AddressType* derivedType = NULL; error = finalType->CreateDerivedAddressType(addressKind, derivedType); if (error != B_OK) { BString errorMessage; errorMessage.SetToFormat("Failed to create derived address" " type %d for base type %s: %s (%" B_PRId32 ")", addressKind, finalType->Name().String(), strerror(error), error); throw ParseException(errorMessage, token.position); } finalType = derivedType; typeReference.SetTo(finalType, true); } else if (token.type == TOKEN_OPENING_SQUARE_BRACKET) { Operand indexSize = _ParseSum(); if (indexSize.Kind() == OPERAND_KIND_TYPE) { throw ParseException("Cannot specify type name as array" " subscript.", token.position); } _EatToken(TOKEN_CLOSING_SQUARE_BRACKET); uint32 resolvedSize = indexSize.PrimitiveValue().ToUInt32(); if (resolvedSize == 0) { throw ParseException("Non-zero array size required in type" " specifier.", token.position); } ArrayType* derivedType = NULL; error = finalType->CreateDerivedArrayType(0, resolvedSize, true, derivedType); if (error != B_OK) { BString errorMessage; errorMessage.SetToFormat("Failed to create derived array type" " of size %" B_PRIu32 " for base type %s: %s (%" B_PRId32 ")", resolvedSize, finalType->Name().String(), strerror(error), error); throw ParseException(errorMessage, token.position); } arraySpecifierEncountered = true; finalType = derivedType; typeReference.SetTo(finalType, true); } else break; } typeReference.Detach(); fTokenizer->RewindToken(); return Operand(finalType); } void CLanguageExpressionEvaluator::_RequestValueIfNeeded( const Token& token, ValueNodeChild* child) { status_t state; BString errorMessage; if (child->Node() == NULL) { state = fNodeManager->AddChildNodes(child); if (state != B_OK) { errorMessage.SetToFormat("Unable to add children for node '%s': " "%s", child->Name().String(), strerror(state)); throw ParseException(errorMessage, token.position); } } state = child->LocationResolutionState(); if (state == VALUE_NODE_UNRESOLVED) throw ValueNeededException(child->Node()); else if (state != B_OK) { errorMessage.SetToFormat("Unable to resolve variable value for '%s': " "%s", child->Name().String(), strerror(state)); throw ParseException(errorMessage, token.position); } ValueNode* node = child->Node(); state = node->LocationAndValueResolutionState(); if (state == VALUE_NODE_UNRESOLVED) throw ValueNeededException(child->Node()); else if (state != B_OK) { errorMessage.SetToFormat("Unable to resolve variable value for '%s': " "%s", child->Name().String(), strerror(state)); throw ParseException(errorMessage, token.position); } } void CLanguageExpressionEvaluator::_GetNodeChildForPrimitive(const Token& token, const BVariant& value, ValueNodeChild*& _output) const { Type* type = new(std::nothrow) SyntheticPrimitiveType(value.Type()); if (type == NULL) { throw ParseException("Out of memory while creating type object.", token.position); } BReference typeReference(type, true); ValueLocation* location = new(std::nothrow) ValueLocation(); if (location == NULL) { throw ParseException("Out of memory while creating location object.", token.position); } BReference locationReference(location, true); ValuePieceLocation piece; if (!piece.SetToValue(value.Bytes(), value.Size()) || !location->AddPiece(piece)) { throw ParseException("Out of memory populating location" " object.", token.position); } char variableName[32]; if (!IntegerFormatter::FormatValue(value, INTEGER_FORMAT_HEX_DEFAULT, variableName, sizeof(variableName))) { throw ParseException("Failed to generate internal variable name.", token.position); } InternalVariableID* id = new(std::nothrow) InternalVariableID(value); if (id == NULL) { throw ParseException("Out of memory while creating ID object.", token.position); } BReference idReference(id, true); Variable* variable = new(std::nothrow) Variable(id, variableName, type, location); if (variable == NULL) { throw ParseException("Out of memory while creating variable object.", token.position); } BReference variableReference(variable, true); _output = new(std::nothrow) VariableValueNodeChild( variable); if (_output == NULL) { throw ParseException("Out of memory while creating node child object.", token.position); } }