Parser define maps to hashes

This commit is contained in:
GriffinR
2025-04-23 17:08:47 -04:00
parent 781f965d6b
commit 715f53731d
3 changed files with 50 additions and 43 deletions

View File

@@ -55,11 +55,12 @@ public:
QString readCIncbin(const QString &text, const QString &label);
QMap<QString, QString> readCIncbinMulti(const QString &filepath);
QStringList readCIncbinArray(const QString &filename, const QString &label);
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);
QHash<QString, int> readCDefinesByRegex(const QString &filename, const QSet<QString> &regexList, QString *error = nullptr);
QHash<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 loadGlobalCDefinesFromFile(const QString &filename, QString *error = nullptr);
void loadGlobalCDefines(const QMap<QString,QString> &defines);
void loadGlobalCDefines(const QHash<QString,QString> &defines);
void resetCDefines();
OrderedMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString>& = {});
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
@@ -96,13 +97,13 @@ private:
// The maps of define names to values/expressions that are available while parsing C defines.
// As the parser reads and evaluates more defines it will update these maps accordingly.
QMap<QString, int> knownDefineValues;
QMap<QString, QString> knownDefineExpressions;
QHash<QString, int> knownDefineValues;
QHash<QString, QString> knownDefineExpressions;
// Maps of special define names to values/expressions that take precedence over defines encountered while parsing.
// Some (like 'TRUE'/'FALSE') are always present in these maps, others may be specified by the user with 'loadGlobalCDefines' / 'loadGlobalCDefinesFromFile'.
QMap<QString, int> globalDefineValues;
QMap<QString, QString> globalDefineExpressions;
QHash<QString, int> globalDefineValues;
QHash<QString, QString> globalDefineExpressions;
int evaluateDefine(const QString &identifier, bool *ok = nullptr);
int evaluateExpression(const QString &expression);
@@ -115,11 +116,11 @@ private:
QString createErrorMessage(const QString &message, const QString &expression);
struct ParsedDefines {
QMap<QString,QString> expressions; // Map of all define names encountered to their expressions
QHash<QString,QString> expressions; // Map of all define names encountered to their expressions
QStringList filteredNames; // List of define names that matched the search text, in the order that they were encountered
};
ParsedDefines readCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
QMap<QString, int> evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
QHash<QString, int> evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error);
bool defineNameMatchesFilter(const QString &name, const QSet<QString> &filterList) const;
bool defineNameMatchesFilter(const QString &name, const QSet<QRegularExpression> &filterList) const;
QString loadTextFile(const QString &path, QString *error = nullptr);

View File

