Fix arithmetic operations with integers ()

Also fixed unsigned right shift operator ">>>"
blender-script
melex750 2019-04-11 04:15:27 -04:00
parent a66b3d0672
commit 250ea57e8b
8 changed files with 109 additions and 55 deletions

View File

@ -129,6 +129,13 @@ bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op)
return true;
}
if (op == ID_ASR || op == ID_SR || op == ID_SL ||
op == ID_ASSOR || op == ID_ASSSL || op == ID_ASSSR ||
op == ID_ASSAND || op == ID_ASSXOR || op == ID_ASSASR)
{
if (max > CBotTypLong) return false;
}
type1.SetType(max);
type2.SetType(max);
return true;

View File

@ -103,7 +103,7 @@ static const boost::bimap<TokenId, std::string> KEYWORDS = makeBimap<TokenId, st
{ID_ASSSR, ">>>="},
{ID_ASSASR, ">>="},
{ID_SL, "<<"},
{ID_SR, ">>"},
{ID_SR, ">>>"},
{ID_ASR, ">>"},
{ID_INC, "++"},
{ID_DEC, "--"},

View File

@ -752,6 +752,11 @@ CBotClass* CBotVar::GetClass()
return nullptr;
}
CBotVar::operator bool()
{
return static_cast<bool>(GetValInt());
}
CBotVar::operator int()
{
return GetValInt();

View File

@ -444,6 +444,7 @@ public:
*/
//@{
operator bool();
operator int();
operator float();
operator std::string();

View File

@ -58,33 +58,9 @@ void CBotVarInt::Dec()
m_defnum.clear();
}
void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() ^ right->GetValInt());
}
void CBotVarInt::And(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() & right->GetValInt());
}
void CBotVarInt::Or(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() | right->GetValInt());
}
void CBotVarInt::SL(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() << right->GetValInt());
}
void CBotVarInt::ASR(CBotVar* left, CBotVar* right)
{
SetValInt(left->GetValInt() >> right->GetValInt());
}
void CBotVarInt::SR(CBotVar* left, CBotVar* right)
{
int source = left->GetValInt();
int shift = right->GetValInt();
if (shift >= 1) source &= 0x7fffffff;
SetValInt(source >> shift);
SetValInt(static_cast<unsigned>(left->GetValInt()) >> right->GetValInt());
}
void CBotVarInt::Not()

View File

