1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-17 10:10:23 +00:00
OpenMW/apps/opencs/model/tools/scriptcheck.cpp
2024-10-31 14:59:55 +03:00

155 lines
4.2 KiB
C++

#include "scriptcheck.hpp"
#include <exception>
#include <sstream>
#include <string>
#include <apps/opencs/model/doc/messages.hpp>
#include <apps/opencs/model/prefs/category.hpp>
#include <apps/opencs/model/prefs/setting.hpp>
#include <apps/opencs/model/world/idcollection.hpp>
#include <apps/opencs/model/world/record.hpp>
#include <apps/opencs/model/world/scriptcontext.hpp>
#include <apps/opencs/model/world/universalid.hpp>
#include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp>
#include <components/compiler/fileparser.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/tokenloc.hpp>
#include <components/esm3/loadscpt.hpp>
#include "../doc/document.hpp"
#include "../world/data.hpp"
#include "../prefs/state.hpp"
CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity(Type type)
{
switch (type)
{
case WarningMessage:
return CSMDoc::Message::Severity_Warning;
case ErrorMessage:
return CSMDoc::Message::Severity_Error;
}
return CSMDoc::Message::Severity_SeriousError;
}
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 << message << " (" << loc.mLiteral << ")"
<< " @ line " << loc.mLine + 1 << ", column " << loc.mColumn;
std::ostringstream hintStream;
hintStream << "l:" << loc.mLine + 1 << " " << loc.mColumn;
mMessages->add(id, stream.str(), hintStream.str(), getSeverity(type));
}
void CSMTools::ScriptCheckStage::report(const std::string& message, Type type)
{
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Script, mId);
std::ostringstream stream;
stream << message;
mMessages->add(id, stream.str(), "", getSeverity(type));
}
CSMTools::ScriptCheckStage::ScriptCheckStage(const CSMDoc::Document& document)
: mDocument(document)
, mContext(document.getData())
, mMessages(nullptr)
, mWarningMode(Mode_Ignore)
{
/// \todo add an option to configure warning mode
setWarningsMode(0);
Compiler::registerExtensions(mExtensions);
mContext.setExtensions(&mExtensions);
mIgnoreBaseRecords = false;
}
int CSMTools::ScriptCheckStage::setup()
{
std::string warnings = CSMPrefs::get()["Scripts"]["warnings"].toString();
if (warnings == "Ignore")
mWarningMode = Mode_Ignore;
else if (warnings == "Normal")
mWarningMode = Mode_Normal;
else if (warnings == "Strict")
mWarningMode = Mode_Strict;
mContext.clear();
mMessages = nullptr;
mId = ESM::RefId();
Compiler::ErrorHandler::reset();
mIgnoreBaseRecords = CSMPrefs::get()["Reports"]["ignore-base-records"].isTrue();
return mDocument.getData().getScripts().getSize();
}
void CSMTools::ScriptCheckStage::perform(int stage, CSMDoc::Messages& messages)
{
const CSMWorld::Record<ESM::Script>& record = mDocument.getData().getScripts().getRecord(stage);
mId = mDocument.getData().getScripts().getId(stage);
// Skip "Base" records (setting!) and "Deleted" records
if ((mIgnoreBaseRecords && record.mState == CSMWorld::RecordBase::State_BaseOnly) || record.isDeleted())
return;
mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore:
setWarningsMode(0);
break;
case Mode_Normal:
setWarningsMode(1);
break;
case Mode_Strict:
setWarningsMode(2);
break;
}
try
{
mFile = record.get().mId.getRefIdString();
std::istringstream input(record.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)
{
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Script, mId);
std::ostringstream stream;
stream << error.what();
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
}
mMessages = nullptr;
}