Add functionality for global constants

This commit is contained in:
GriffinR 2025-04-21 20:16:59 -04:00
parent e8ac633700
commit ed273b9ca0
6 changed files with 60 additions and 28 deletions

View File

@ -345,6 +345,7 @@ public:
this->unusedTileCovered = 0x0000;
this->unusedTileSplit = 0x0000;
this->maxEventsPerGroup = 255;
this->globalConstantsFilepaths.clear();
this->identifiers.clear();
this->readKeys.clear();
}
@ -417,6 +418,7 @@ public:
QMargins playerViewDistance;
QList<uint32_t> warpBehaviors;
int maxEventsPerGroup;
QStringList globalConstantsFilepaths;
protected:
virtual QString getConfigFilepath() override;

View File

@ -43,7 +43,7 @@ class ParseUtil
{
public:
ParseUtil();
void set_root(const QString &dir);
void setRoot(const QString &dir) { this->root = dir; }
static QString readTextFile(const QString &path, QString *error = nullptr);
bool cacheFile(const QString &path, QString *error = nullptr);
void clearFileCache() { this->fileCache.clear(); }
@ -58,6 +58,8 @@ public:
QMap<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> &regexList, QString *error = nullptr);
QMap<QString, int> readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error = nullptr);
QStringList readCDefineNames(const QString &filename, const QSet<QString> &regexList, QString *error = nullptr);
void loadGlobalCDefines(const QString &filename, QString *error = nullptr);
void resetGlobalCDefines();
OrderedMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
QStringList getLabelValues(const QList<QStringList>&, const QString&);
@ -90,6 +92,8 @@ private:
QString curDefine;
QHash<QString, QString> fileCache;
QHash<QString, QStringList> errorMap;
QMap<QString, int> globalDefineValues;
QMap<QString, QString> globalDefineExpressions;
int evaluateDefine(const QString&, const QString &, QMap<QString, int>*, QMap<QString, QString>*);
QList<Token> tokenizeExpression(QString, QMap<QString, int>*, QMap<QString, QString>*);
QList<Token> generatePostfix(const QList<Token> &tokens);

View File

@ -76,7 +76,7 @@ public:
int maxEncounterRate;
bool wildEncountersLoaded;
void set_root(QString);
void setRoot(const QString&);
void clearMaps();
void clearTilesetCache();
@ -203,6 +203,7 @@ public:
bool readEventGraphics();
bool readFieldmapProperties();
bool readFieldmapMasks();
bool readGlobalConstants();
QMap<QString, QMap<QString, QString>> readObjEventGfxInfo();
QPixmap getEventPixmap(const QString &gfxName, const QString &movementName);

View File