@@ -488,11 +488,11 @@ ParseUtil::ParsedDefines ParseUtil::readCDefines(const QString &filename, const
}
// Read all the define names and their expressions in the specified file, then evaluate the ones matching the search text (and any they depend on).
QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error) {
QHash<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QSet<QString> &filterList, bool useRegex, QString *error) {
ParsedDefines defines = readCDefines(filename, filterList, useRegex, error);
// Evaluate defines
QMap<QString, int> filteredValues;
QHash<QString, int> filteredValues;
this->errorMap.clear();
while (!defines.filteredNames.isEmpty()) {
this->curDefine = defines.filteredNames.takeFirst();
@@ -504,12 +504,12 @@ QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QS
}
// Find and evaluate a specific set of defines with known names.
QMap<QString, int> ParseUtil::readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error) {
QHash<QString, int> ParseUtil::readCDefinesByName(const QString &filename, const QSet<QString> &names, QString *error) {
return evaluateCDefines(filename, names, false, error);
}
// Find and evaluate an unknown list of defines with a known name pattern.
QMap<QString, int> ParseUtil::readCDefinesByRegex(const QString &filename, const QSet<QString> &regexList, QString *error) {
QHash<QString, int> ParseUtil::readCDefinesByRegex(const QString &filename, const QSet<QString> &regexList, QString *error) {
return evaluateCDefines(filename, regexList, true, error);
}
@@ -526,12 +526,17 @@ void ParseUtil::loadGlobalCDefinesFromFile(const QString &filename, QString *err
loadGlobalCDefines(readCDefines(filename, {}, false, error).expressions);
}
void ParseUtil::loadGlobalCDefines(const QMap<QString,QString> &defines) {
void ParseUtil::loadGlobalCDefines(const QHash<QString,QString> &defines) {
this->globalDefineExpressions.insert(defines);
}
void ParseUtil::loadGlobalCDefines(const QMap<QString,QString> &defines) {
for (auto it = defines.constBegin(); it != defines.constEnd(); it++)
this->globalDefineExpressions.insert(it.key(), it.value());
}
void ParseUtil::resetCDefines() {
static const QMap<QString, int> defaultDefineValues = {
static const QHash<QString, int> defaultDefineValues = {
{"FALSE", 0},
{"TRUE", 1},
{"SCHAR_MIN", SCHAR_MIN},

View File

@@ -1481,7 +1481,7 @@ bool Project::readTilesetMetatileLabels() {
fileWatcher.addPath(root + "/" + metatileLabelsFilename);
const QSet<QString> regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix))};
const QMap<QString, int> defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList);
const auto defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList);
for (auto i = defines.constBegin(); i != defines.constEnd(); i++) {
QString label = i.key();
uint32_t metatileId = i.value();
@@ -2116,16 +2116,15 @@ bool Project::readFieldmapProperties() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_fieldmap);
fileWatcher.addPath(root + "/" + filename);
const QMap<QString, int> defines = parser.readCDefinesByName(filename, {
numTilesPrimaryName,
numTilesTotalName,
numMetatilesPrimaryName,
numPalsPrimaryName,
numPalsTotalName,
maxMapSizeName,
numTilesPerMetatileName,
mapOffsetWidthName,
mapOffsetHeightName,
const auto defines = parser.readCDefinesByName(filename, { numTilesPrimaryName,
numTilesTotalName,
numMetatilesPrimaryName,
numPalsPrimaryName,
numPalsTotalName,
maxMapSizeName,
numTilesPerMetatileName,
mapOffsetWidthName,
mapOffsetHeightName,
});
auto loadDefine = [defines](const QString name, int * dest, int min, int max) {
@@ -2219,16 +2218,15 @@ bool Project::readFieldmapMasks() {
const QString elevationMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_elevation);
const QString behaviorMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_behavior);
const QString layerTypeMaskName = projectConfig.getIdentifier(ProjectIdentifier::define_mask_layer);
const QSet<QString> searchNames = {
metatileIdMaskName,
collisionMaskName,
elevationMaskName,
behaviorMaskName,
layerTypeMaskName,
};
const QString globalFieldmap = projectConfig.getFilePath(ProjectFilePath::global_fieldmap);
fileWatcher.addPath(root + "/" + globalFieldmap);
QMap<QString, int> defines = parser.readCDefinesByName(globalFieldmap, searchNames);
const auto defines = parser.readCDefinesByName(globalFieldmap, { metatileIdMaskName,
collisionMaskName,
elevationMaskName,
behaviorMaskName,
layerTypeMaskName,
});
// These mask values are accessible via the settings editor for users who don't have these defines.
// If users do have the defines we disable them in the settings editor and direct them to their project files.
@@ -2239,8 +2237,8 @@ bool Project::readFieldmapMasks() {
// Read Block masks
auto readBlockMask = [defines](const QString name, uint16_t *value) {
auto it = defines.find(name);
if (it == defines.end())
auto it = defines.constFind(name);
if (it == defines.constEnd())
return false;
*value = static_cast<uint16_t>(it.value());
if (*value != it.value()){
@@ -2314,7 +2312,7 @@ bool Project::readFieldmapMasks() {
// Read #defines for encounter and terrain types to populate in the Tileset Editor dropdowns (if necessary)
QString error;
if (projectConfig.metatileEncounterTypeMask) {
QMap<QString, int> defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_encounter_types)}, &error);
const auto defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_encounter_types)}, &error);
if (!error.isEmpty()) {
logWarn(QString("Failed to read encounter type constants from '%1': %2").arg(globalFieldmap).arg(error));
error = QString();
@@ -2325,7 +2323,7 @@ bool Project::readFieldmapMasks() {
}
}
if (projectConfig.metatileTerrainTypeMask) {
QMap<QString, int> defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_terrain_types)}, &error);
const auto defines = parser.readCDefinesByRegex(globalFieldmap, {projectConfig.getIdentifier(ProjectIdentifier::regex_terrain_types)}, &error);
if (!error.isEmpty()) {
logWarn(QString("Failed to read terrain type constants from '%1': %2").arg(globalFieldmap).arg(error));
error = QString();
@@ -2673,7 +2671,7 @@ bool Project::readMetatileBehaviors() {
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_behaviors);
fileWatcher.addPath(root + "/" + filename);
QString error;
QMap<QString, int> defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}, &error);
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}, &error);
if (defines.isEmpty() && projectConfig.metatileBehaviorMask) {
// Not having any metatile behavior names is ok (their values will be displayed instead)
// but if the user's metatiles can have nonzero values then warn them, as they likely want names.
@@ -2710,9 +2708,14 @@ bool Project::readObjEventGfxConstants() {
QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events);
fileWatcher.addPath(root + "/" + filename);
QString error;
this->gfxDefines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}, &error);
const auto defines = parser.readCDefinesByRegex(filename, {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}, &error);
if (!error.isEmpty())
logWarn(QString("Failed to read object event graphics constants from '%1': %2").arg(filename).arg(error));
this->gfxDefines.clear();
for (auto it = defines.constBegin(); it != defines.constEnd(); it++)
this->gfxDefines.insert(it.key(), it.value());
return true;
}
@@ -2720,7 +2723,7 @@ bool Project::readMiscellaneousConstants() {
const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_global);
const QString maxObjectEventsName = projectConfig.getIdentifier(ProjectIdentifier::define_obj_event_count);
fileWatcher.addPath(root + "/" + filename);
QMap<QString, int> defines = parser.readCDefinesByName(filename, {maxObjectEventsName});
const auto defines = parser.readCDefinesByName(filename, {maxObjectEventsName});
this->maxObjectEvents = 64; // Default value
auto it = defines.find(maxObjectEventsName);
@@ -2953,9 +2956,7 @@ QPixmap Project::getEventPixmap(const QString &gfxName, int frame, bool hFlip) {
// Invalid gfx constant. If this is a number, try to use that instead.
bool ok;
int gfxNum = ParseUtil::gameStringToInt(gfxName, &ok);
if (ok && gfxNum < this->gfxDefines.count()) {
gfx = this->eventGraphicsMap.value(this->gfxDefines.key(gfxNum, "NULL"), nullptr);
}
if (ok) gfx = this->eventGraphicsMap.value(this->gfxDefines.key(gfxNum, "NULL"), nullptr);
}
if (gfx && !gfx->loaded) {
// This is the first request for this event's sprite. We'll attempt to load it now.