mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 16:29:55 +00:00
Allow comparison operators of arbitrary length
This commit is contained in:
parent
31ae1cd339
commit
868a398b86
3 changed files with 81 additions and 101 deletions
|
@ -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
|
||||||
|
|
|
@ -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,68 @@ 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;
|
||||||
|
std::string_view trimmedOperator = std::string_view{ op }.substr(0, end);
|
||||||
|
switch (trimmedOperator[0])
|
||||||
{
|
{
|
||||||
putback(c);
|
case '=':
|
||||||
return false;
|
special = S_cmpEQ;
|
||||||
}
|
if (trimmedOperator.size() != 2 || trimmedOperator[1] != '=')
|
||||||
}
|
mErrorHandler.warning(
|
||||||
else if (c == '!')
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as ==", loc);
|
||||||
{
|
break;
|
||||||
if (get(c))
|
case '<':
|
||||||
{
|
special = S_cmpLT;
|
||||||
/// \todo hack to allow a space in comparison operators (add option to disable)
|
if (trimmedOperator[1] == '=')
|
||||||
if (c == ' ' && !get(c))
|
{
|
||||||
return false;
|
special = S_cmpLE;
|
||||||
|
if (trimmedOperator.size() != 2)
|
||||||
if (c == '=')
|
mErrorHandler.warning(
|
||||||
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as <=", loc);
|
||||||
|
}
|
||||||
|
else if (trimmedOperator.size() != 1)
|
||||||
|
mErrorHandler.warning(
|
||||||
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as <", loc);
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
special = S_cmpGT;
|
||||||
|
if (trimmedOperator[1] == '=')
|
||||||
|
{
|
||||||
|
special = S_cmpGE;
|
||||||
|
if (trimmedOperator.size() != 2)
|
||||||
|
mErrorHandler.warning(
|
||||||
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as >=", loc);
|
||||||
|
}
|
||||||
|
else if (trimmedOperator.size() != 1)
|
||||||
|
mErrorHandler.warning(
|
||||||
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as >", loc);
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
special = S_cmpNE;
|
special = S_cmpNE;
|
||||||
else
|
if (trimmedOperator.size() != 2 || trimmedOperator[1] != '=')
|
||||||
{
|
mErrorHandler.warning(
|
||||||
putback(c);
|
"invalid operator " + std::string(trimmedOperator) + ", treating it as !=", loc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else if (c.isMinusSign())
|
else if (c.isMinusSign())
|
||||||
{
|
{
|
||||||
|
@ -503,62 +532,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…
Reference in a new issue