mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-17 10:21:11 +00:00
Merge branch 'operate_on_this' into 'master'
Handle incorrect comparison operators Closes #6716 See merge request OpenMW/openmw!2801
This commit is contained in:
commit
8e36d5e704
@ -23,6 +23,7 @@
|
|||||||
Bug #6645: Enemy block sounds align with animation instead of blocked hits
|
Bug #6645: Enemy block sounds align with animation instead of blocked hits
|
||||||
Bug #6657: Distant terrain tiles become black when using FWIW mod
|
Bug #6657: Distant terrain tiles become black when using FWIW mod
|
||||||
Bug #6661: Saved games that have no preview screenshot cause issues or crashes
|
Bug #6661: Saved games that have no preview screenshot cause issues or crashes
|
||||||
|
Bug #6716: mwscript comparison operator handling is too restrictive
|
||||||
Bug #6807: Ultimate Galleon is not working properly
|
Bug #6807: Ultimate Galleon is not working properly
|
||||||
Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands
|
Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands
|
||||||
Bug #6939: OpenMW-CS: ID columns are too short
|
Bug #6939: OpenMW-CS: ID columns are too short
|
||||||
|
@ -180,8 +180,8 @@ End)mwscript";
|
|||||||
short a
|
short a
|
||||||
short b
|
short b
|
||||||
short eq
|
short eq
|
||||||
short gte
|
short gt
|
||||||
short lte
|
short lt
|
||||||
short ne
|
short ne
|
||||||
|
|
||||||
set eq to 0
|
set eq to 0
|
||||||
@ -192,20 +192,20 @@ if ( a = = b )
|
|||||||
set eq to ( eq + 1 )
|
set eq to ( eq + 1 )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
set gte to 0
|
set gt to 0
|
||||||
if ( a >= b )
|
if ( a > b )
|
||||||
set gte to ( gte + 1 )
|
set gt to ( gt + 1 )
|
||||||
endif
|
endif
|
||||||
if ( a > = b )
|
if ( a > = b )
|
||||||
set gte to ( gte + 1 )
|
set gt to ( gt + 1 )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
set lte to 0
|
set lt to 0
|
||||||
if ( a <= b )
|
if ( a < b )
|
||||||
set lte to ( lte + 1 )
|
set lt to ( lt + 1 )
|
||||||
endif
|
endif
|
||||||
if ( a < = b )
|
if ( a < = b )
|
||||||
set lte to ( lte + 1 )
|
set lt to ( lt + 1 )
|
||||||
endif
|
endif
|
||||||
|
|
||||||
set ne to 0
|
set ne to 0
|
||||||
@ -627,8 +627,8 @@ End)mwscript";
|
|||||||
context.setLocalShort(1, b);
|
context.setLocalShort(1, b);
|
||||||
run(*script, context);
|
run(*script, context);
|
||||||
EXPECT_EQ(context.getLocalShort(2), a == b ? 2 : 0);
|
EXPECT_EQ(context.getLocalShort(2), a == b ? 2 : 0);
|
||||||
EXPECT_EQ(context.getLocalShort(3), a >= b ? 2 : 0);
|
EXPECT_EQ(context.getLocalShort(3), a > b ? 2 : 0);
|
||||||
EXPECT_EQ(context.getLocalShort(4), a <= b ? 2 : 0);
|
EXPECT_EQ(context.getLocalShort(4), a < b ? 2 : 0);
|
||||||
EXPECT_EQ(context.getLocalShort(5), a != b ? 2 : 0);
|
EXPECT_EQ(context.getLocalShort(5), a != b ? 2 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,19 @@
|
|||||||
|
|
||||||
#include <components/misc/strings/lower.hpp>
|
#include <components/misc/strings/lower.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool startsComparisonOperator(const Compiler::MultiChar& c)
|
||||||
|
{
|
||||||
|
return c == '=' || c == '<' || c == '>' || c == '!';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validComparisonOperatorCharacter(const Compiler::MultiChar& c)
|
||||||
|
{
|
||||||
|
return startsComparisonOperator(c) || c == ' ' || c == '\t';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
bool Scanner::get(MultiChar& c)
|
bool Scanner::get(MultiChar& c)
|
||||||
@ -440,52 +453,61 @@ namespace Compiler
|
|||||||
|
|
||||||
special = S_member;
|
special = S_member;
|
||||||
}
|
}
|
||||||
else if (c == '=')
|
else if (startsComparisonOperator(c))
|
||||||
{
|
{
|
||||||
if (get(c))
|
TokenLoc loc = mLoc;
|
||||||
|
std::string op;
|
||||||
|
c.appendTo(op);
|
||||||
|
while (get(c))
|
||||||
{
|
{
|
||||||
/// \todo hack to allow a space in comparison operators (add option to disable)
|
if (validComparisonOperatorCharacter(c))
|
||||||
if (c == ' ' && !get(c))
|
c.appendTo(op);
|
||||||
special = S_cmpEQ;
|
|
||||||
else if (c == '=')
|
|
||||||
special = S_cmpEQ;
|
|
||||||
else if (c == '>' || c == '<') // Treat => and =< as ==
|
|
||||||
{
|
|
||||||
special = S_cmpEQ;
|
|
||||||
mErrorHandler.warning(std::string("invalid operator =") + c.data() + ", treating it as ==", mLoc);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
special = S_cmpEQ;
|
|
||||||
putback(c);
|
putback(c);
|
||||||
// return false;
|
break;
|
||||||
/// Allow = as synonym for ==. \todo optionally disable for post-1.0 scripting improvements.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
size_t end = op.size();
|
||||||
|
while (end > 0 && (op[end - 1] == '\t' || op[end - 1] == ' '))
|
||||||
|
--end;
|
||||||
|
switch (op[0])
|
||||||
{
|
{
|
||||||
putback(c);
|
case '=':
|
||||||
return false;
|
special = S_cmpEQ;
|
||||||
}
|
if (end != 2 || op[1] != '=')
|
||||||
}
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as ==", loc);
|
||||||
else if (c == '!')
|
break;
|
||||||
{
|
case '<':
|
||||||
if (get(c))
|
special = S_cmpLT;
|
||||||
{
|
if (op[1] == '=')
|
||||||
/// \todo hack to allow a space in comparison operators (add option to disable)
|
{
|
||||||
if (c == ' ' && !get(c))
|
special = S_cmpLE;
|
||||||
return false;
|
if (end != 2)
|
||||||
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as <=", loc);
|
||||||
if (c == '=')
|
}
|
||||||
|
else if (end != 1)
|
||||||
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as <", loc);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
special = S_cmpGT;
|
||||||
|
if (op[1] == '=')
|
||||||
|
{
|
||||||
|
special = S_cmpGE;
|
||||||
|
if (end != 2)
|
||||||
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as >=", loc);
|
||||||
|
}
|
||||||
|
else if (end != 1)
|
||||||
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as >", loc);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
special = S_cmpNE;
|
special = S_cmpNE;
|
||||||
else
|
if (end != 2 || op[1] != '=')
|
||||||
{
|
mErrorHandler.warning("invalid operator " + op.substr(0, end) + ", treating it as !=", loc);
|
||||||
putback(c);
|
break;
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else if (c.isMinusSign())
|
else if (c.isMinusSign())
|
||||||
{
|
{
|
||||||
@ -503,62 +525,6 @@ namespace Compiler
|
|||||||
else
|
else
|
||||||
special = S_minus;
|
special = S_minus;
|
||||||
}
|
}
|
||||||
else if (c == '<')
|
|
||||||
{
|
|
||||||
if (get(c))
|
|
||||||
{
|
|
||||||
/// \todo hack to allow a space in comparison operators (add option to disable)
|
|
||||||
if (c == ' ' && !get(c))
|
|
||||||
special = S_cmpLT;
|
|
||||||
else if (c == '=')
|
|
||||||
{
|
|
||||||
special = S_cmpLE;
|
|
||||||
|
|
||||||
if (get(c) && c != '=') // <== is a allowed as an alternative to <= :(
|
|
||||||
putback(c);
|
|
||||||
}
|
|
||||||
else if (c == '<' || c == '>') // Treat <> and << as <
|
|
||||||
{
|
|
||||||
special = S_cmpLT;
|
|
||||||
mErrorHandler.warning("Invalid operator, treating it as <", mLoc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
putback(c);
|
|
||||||
special = S_cmpLT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
special = S_cmpLT;
|
|
||||||
}
|
|
||||||
else if (c == '>')
|
|
||||||
{
|
|
||||||
if (get(c))
|
|
||||||
{
|
|
||||||
/// \todo hack to allow a space in comparison operators (add option to disable)
|
|
||||||
if (c == ' ' && !get(c))
|
|
||||||
special = S_cmpGT;
|
|
||||||
else if (c == '=')
|
|
||||||
{
|
|
||||||
special = S_cmpGE;
|
|
||||||
|
|
||||||
if (get(c) && c != '=') // >== is a allowed as an alternative to >= :(
|
|
||||||
putback(c);
|
|
||||||
}
|
|
||||||
else if (c == '<' || c == '>') // Treat >< and >> as >
|
|
||||||
{
|
|
||||||
special = S_cmpGT;
|
|
||||||
mErrorHandler.warning("Invalid operator, treating it as >", mLoc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
putback(c);
|
|
||||||
special = S_cmpGT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
special = S_cmpGT;
|
|
||||||
}
|
|
||||||
else if (c == '+')
|
else if (c == '+')
|
||||||
special = S_plus;
|
special = S_plus;
|
||||||
else if (c == '*')
|
else if (c == '*')
|
||||||
|
@ -48,25 +48,31 @@ namespace Compiler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const char ch) { return mData[0] == ch && mData[1] == 0 && mData[2] == 0 && mData[3] == 0; }
|
bool operator==(const char ch) const
|
||||||
|
{
|
||||||
|
return mData[0] == ch && mData[1] == 0 && mData[2] == 0 && mData[3] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const MultiChar& ch)
|
bool operator==(const MultiChar& ch) const
|
||||||
{
|
{
|
||||||
return mData[0] == ch.mData[0] && mData[1] == ch.mData[1] && mData[2] == ch.mData[2]
|
return mData[0] == ch.mData[0] && mData[1] == ch.mData[1] && mData[2] == ch.mData[2]
|
||||||
&& mData[3] == ch.mData[3];
|
&& mData[3] == ch.mData[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const char ch) { return mData[0] != ch || mData[1] != 0 || mData[2] != 0 || mData[3] != 0; }
|
bool operator!=(const char ch) const
|
||||||
|
{
|
||||||
|
return mData[0] != ch || mData[1] != 0 || mData[2] != 0 || mData[3] != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool isWhitespace()
|
bool isWhitespace() const
|
||||||
{
|
{
|
||||||
return (mData[0] == ' ' || mData[0] == '\t' || mData[0] == ',') && mData[1] == 0 && mData[2] == 0
|
return (mData[0] == ' ' || mData[0] == '\t' || mData[0] == ',') && mData[1] == 0 && mData[2] == 0
|
||||||
&& mData[3] == 0;
|
&& mData[3] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDigit() { return std::isdigit(mData[0]) && mData[1] == 0 && mData[2] == 0 && mData[3] == 0; }
|
bool isDigit() const { return std::isdigit(mData[0]) && mData[1] == 0 && mData[2] == 0 && mData[3] == 0; }
|
||||||
|
|
||||||
bool isMinusSign()
|
bool isMinusSign() const
|
||||||
{
|
{
|
||||||
if (mData[0] == '-' && mData[1] == 0 && mData[2] == 0 && mData[3] == 0)
|
if (mData[0] == '-' && mData[1] == 0 && mData[2] == 0 && mData[3] == 0)
|
||||||
return true;
|
return true;
|
||||||
@ -74,7 +80,7 @@ namespace Compiler
|
|||||||
return mData[0] == '\xe2' && mData[1] == '\x80' && mData[2] == '\x93' && mData[3] == 0;
|
return mData[0] == '\xe2' && mData[1] == '\x80' && mData[2] == '\x93' && mData[3] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAlpha()
|
bool isAlpha() const
|
||||||
{
|
{
|
||||||
if (isMinusSign())
|
if (isMinusSign())
|
||||||
return false;
|
return false;
|
||||||
@ -82,13 +88,13 @@ namespace Compiler
|
|||||||
return std::isalpha(mData[0]) || mData[1] != 0 || mData[2] != 0 || mData[3] != 0;
|
return std::isalpha(mData[0]) || mData[1] != 0 || mData[2] != 0 || mData[3] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendTo(std::string& str)
|
void appendTo(std::string& str) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i <= mLength; i++)
|
for (int i = 0; i <= mLength; i++)
|
||||||
str += mData[i];
|
str += mData[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void putback(std::istream& in)
|
void putback(std::istream& in) const
|
||||||
{
|
{
|
||||||
for (int i = mLength; i >= 0; i--)
|
for (int i = mLength; i >= 0; i--)
|
||||||
in.putback(mData[i]);
|
in.putback(mData[i]);
|
||||||
@ -157,7 +163,7 @@ namespace Compiler
|
|||||||
mLength = -1;
|
mLength = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string data()
|
std::string data() const
|
||||||
{
|
{
|
||||||
// NB: mLength is the number of the last element in the array
|
// NB: mLength is the number of the last element in the array
|
||||||
return std::string(mData, mLength + 1);
|
return std::string(mData, mLength + 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user