mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-29 19:36:43 +00:00
Issue #181: Member variable access in expressions; error reporting fix for the previous commit
This commit is contained in:
parent
6a89d76321
commit
6c5b21fa42
6 changed files with 70 additions and 11 deletions
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "../mwworld/world.hpp"
|
#include "../mwworld/world.hpp"
|
||||||
|
|
||||||
|
#include "scriptmanager.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
CompilerContext::CompilerContext (Type type)
|
CompilerContext::CompilerContext (Type type)
|
||||||
|
@ -21,6 +23,18 @@ namespace MWScript
|
||||||
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name);
|
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char CompilerContext::getMemberType (const std::string& name, const std::string& id) const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
||||||
|
|
||||||
|
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||||
|
|
||||||
|
if (script.empty())
|
||||||
|
return ' ';
|
||||||
|
|
||||||
|
return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name);
|
||||||
|
}
|
||||||
|
|
||||||
bool CompilerContext::isId (const std::string& name) const
|
bool CompilerContext::isId (const std::string& name) const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
|
@ -30,6 +30,9 @@ namespace MWScript
|
||||||
/// 'l: long, 's': short, 'f': float, ' ': does not exist.
|
/// 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||||
virtual char getGlobalType (const std::string& name) const;
|
virtual char getGlobalType (const std::string& name) const;
|
||||||
|
|
||||||
|
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||||
|
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||||
|
|
||||||
virtual bool isId (const std::string& name) const;
|
virtual bool isId (const std::string& name) const;
|
||||||
///< Does \a name match an ID, that can be referenced?
|
///< Does \a name match an ID, that can be referenced?
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace MWScript
|
||||||
catch (const Compiler::SourceException&)
|
catch (const Compiler::SourceException&)
|
||||||
{
|
{
|
||||||
// error has already been reported via error handler
|
// error has already been reported via error handler
|
||||||
|
Success = false;
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
|
@ -146,6 +147,9 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
if (!compile (name))
|
if (!compile (name))
|
||||||
{
|
{
|
||||||
|
/// \todo Handle case of cyclic member variable access. Currently this could look up
|
||||||
|
/// the whole application in an endless recursion.
|
||||||
|
|
||||||
// failed -> ignore script from now on.
|
// failed -> ignore script from now on.
|
||||||
std::vector<Interpreter::Type_Code> empty;
|
std::vector<Interpreter::Type_Code> empty;
|
||||||
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
|
||||||
|
|
|
@ -33,10 +33,12 @@ namespace Compiler
|
||||||
virtual char getGlobalType (const std::string& name) const = 0;
|
virtual char getGlobalType (const std::string& name) const = 0;
|
||||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||||
|
|
||||||
|
virtual char getMemberType (const std::string& name, const std::string& id) const = 0;
|
||||||
|
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||||
|
|
||||||
virtual bool isId (const std::string& name) const = 0;
|
virtual bool isId (const std::string& name) const = 0;
|
||||||
///< Does \a name match an ID, that can be referenced?
|
///< Does \a name match an ID, that can be referenced?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -195,10 +195,31 @@ namespace Compiler
|
||||||
return parseArguments (arguments, scanner, mCode);
|
return parseArguments (arguments, scanner, mCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExprParser::handleMemberAccess (const std::string& name)
|
||||||
|
{
|
||||||
|
mMemberOp = false;
|
||||||
|
|
||||||
|
std::string name2 = toLower (name);
|
||||||
|
std::string id = toLower (mExplicit);
|
||||||
|
|
||||||
|
char type = getContext().getMemberType (name2, id);
|
||||||
|
|
||||||
|
if (type!=' ')
|
||||||
|
{
|
||||||
|
Generator::fetchMember (mCode, mLiterals, type, name2, id);
|
||||||
|
mNextOperand = false;
|
||||||
|
mExplicit.clear();
|
||||||
|
mOperands.push_back (type=='f' ? 'f' : 'l');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ExprParser::ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
Literals& literals, bool argument)
|
Literals& literals, bool argument)
|
||||||
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
: Parser (errorHandler, context), mLocals (locals), mLiterals (literals),
|
||||||
mNextOperand (true), mFirst (true), mArgument (argument)
|
mNextOperand (true), mFirst (true), mArgument (argument), mRefOp (false), mMemberOp (false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
bool ExprParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
|
||||||
|
@ -251,7 +272,12 @@ namespace Compiler
|
||||||
Scanner& scanner)
|
Scanner& scanner)
|
||||||
{
|
{
|
||||||
if (!mExplicit.empty())
|
if (!mExplicit.empty())
|
||||||
|
{
|
||||||
|
if (mMemberOp && handleMemberAccess (name))
|
||||||
|
return true;
|
||||||
|
|
||||||
return Parser::parseName (name, loc, scanner);
|
return Parser::parseName (name, loc, scanner);
|
||||||
|
}
|
||||||
|
|
||||||
mFirst = false;
|
mFirst = false;
|
||||||
|
|
||||||
|
@ -281,7 +307,7 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mExplicit.empty() && getContext().isId (name))
|
if (mExplicit.empty() && getContext().isId (name2))
|
||||||
{
|
{
|
||||||
mExplicit = name;
|
mExplicit = name;
|
||||||
return true;
|
return true;
|
||||||
|
@ -497,6 +523,12 @@ namespace Compiler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mMemberOp && code==Scanner::S_member)
|
||||||
|
{
|
||||||
|
mMemberOp = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return Parser::parseSpecial (code, loc, scanner);
|
return Parser::parseSpecial (code, loc, scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,6 +641,7 @@ namespace Compiler
|
||||||
mFirst = true;
|
mFirst = true;
|
||||||
mExplicit.clear();
|
mExplicit.clear();
|
||||||
mRefOp = false;
|
mRefOp = false;
|
||||||
|
mMemberOp = false;
|
||||||
Parser::reset();
|
Parser::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace Compiler
|
||||||
bool mArgument;
|
bool mArgument;
|
||||||
std::string mExplicit;
|
std::string mExplicit;
|
||||||
bool mRefOp;
|
bool mRefOp;
|
||||||
|
bool mMemberOp;
|
||||||
|
|
||||||
int getPriority (char op) const;
|
int getPriority (char op) const;
|
||||||
|
|
||||||
|
@ -53,6 +54,8 @@ namespace Compiler
|
||||||
|
|
||||||
int parseArguments (const std::string& arguments, Scanner& scanner);
|
int parseArguments (const std::string& arguments, Scanner& scanner);
|
||||||
|
|
||||||
|
bool handleMemberAccess (const std::string& name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
ExprParser (ErrorHandler& errorHandler, Context& context, Locals& locals,
|
||||||
|
|
Loading…
Reference in a new issue