@ -27,10 +27,10 @@ namespace CBot
/**
* \brief CBotVar subclass for managing integer values (::CBotTypInt)
*/
class CBotVarInt : public CBotVarNumber<int, CBotTypInt>
class CBotVarInt : public CBotVarInteger<int, CBotTypInt>
{
public:
CBotVarInt(const CBotToken &name) : CBotVarNumber(name) {}
CBotVarInt(const CBotToken &name) : CBotVarInteger(name) {}
void SetValInt(int val, const std::string& s = "") override;
std::string GetValString() override;
@ -40,19 +40,21 @@ public:
void Neg() override;
void Inc() override;
void Dec() override;
void XOr(CBotVar* left, CBotVar* right) override;
void Or(CBotVar* left, CBotVar* right) override;
void And(CBotVar* left, CBotVar* right) override;
void Not() override;
void SL(CBotVar* left, CBotVar* right) override;
void SR(CBotVar* left, CBotVar* right) override;
void ASR(CBotVar* left, CBotVar* right) override;
bool Save0State(std::ostream &ostr) override;
bool Save1State(std::ostream &ostr) override;
protected:
void SetValue(int val) override
{
CBotVarNumberBase::SetValue(val);
m_defnum.clear();
}
protected:
//! The name if given by DefineNum.
std::string m_defnum;

View File

@ -74,6 +74,13 @@ public:
return s.str();
}
protected:
virtual void SetValue(T val)
{
this->m_val = val;
this->m_binit = CBotVar::InitType::DEF;
}
protected:
//! The value
T m_val;
@ -93,14 +100,12 @@ public:
void SetValInt(int val, const std::string &s = "") override
{
this->m_val = static_cast<T>(val);
this->m_binit = CBotVar::InitType::DEF;
this->SetValue(static_cast<T>(val));
}
void SetValFloat(float val) override
{
this->m_val = static_cast<T>(val);
this->m_binit = CBotVar::InitType::DEF;
this->SetValue(static_cast<T>(val));
}
int GetValInt() override
@ -116,11 +121,11 @@ public:
bool Eq(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() == right->GetValFloat();
return static_cast<T>(*left) == static_cast<T>(*right);
}
bool Ne(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() != right->GetValFloat();
return static_cast<T>(*left) != static_cast<T>(*right);
}
};
@ -135,33 +140,33 @@ public:
void Mul(CBotVar* left, CBotVar* right) override
{
this->SetValFloat(left->GetValFloat() * right->GetValFloat());
this->SetValue(static_cast<T>(*left) * static_cast<T>(*right));
}
void Power(CBotVar* left, CBotVar* right) override
{
this->SetValFloat(pow(left->GetValFloat(), right->GetValFloat()));
this->SetValue(pow(static_cast<T>(*left), static_cast<T>(*right)));
}
CBotError Div(CBotVar* left, CBotVar* right) override
{
float r = right->GetValFloat();
if (r == 0) return CBotErrZeroDiv;
this->SetValFloat(left->GetValFloat() / r);
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(static_cast<T>(*left) / r);
return CBotNoErr;
}
CBotError Modulo(CBotVar* left, CBotVar* right) override
{
float r = right->GetValFloat();
if (r == 0) return CBotErrZeroDiv;
this->SetValFloat(fmod(left->GetValFloat(), r));
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(fmod(static_cast<T>(*left), r));
return CBotNoErr;
}
void Add(CBotVar* left, CBotVar* right) override
{
this->SetValFloat(left->GetValFloat() + right->GetValFloat());
this->SetValue(static_cast<T>(*left) + static_cast<T>(*right));
}
void Sub(CBotVar* left, CBotVar* right) override
{
this->SetValFloat(left->GetValFloat() - right->GetValFloat());
this->SetValue(static_cast<T>(*left) - static_cast<T>(*right));
}
void Neg() override
@ -179,21 +184,65 @@ public:
bool Lo(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() < right->GetValFloat();
return static_cast<T>(*left) < static_cast<T>(*right);
}
bool Hi(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() > right->GetValFloat();
return static_cast<T>(*left) > static_cast<T>(*right);
}
bool Ls(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() <= right->GetValFloat();
return static_cast<T>(*left) <= static_cast<T>(*right);
}
bool Hs(CBotVar* left, CBotVar* right) override
{
return left->GetValFloat() >= right->GetValFloat();
return static_cast<T>(*left) >= static_cast<T>(*right);
}
};
}
/**
* \brief An integer variable (byte, short, char, int, long)
*/
template <typename T, CBotType type>
class CBotVarInteger : public CBotVarNumber<T, type>
{
public:
CBotVarInteger(const CBotToken &name) : CBotVarNumber<T, type>(name) {}
CBotError Modulo(CBotVar* left, CBotVar* right) override
{
T r = static_cast<T>(*right);
if ( r == static_cast<T>(0) ) return CBotErrZeroDiv;
this->SetValue(static_cast<T>(*left) % r);
return CBotNoErr;
}
void XOr(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) ^ static_cast<T>(*right));
}
void And(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) & static_cast<T>(*right));
}
void Or(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) | static_cast<T>(*right));
}
void SL(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) << right->GetValInt());
}
void ASR(CBotVar* left, CBotVar* right) override
{
this->SetValue(static_cast<T>(*left) >> right->GetValInt());
}
void Not() override
{
this->m_val = ~(this->m_val);
}
};
} // namespace CBot

View File

@ -605,6 +605,20 @@ TEST_F(CBotUT, VarImplicitCast)
);
}
TEST_F(CBotUT, IntegerMathNearLimits_Issue993)
{
ExecuteTest(
"extern void Test_Issue993() {\n"
" ASSERT(-2147483600 * 1 == -2147483600);\n"
" ASSERT( 2147483600 * 1 == 2147483600);\n"
" ASSERT( 2147483646 * 1 == 2147483646);\n"
" ASSERT( 2147483646 * -1 == -2147483646);\n"
" ASSERT( 2147483000 * -1 == -2147483000);\n"
" ASSERT( 2147483000 * 1 == 2147483000);\n"
"}\n"
);
}
TEST_F(CBotUT, ToString)
{
ExecuteTest(