diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 00166821..a69ed2f4 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -54,9 +54,9 @@ public: QString readCIncbin(const QString &text, const QString &label); QMap readCIncbinMulti(const QString &filepath); QStringList readCIncbinArray(const QString &filename, const QString &label); - QMap readCDefinesByPrefix(const QString &filename, const QStringList &searchText); + QMap readCDefinesByRegex(const QString &filename, const QStringList ®exList); QMap readCDefinesByName(const QString &filename, const QStringList &names); - QStringList readCDefineNames(const QString&, const QStringList &searchText); + QStringList readCDefineNames(const QString &filename, const QStringList ®exList); QMap> readCStructs(const QString &, const QString & = "", const QHash = { }); QList getLabelMacros(const QList&, const QString&); QStringList getLabelValues(const QList&, const QString&); @@ -102,9 +102,9 @@ private: QMap expressions; // Map of all define names->expressions encountered QStringList filteredNames; // Define names matching the search text in the order they were encountered in the file }; - ParsedDefines readCDefines(const QString &filename, const QStringList &filterList, bool fullMatch); - QMap evaluateCDefines(const QString &filename, const QStringList &filterList, bool fullMatch); - bool defineNameMatchesFilter(const QString &name, const QStringList &filterList, bool fullMatch); + ParsedDefines readCDefines(const QString &filename, const QStringList &filterList, bool useRegex); + QMap evaluateCDefines(const QString &filename, const QStringList &filterList, bool useRegex); + bool defineNameMatchesFilter(const QString &name, const QStringList &filterList, bool useRegex); static const QRegularExpression re_incScriptLabel; static const QRegularExpression re_globalIncScriptLabel; diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 4043ea17..c9b02275 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -369,18 +369,18 @@ QStringList ParseUtil::readCIncbinArray(const QString &filename, const QString & return paths; } -bool ParseUtil::defineNameMatchesFilter(const QString &name, const QStringList &filterList, bool fullMatch) { +bool ParseUtil::defineNameMatchesFilter(const QString &name, const QStringList &filterList, bool useRegex) { for (auto filter : filterList) { - if (fullMatch) { - if (name == filter) return true; - } else { - if (name.startsWith(filter) || QRegularExpression(filter).match(name).hasMatch()) return true; - } + if (useRegex) { + // TODO: These QRegularExpression should probably be constructed beforehand, + // otherwise we recreate them for every define we check. + if (QRegularExpression(filter).match(name).hasMatch()) return true; + } else if (name == filter) return true; } return false; } -ParseUtil::ParsedDefines ParseUtil::readCDefines(const QString &filename, const QStringList &filterList, bool fullMatch) { +ParseUtil::ParsedDefines ParseUtil::readCDefines(const QString &filename, const QStringList &filterList, bool useRegex) { ParsedDefines result; this->file = filename; @@ -432,14 +432,14 @@ ParseUtil::ParsedDefines ParseUtil::readCDefines(const QString &filename, const baseNum = 1; } result.expressions.insert(name, expression); - if (defineNameMatchesFilter(name, filterList, fullMatch)) + if (defineNameMatchesFilter(name, filterList, useRegex)) result.filteredNames.append(name); } } else { // Encountered a #define const QString name = match.captured("defineName"); result.expressions.insert(name, match.captured("defineValue")); - if (defineNameMatchesFilter(name, filterList, fullMatch)) + if (defineNameMatchesFilter(name, filterList, useRegex)) result.filteredNames.append(name); } } @@ -447,8 +447,8 @@ 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 ParseUtil::evaluateCDefines(const QString &filename, const QStringList &filterList, bool fullMatch) { - ParsedDefines defines = readCDefines(filename, filterList, fullMatch); +QMap ParseUtil::evaluateCDefines(const QString &filename, const QStringList &filterList, bool useRegex) { + ParsedDefines defines = readCDefines(filename, filterList, useRegex); // Evaluate defines QMap filteredValues; @@ -465,20 +465,21 @@ QMap ParseUtil::evaluateCDefines(const QString &filename, const QS return filteredValues; } -// Find and evaluate an unknown list of defines with a known name prefix. -QMap ParseUtil::readCDefinesByPrefix(const QString &filename, const QStringList &filterList) { - return evaluateCDefines(filename, filterList, false); -} - // Find and evaluate a specific set of defines with known names. QMap ParseUtil::readCDefinesByName(const QString &filename, const QStringList &names) { - return evaluateCDefines(filename, names, true); + return evaluateCDefines(filename, names, false); } -// Similar to readCDefinesByPrefix, but for cases where we only need to show a list of define names. +// Find and evaluate an unknown list of defines with a known name pattern. +QMap ParseUtil::readCDefinesByRegex(const QString &filename, const QStringList ®exList) { + return evaluateCDefines(filename, regexList, true); +} + +// Find an unknown list of defines with a known name pattern. +// Similar to readCDefinesByRegex, but for cases where we only need to show a list of define names. // We can skip evaluating any expressions (and by extension skip reporting any errors from this process). -QStringList ParseUtil::readCDefineNames(const QString &filename, const QStringList &filterList) { - return readCDefines(filename, filterList, false).filteredNames; +QStringList ParseUtil::readCDefineNames(const QString &filename, const QStringList ®exList) { + return readCDefines(filename, regexList, true).filteredNames; } QStringList ParseUtil::readCArray(const QString &filename, const QString &label) { diff --git a/src/project.cpp b/src/project.cpp index 10ace396..8c1dbba5 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1557,8 +1557,8 @@ bool Project::readTilesetMetatileLabels() { QString metatileLabelsFilename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_labels); fileWatcher.addPath(root + "/" + metatileLabelsFilename); - const QStringList prefixes = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix))}; - QMap defines = parser.readCDefinesByPrefix(metatileLabelsFilename, prefixes); + const QStringList regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_metatile_label_prefix))}; + QMap defines = parser.readCDefinesByRegex(metatileLabelsFilename, regexList); for (QString label : defines.keys()) { uint32_t metatileId = static_cast(defines[label]); @@ -2114,10 +2114,10 @@ bool Project::readRegionMapSections() { this->mapSectionNameToValue.clear(); this->mapSectionValueToName.clear(); - const QStringList prefixes = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix))}; + const QStringList regexList = {QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix))}; QString filename = projectConfig.getFilePath(ProjectFilePath::constants_region_map_sections); fileWatcher.addPath(root + "/" + filename); - this->mapSectionNameToValue = parser.readCDefinesByPrefix(filename, prefixes); + this->mapSectionNameToValue = parser.readCDefinesByRegex(filename, regexList); if (this->mapSectionNameToValue.isEmpty()) { logError(QString("Failed to read region map sections from %1.").arg(filename)); return false; @@ -2132,13 +2132,13 @@ bool Project::readRegionMapSections() { // Read the constants to preserve any "unused" heal locations when writing the file later bool Project::readHealLocationConstants() { this->healLocationNameToValue.clear(); - const QStringList prefixes = { + const QStringList regexList = { QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_heal_locations_prefix)), QString("\\b%1").arg(projectConfig.getIdentifier(ProjectIdentifier::define_spawn_prefix)) }; QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_heal_locations); fileWatcher.addPath(root + "/" + constantsFilename); - this->healLocationNameToValue = parser.readCDefinesByPrefix(constantsFilename, prefixes); + this->healLocationNameToValue = parser.readCDefinesByRegex(constantsFilename, regexList); // No need to check if empty, not finding any heal location constants is ok return true; } @@ -2237,40 +2237,40 @@ bool Project::readHealLocations() { } bool Project::readItemNames() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_items)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_items)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_items); fileWatcher.addPath(root + "/" + filename); - itemNames = parser.readCDefineNames(filename, prefixes); + itemNames = parser.readCDefineNames(filename, regexList); if (itemNames.isEmpty()) logWarn(QString("Failed to read item constants from %1").arg(filename)); return true; } bool Project::readFlagNames() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_flags)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_flags)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_flags); fileWatcher.addPath(root + "/" + filename); - flagNames = parser.readCDefineNames(filename, prefixes); + flagNames = parser.readCDefineNames(filename, regexList); if (flagNames.isEmpty()) logWarn(QString("Failed to read flag constants from %1").arg(filename)); return true; } bool Project::readVarNames() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_vars)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_vars)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_vars); fileWatcher.addPath(root + "/" + filename); - varNames = parser.readCDefineNames(filename, prefixes); + varNames = parser.readCDefineNames(filename, regexList); if (varNames.isEmpty()) logWarn(QString("Failed to read var constants from %1").arg(filename)); return true; } bool Project::readMovementTypes() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_movement_types)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_movement_types)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_event_movement); fileWatcher.addPath(root + "/" + filename); - movementTypes = parser.readCDefineNames(filename, prefixes); + movementTypes = parser.readCDefineNames(filename, regexList); if (movementTypes.isEmpty()) logWarn(QString("Failed to read movement type constants from %1").arg(filename)); return true; @@ -2286,30 +2286,30 @@ bool Project::readInitialFacingDirections() { } bool Project::readMapTypes() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_map_types)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_map_types)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); - mapTypes = parser.readCDefineNames(filename, prefixes); + mapTypes = parser.readCDefineNames(filename, regexList); if (mapTypes.isEmpty()) logWarn(QString("Failed to read map type constants from %1").arg(filename)); return true; } bool Project::readMapBattleScenes() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_battle_scenes)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_battle_scenes)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_map_types); fileWatcher.addPath(root + "/" + filename); - mapBattleScenes = parser.readCDefineNames(filename, prefixes); + mapBattleScenes = parser.readCDefineNames(filename, regexList); if (mapBattleScenes.isEmpty()) logWarn(QString("Failed to read map battle scene constants from %1").arg(filename)); return true; } bool Project::readWeatherNames() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_weather)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_weather)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); - weatherNames = parser.readCDefineNames(filename, prefixes); + weatherNames = parser.readCDefineNames(filename, regexList); if (weatherNames.isEmpty()) logWarn(QString("Failed to read weather constants from %1").arg(filename)); return true; @@ -2319,10 +2319,10 @@ bool Project::readCoordEventWeatherNames() { if (!projectConfig.eventWeatherTriggerEnabled) return true; - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_coord_event_weather)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_weather); fileWatcher.addPath(root + "/" + filename); - coordEventWeatherNames = parser.readCDefineNames(filename, prefixes); + coordEventWeatherNames = parser.readCDefineNames(filename, regexList); if (coordEventWeatherNames.isEmpty()) logWarn(QString("Failed to read coord event weather constants from %1").arg(filename)); return true; @@ -2332,30 +2332,30 @@ bool Project::readSecretBaseIds() { if (!projectConfig.eventSecretBaseEnabled) return true; - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_secret_bases)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_secret_bases); fileWatcher.addPath(root + "/" + filename); - secretBaseIds = parser.readCDefineNames(filename, prefixes); + secretBaseIds = parser.readCDefineNames(filename, regexList); if (secretBaseIds.isEmpty()) logWarn(QString("Failed to read secret base id constants from '%1'").arg(filename)); return true; } bool Project::readBgEventFacingDirections() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_sign_facing_directions)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_sign_facing_directions)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_event_bg); fileWatcher.addPath(root + "/" + filename); - bgEventFacingDirections = parser.readCDefineNames(filename, prefixes); + bgEventFacingDirections = parser.readCDefineNames(filename, regexList); if (bgEventFacingDirections.isEmpty()) logWarn(QString("Failed to read bg event facing direction constants from %1").arg(filename)); return true; } bool Project::readTrainerTypes() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_trainer_types)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_trainer_types)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_trainer_types); fileWatcher.addPath(root + "/" + filename); - trainerTypes = parser.readCDefineNames(filename, prefixes); + trainerTypes = parser.readCDefineNames(filename, regexList); if (trainerTypes.isEmpty()) logWarn(QString("Failed to read trainer type constants from %1").arg(filename)); return true; @@ -2365,10 +2365,10 @@ bool Project::readMetatileBehaviors() { this->metatileBehaviorMap.clear(); this->metatileBehaviorMapInverse.clear(); - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_behaviors)}; QString filename = projectConfig.getFilePath(ProjectFilePath::constants_metatile_behaviors); fileWatcher.addPath(root + "/" + filename); - QMap defines = parser.readCDefinesByPrefix(filename, prefixes); + QMap defines = parser.readCDefinesByRegex(filename, regexList); if (defines.isEmpty()) { // Not having any metatile behavior names is ok (their values will be displayed instead). // If the user's metatiles can have nonzero values then warn them, as they likely want names. @@ -2387,10 +2387,10 @@ bool Project::readMetatileBehaviors() { } bool Project::readSongNames() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_music)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_music)}; const QString filename = projectConfig.getFilePath(ProjectFilePath::constants_songs); fileWatcher.addPath(root + "/" + filename); - this->songNames = parser.readCDefineNames(filename, prefixes); + this->songNames = parser.readCDefineNames(filename, regexList); if (this->songNames.isEmpty()) logWarn(QString("Failed to read song names from %1.").arg(filename)); @@ -2402,10 +2402,10 @@ bool Project::readSongNames() { } bool Project::readObjEventGfxConstants() { - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_obj_event_gfx)}; QString filename = projectConfig.getFilePath(ProjectFilePath::constants_obj_events); fileWatcher.addPath(root + "/" + filename); - this->gfxDefines = parser.readCDefinesByPrefix(filename, prefixes); + this->gfxDefines = parser.readCDefinesByRegex(filename, regexList); if (this->gfxDefines.isEmpty()) logWarn(QString("Failed to read object event graphics constants from %1.").arg(filename)); return true; @@ -2611,10 +2611,10 @@ bool Project::readSpeciesIconPaths() { const QMap iconIncbins = parser.readCIncbinMulti(incfilename); // Read species constants. If this fails we can get them from the icon table (but we shouldn't rely on it). - const QStringList prefixes = {projectConfig.getIdentifier(ProjectIdentifier::regex_species)}; + const QStringList regexList = {projectConfig.getIdentifier(ProjectIdentifier::regex_species)}; const QString constantsFilename = projectConfig.getFilePath(ProjectFilePath::constants_species); fileWatcher.addPath(root + "/" + constantsFilename); - QStringList speciesNames = parser.readCDefineNames(constantsFilename, prefixes); + QStringList speciesNames = parser.readCDefineNames(constantsFilename, regexList); if (speciesNames.isEmpty()) speciesNames = monIconNames.keys();