@ -15,26 +15,8 @@ const QRegularExpression ParseUtil::re_poryScriptLabel("\\b(script)(\\((global|l
const QRegularExpression ParseUtil::re_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?<label>[\\w_][\\w\\d_]*)");
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
static const QMap<QString, int> globalDefineValues = {
{"FALSE", 0},
{"TRUE", 1},
{"SCHAR_MIN", SCHAR_MIN},
{"SCHAR_MAX", SCHAR_MAX},
{"CHAR_MIN", CHAR_MIN},
{"CHAR_MAX", CHAR_MAX},
{"UCHAR_MAX", UCHAR_MAX},
{"SHRT_MIN", SHRT_MIN},
{"SHRT_MAX", SHRT_MAX},
{"USHRT_MAX", USHRT_MAX},
{"INT_MIN", INT_MIN},
{"INT_MAX", INT_MAX},
{"UINT_MAX", UINT_MAX},
};
ParseUtil::ParseUtil() { }
void ParseUtil::set_root(const QString &dir) {
this->root = dir;
ParseUtil::ParseUtil() {
resetGlobalCDefines();
}
QString ParseUtil::pathWithRoot(const QString &path) {
@ -181,10 +163,14 @@ QList<Token> ParseUtil::tokenizeExpression(QString expression, QMap<QString, int
QString token = match.captured(tokenType);
if (!token.isEmpty()) {
if (tokenType == "identifier") {
// If this expression depends on a define we know of but haven't evaluated then evaluate it now
if (unevaluatedExpressions->contains(token)) {
// This expression depends on a define we know of but haven't evaluated. Evaluate it now
evaluateDefine(token, unevaluatedExpressions->value(token), knownValues, unevaluatedExpressions);
} else if (this->globalDefineExpressions.contains(token)) {
int value = evaluateDefine(token, this->globalDefineExpressions.value(token), &this->globalDefineValues, &this->globalDefineExpressions);
knownValues->insert(token, value);
}
if (knownValues->contains(token)) {
// Any errors encountered when this identifier was evaluated should be recorded for this expression as well.
recordErrors(this->errorMap.value(token));
@ -490,7 +476,7 @@ QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QS
// Evaluate defines
QMap<QString, int> filteredValues;
QMap<QString, int> allValues = globalDefineValues;
QMap<QString, int> allValues = this->globalDefineValues;
this->errorMap.clear();
while (!defines.filteredNames.isEmpty()) {
const QString name = defines.filteredNames.takeFirst();
@ -521,6 +507,32 @@ QStringList ParseUtil::readCDefineNames(const QString &filename, const QSet<QStr
return readCDefines(filename, regexList, true, error).filteredNames;
}
// Find any defines in the specified file and save their expressions.
// If any of these defines are encountered later by other define parsing functions then they'll be recognized and evaluated.
void ParseUtil::loadGlobalCDefines(const QString &filename, QString *error) {
this->globalDefineExpressions.insert(readCDefines(filename, {}, false, error).expressions);
}
void ParseUtil::resetGlobalCDefines() {
static const QMap<QString, int> defaultDefineValues = {
{"FALSE", 0},
{"TRUE", 1},
{"SCHAR_MIN", SCHAR_MIN},
{"SCHAR_MAX", SCHAR_MAX},
{"CHAR_MIN", CHAR_MIN},
{"CHAR_MAX", CHAR_MAX},
{"UCHAR_MAX", UCHAR_MAX},
{"SHRT_MIN", SHRT_MIN},
{"SHRT_MAX", SHRT_MAX},
{"USHRT_MAX", USHRT_MAX},
{"INT_MIN", INT_MIN},
{"INT_MAX", INT_MAX},
{"UINT_MAX", UINT_MAX},
};
this->globalDefineValues = defaultDefineValues;
this->globalDefineExpressions.clear();
}
QStringList ParseUtil::readCArray(const QString &filename, const QString &label) {
QStringList list;

View File

@ -660,7 +660,7 @@ bool MainWindow::openProject(QString dir, bool initial) {
// Create the project
auto project = new Project(editor);
project->set_root(dir);
project->setRoot(dir);
connect(project, &Project::fileChanged, this, &MainWindow::showFileWatcherWarning);
connect(project, &Project::mapLoaded, this, &MainWindow::onMapLoaded);
connect(project, &Project::mapCreated, this, &MainWindow::onNewMapCreated);

View File

@ -48,10 +48,10 @@ Project::~Project()
QPixmapCache::clear();
}
void Project::set_root(QString dir) {
void Project::setRoot(const QString &dir) {
this->root = dir;
FileDialog::setDirectory(dir);
this->parser.set_root(dir);
this->parser.setRoot(dir);
}
// Before attempting the initial project load we should check for a few notable files.
@ -78,7 +78,8 @@ bool Project::sanityCheck() {
bool Project::load() {
resetFileCache();
this->disabledSettingsNames.clear();
bool success = readMapLayouts()
bool success = readGlobalConstants()
&& readMapLayouts()
&& readRegionMapSections()
&& readItemNames()
&& readFlagNames()
@ -2742,6 +2743,18 @@ bool Project::readMiscellaneousConstants() {
return true;
}
bool Project::readGlobalConstants() {
this->parser.resetGlobalCDefines();
for (const auto &path : projectConfig.globalConstantsFilepaths) {
QString error;
this->parser.loadGlobalCDefines(path, &error);
if (!error.isEmpty()) {
logWarn(QString("Failed to read global constants file '%1': %2").arg(path).arg(error));
}
}
return true;
}
bool Project::readEventScriptLabels() {
this->globalScriptLabels.clear();