mirror of https://github.com/OpenMW/openmw.git
commit
6ac64bbe15
@ -0,0 +1,103 @@
|
||||
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
#include <components/compiler/tokenloc.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/fileparser.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
|
||||
Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error ";
|
||||
else
|
||||
stream << "warning ";
|
||||
|
||||
stream
|
||||
<< "script " << mFile
|
||||
<< ", line " << loc.mLine << ", column " << loc.mColumn
|
||||
<< " (" << loc.mLiteral << "): " << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error: ";
|
||||
else
|
||||
stream << "warning: ";
|
||||
|
||||
stream << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
|
||||
: mData (data), mContext (data), mMessages (0)
|
||||
{
|
||||
/// \todo add an option to configure warning mode
|
||||
setWarningsMode (0);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
mContext.setExtensions (&mExtensions);
|
||||
}
|
||||
|
||||
int CSMTools::ScriptCheckStage::setup()
|
||||
{
|
||||
mContext.clear();
|
||||
mMessages = 0;
|
||||
mId.clear();
|
||||
|
||||
return mData.getScripts().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mMessages = &messages;
|
||||
mId = mData.getScripts().getId (stage);
|
||||
|
||||
try
|
||||
{
|
||||
mFile = mData.getScripts().getRecord (stage).get().mId;
|
||||
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
|
||||
|
||||
Compiler::Scanner scanner (*this, input, mContext.getExtensions());
|
||||
|
||||
Compiler::FileParser parser (*this, mContext);
|
||||
|
||||
scanner.scan (parser);
|
||||
}
|
||||
catch (const Compiler::SourceException&)
|
||||
{
|
||||
// error has already been reported via error handler
|
||||
}
|
||||
catch (const std::exception& error)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|Critical compile error: " << error.what();
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
mMessages = 0;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
#ifndef CSM_TOOLS_SCRIPTCHECK_H
|
||||
#define CSM_TOOLS_SCRIPTCHECK_H
|
||||
|
||||
#include <components/compiler/errorhandler.hpp>
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
#include "../world/scriptcontext.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that scripts compile
|
||||
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
|
||||
{
|
||||
const CSMWorld::Data& mData;
|
||||
Compiler::Extensions mExtensions;
|
||||
CSMWorld::ScriptContext mContext;
|
||||
std::string mId;
|
||||
std::string mFile;
|
||||
std::vector<std::string> *mMessages;
|
||||
|
||||
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
|
||||
///< Report error to the user.
|
||||
|
||||
virtual void report (const std::string& message, Type type);
|
||||
///< Report a file related error
|
||||
|
||||
public:
|
||||
|
||||
ScriptCheckStage (const CSMWorld::Data& data);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,83 @@
|
||||
|
||||
#include "declarationparser.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "scanner.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "skipparser.hpp"
|
||||
#include "locals.hpp"
|
||||
|
||||
Compiler::DeclarationParser::DeclarationParser (ErrorHandler& errorHandler, const Context& context,
|
||||
Locals& locals)
|
||||
: Parser (errorHandler, context), mLocals (locals), mState (State_Begin), mType (0)
|
||||
{}
|
||||
|
||||
bool Compiler::DeclarationParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==State_Name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
char type = mLocals.getType (name2);
|
||||
|
||||
if (type!=' ')
|
||||
{
|
||||
/// \todo add option to make re-declared local variables an error
|
||||
getErrorHandler().warning ("can't re-declare local variable (ignoring declaration)",
|
||||
loc);
|
||||
|
||||
mState = State_End;
|
||||
return true;
|
||||
}
|
||||
|
||||
mLocals.declare (mType, name2);
|
||||
|
||||
mState = State_End;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Parser::parseName (name, loc, scanner);
|
||||
}
|
||||
|
||||
bool Compiler::DeclarationParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (mState==State_Begin)
|
||||
{
|
||||
switch (keyword)
|
||||
{
|
||||
case Scanner::K_short: mType = 's'; break;
|
||||
case Scanner::K_long: mType = 'l'; break;
|
||||
case Scanner::K_float: mType = 'f'; break;
|
||||
default: mType = 0;
|
||||
}
|
||||
|
||||
if (mType)
|
||||
{
|
||||
mState = State_Name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (mState==State_Name)
|
||||
{
|
||||
// allow keywords to be used as local variable names. MW script compiler, you suck!
|
||||
/// \todo option to disable this atrocity.
|
||||
return parseName (loc.mLiteral, loc, scanner);
|
||||
}
|
||||
|
||||
return Parser::parseKeyword (keyword, loc, scanner);
|
||||
}
|
||||
|
||||
bool Compiler::DeclarationParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code==Scanner::S_newline && mState==State_End)
|
||||
return false;
|
||||
|
||||
return Parser::parseSpecial (code, loc, scanner);
|
||||
}
|
||||
|
||||
void Compiler::DeclarationParser::reset()
|
||||
{
|
||||
mState = State_Begin;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
#ifndef COMPILER_DECLARATIONPARSER_H_INCLUDED
|
||||
#define COMPILER_DECLARATIONPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
class DeclarationParser : public Parser
|
||||
{
|
||||
enum State
|
||||
{
|
||||
State_Begin, State_Name, State_End
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
State mState;
|
||||
char mType;
|
||||
|
||||
public:
|
||||
|
||||
DeclarationParser (ErrorHandler& errorHandler, const Context& context, Locals& locals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
void reset();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,52 @@
|
||||
|
||||
#include "quickfileparser.hpp"
|
||||
|
||||
#include "skipparser.hpp"
|
||||
#include "scanner.hpp"
|
||||
|
||||
Compiler::QuickFileParser::QuickFileParser (ErrorHandler& errorHandler, const Context& context,
|
||||
Locals& locals)
|
||||
: Parser (errorHandler, context), mDeclarationParser (errorHandler, context, locals)
|
||||
{}
|
||||
|
||||
bool Compiler::QuickFileParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::QuickFileParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (keyword==Scanner::K_end)
|
||||
return false;
|
||||
|
||||
if (keyword==Scanner::K_short || keyword==Scanner::K_long || keyword==Scanner::K_float)
|
||||
{
|
||||
mDeclarationParser.reset();
|
||||
scanner.putbackKeyword (keyword, loc);
|
||||
scanner.scan (mDeclarationParser);
|
||||
return true;
|
||||
}
|
||||
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
|
||||
{
|
||||
if (code!=Scanner::S_newline)
|
||||
{
|
||||
SkipParser skip (getErrorHandler(), getContext());
|
||||
scanner.scan (skip);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Compiler::QuickFileParser::parseEOF (Scanner& scanner)
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
#ifndef COMPILER_QUICKFILEPARSER_H_INCLUDED
|
||||
#define COMPILER_QUICKFILEPARSER_H_INCLUDED
|
||||
|
||||
#include "parser.hpp"
|
||||
#include "declarationparser.hpp"
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
class Locals;
|
||||
|
||||
/// \brief File parser variant that ignores everything but variable declarations
|
||||
class QuickFileParser : public Parser
|
||||
{
|
||||
DeclarationParser mDeclarationParser;
|
||||
|
||||
public:
|
||||
|
||||
QuickFileParser (ErrorHandler& errorHandler, const Context& context, Locals& locals);
|
||||
|
||||
virtual bool parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner);
|
||||
///< Handle a name token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a keyword token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
|
||||
///< Handle a special character token.
|
||||
/// \return fetch another token?
|
||||
|
||||
virtual void parseEOF (Scanner& scanner);
|
||||
///< Handle EOF token.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue