Initial enum support
This commit is contained in:
parent
dc79d5d258
commit
4b0d30fbc4
2 changed files with 90 additions and 58 deletions
|
@ -54,9 +54,9 @@ public:
|
||||||
QString readCIncbin(const QString &text, const QString &label);
|
QString readCIncbin(const QString &text, const QString &label);
|
||||||
QMap<QString, QString> readCIncbinMulti(const QString &filepath);
|
QMap<QString, QString> readCIncbinMulti(const QString &filepath);
|
||||||
QStringList readCIncbinArray(const QString &filename, const QString &label);
|
QStringList readCIncbinArray(const QString &filename, const QString &label);
|
||||||
QMap<QString, int> readCDefinesByPrefix(const QString &filename, QStringList prefixes);
|
QMap<QString, int> readCDefinesByPrefix(const QString &filename, QStringList searchText);
|
||||||
QMap<QString, int> readCDefinesByName(const QString &filename, QStringList names);
|
QMap<QString, int> readCDefinesByName(const QString &filename, QStringList names);
|
||||||
QStringList readCDefineNames(const QString&, const QStringList&);
|
QStringList readCDefineNames(const QString&, QStringList searchText);
|
||||||
QMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString> = { });
|
QMap<QString, QHash<QString, QString>> readCStructs(const QString &, const QString & = "", const QHash<int, QString> = { });
|
||||||
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
|
QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&);
|
||||||
QStringList getLabelValues(const QList<QStringList>&, const QString&);
|
QStringList getLabelValues(const QList<QStringList>&, const QString&);
|
||||||
|
@ -97,8 +97,9 @@ private:
|
||||||
void recordErrors(const QStringList &errors);
|
void recordErrors(const QStringList &errors);
|
||||||
void logRecordedErrors();
|
void logRecordedErrors();
|
||||||
QString createErrorMessage(const QString &message, const QString &expression);
|
QString createErrorMessage(const QString &message, const QString &expression);
|
||||||
QString readCDefinesFile(const QString &filename);
|
QMap<QString, QString> readCDefineExpressions(const QString &filename);
|
||||||
QMap<QString, int> readCDefines(const QString &filename, const QStringList &searchText, bool fullMatch);
|
QMap<QString,QString> filterCDefineExpressions(const QMap<QString,QString> &allExpressions, QStringList searchText, bool fullMatch);
|
||||||
|
QMap<QString, int> evaluateCDefines(const QString &filename, const QStringList &searchText, bool fullMatch);
|
||||||
|
|
||||||
static const QRegularExpression re_incScriptLabel;
|
static const QRegularExpression re_incScriptLabel;
|
||||||
static const QRegularExpression re_globalIncScriptLabel;
|
static const QRegularExpression re_globalIncScriptLabel;
|
||||||
|
|
|
@ -15,6 +15,22 @@ 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_globalPoryScriptLabel("\\b(script)(\\((global)\\))?\\s*\\b(?<label>[\\w_][\\w\\d_]*)");
|
||||||
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
|
const QRegularExpression ParseUtil::re_poryRawSection("\\b(raw)\\s*`(?<raw_script>[^`]*)");
|
||||||
|
|
||||||
|
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},
|
||||||
|
};
|
||||||
|
|
||||||
using OrderedJson = poryjson::Json;
|
using OrderedJson = poryjson::Json;
|
||||||
|
|
||||||
ParseUtil::ParseUtil() { }
|
ParseUtil::ParseUtil() { }
|
||||||
|
@ -353,12 +369,14 @@ QStringList ParseUtil::readCIncbinArray(const QString &filename, const QString &
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ParseUtil::readCDefinesFile(const QString &filename)
|
// Open the file and return all the names and expressions defined by #define or enum
|
||||||
|
QMap<QString,QString> ParseUtil::readCDefineExpressions(const QString &filename)
|
||||||
{
|
{
|
||||||
|
QMap<QString, QString> expressions;
|
||||||
this->file = filename;
|
this->file = filename;
|
||||||
|
|
||||||
if (this->file.isEmpty()) {
|
if (this->file.isEmpty()) {
|
||||||
return QString();
|
return expressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString filepath = this->root + "/" + this->file;
|
QString filepath = this->root + "/" + this->file;
|
||||||
|
@ -366,50 +384,82 @@ QString ParseUtil::readCDefinesFile(const QString &filename)
|
||||||
|
|
||||||
if (this->text.isNull()) {
|
if (this->text.isNull()) {
|
||||||
logError(QString("Failed to read C defines file: '%1'").arg(filepath));
|
logError(QString("Failed to read C defines file: '%1'").arg(filepath));
|
||||||
return QString();
|
return expressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QRegularExpression re_extraChars("(//.*)|(\\/+\\*+[^*]*\\*+\\/+)");
|
static const QRegularExpression re_extraChars("(//.*)|(\\/+\\*+[^*]*\\*+\\/+)");
|
||||||
this->text.replace(re_extraChars, "");
|
this->text.replace(re_extraChars, "");
|
||||||
static const QRegularExpression re_extraSpaces("(\\\\\\s+)");
|
static const QRegularExpression re_extraSpaces("(\\\\\\s+)");
|
||||||
this->text.replace(re_extraSpaces, "");
|
this->text.replace(re_extraSpaces, "");
|
||||||
return this->text;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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).
|
if (this->text.isEmpty())
|
||||||
// If 'fullMatch' is true, 'searchText' is a list of exact define names to evaluate and return.
|
return expressions;
|
||||||
// If 'fullMatch' is false, 'searchText' is a list of prefixes or regexes for define names to evaluate and return.
|
|
||||||
QMap<QString, int> ParseUtil::readCDefines(const QString &filename, const QStringList &searchText, bool fullMatch)
|
|
||||||
{
|
|
||||||
QMap<QString, int> filteredValues;
|
|
||||||
|
|
||||||
this->text = this->readCDefinesFile(filename);
|
// Capture either the name and value of a #define, or everything between the braces of 'enum { }'
|
||||||
if (this->text.isEmpty()) {
|
static const QRegularExpression re("#define\\s+(?<defineName>\\w+)[\\s\\n][^\\S\\n]*(?<defineValue>.+)?"
|
||||||
return filteredValues;
|
"|\\benum\\b[^{]*{(?<enumBody>[^}]*)}");
|
||||||
}
|
|
||||||
|
|
||||||
// Extract all the define names and expressions
|
|
||||||
QMap<QString, QString> allExpressions;
|
|
||||||
QMap<QString, QString> filteredExpressions;
|
|
||||||
static const QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+(?<defineValue>.+)");
|
|
||||||
QRegularExpressionMatchIterator iter = re.globalMatch(this->text);
|
QRegularExpressionMatchIterator iter = re.globalMatch(this->text);
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
QRegularExpressionMatch match = iter.next();
|
QRegularExpressionMatch match = iter.next();
|
||||||
const QString name = match.captured("defineName");
|
const QString enumBody = match.captured("enumBody");
|
||||||
const QString expression = match.captured("defineValue");
|
if (!enumBody.isNull()) {
|
||||||
// If name matches the search text record it for evaluation.
|
// Encountered an enum, extract the elements of the enum and give each an appropriate expression
|
||||||
|
int baseNum = 0;
|
||||||
|
QString baseExpression = "0";
|
||||||
|
static const QRegularExpression re_enumElement("\\b(?<name>\\w+)\\b\\s*=?\\s*(?<expression>.+)?[,\\$]"); // TODO: Ignores terminal element lacking comma
|
||||||
|
QRegularExpressionMatchIterator elementIter = re_enumElement.globalMatch(enumBody);
|
||||||
|
while (elementIter.hasNext()) {
|
||||||
|
QRegularExpressionMatch elementMatch = elementIter.next();
|
||||||
|
QString expression = elementMatch.captured("expression");
|
||||||
|
if (expression.isEmpty()) {
|
||||||
|
// enum values may use tokens that we don't know how to evaluate yet.
|
||||||
|
// For now we define each element to be 1 + the previous element's expression.
|
||||||
|
expression = QString("((%1)+%2)").arg(baseExpression).arg(baseNum++);
|
||||||
|
} else {
|
||||||
|
// This element was explicitly assigned an expression with '=', reset the bases for any subsequent elements.
|
||||||
|
baseExpression = expression;
|
||||||
|
baseNum = 1;
|
||||||
|
}
|
||||||
|
expressions.insert(elementMatch.captured("name"), expression);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Encountered a #define
|
||||||
|
expressions.insert(match.captured("defineName"), match.captured("defineValue"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expressions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a map of define names->expressions, returns a map of define names->expressions where all the names match searchText.
|
||||||
|
// If 'fullMatch' is true, 'searchText' is a list of exact define names to match.
|
||||||
|
// If 'fullMatch' is false, 'searchText' is a list of prefixes or regexes of define names to match.
|
||||||
|
QMap<QString,QString> ParseUtil::filterCDefineExpressions(const QMap<QString,QString> &allExpressions, QStringList searchText, bool fullMatch) {
|
||||||
|
QMap<QString,QString> filteredExpressions;
|
||||||
|
searchText.removeDuplicates();
|
||||||
|
for (auto i = allExpressions.cbegin(), end = allExpressions.cend(); i != end; i++) {
|
||||||
|
const QString name = i.key();
|
||||||
for (auto s : searchText) {
|
for (auto s : searchText) {
|
||||||
if ((fullMatch && name == s) || (!fullMatch && (name.startsWith(s) || QRegularExpression(s).match(name).hasMatch()))) {
|
if ((fullMatch && name == s) || (!fullMatch && (name.startsWith(s) || QRegularExpression(s).match(name).hasMatch()))) {
|
||||||
filteredExpressions.insert(name, expression);
|
filteredExpressions.insert(name, i.value());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allExpressions.insert(name, expression);
|
}
|
||||||
|
return filteredExpressions;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, int> allValues;
|
// 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).
|
||||||
allValues.insert("FALSE", 0);
|
QMap<QString, int> ParseUtil::evaluateCDefines(const QString &filename, const QStringList &searchText, bool fullMatch) {
|
||||||
allValues.insert("TRUE", 1);
|
QMap<QString, int> filteredValues;
|
||||||
|
QMap<QString, int> allValues = defaultDefineValues;
|
||||||
|
|
||||||
|
QMap<QString, QString> allExpressions = this->readCDefineExpressions(filename);
|
||||||
|
if (allExpressions.isEmpty())
|
||||||
|
return filteredValues;
|
||||||
|
|
||||||
|
QMap<QString, QString> filteredExpressions = this->filterCDefineExpressions(allExpressions, searchText, fullMatch);
|
||||||
|
|
||||||
// Evaluate defines
|
// Evaluate defines
|
||||||
this->errorMap.clear();
|
this->errorMap.clear();
|
||||||
|
@ -425,39 +475,20 @@ QMap<QString, int> ParseUtil::readCDefines(const QString &filename, const QStrin
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and evaluate an unknown list of defines with a known name prefix.
|
// Find and evaluate an unknown list of defines with a known name prefix.
|
||||||
QMap<QString, int> ParseUtil::readCDefinesByPrefix(const QString &filename, QStringList prefixes) {
|
QMap<QString, int> ParseUtil::readCDefinesByPrefix(const QString &filename, QStringList searchText) {
|
||||||
prefixes.removeDuplicates();
|
return this->evaluateCDefines(filename, searchText, false);
|
||||||
return this->readCDefines(filename, prefixes, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find and evaluate a specific set of defines with known names.
|
// Find and evaluate a specific set of defines with known names.
|
||||||
QMap<QString, int> ParseUtil::readCDefinesByName(const QString &filename, QStringList names) {
|
QMap<QString, int> ParseUtil::readCDefinesByName(const QString &filename, QStringList names) {
|
||||||
names.removeDuplicates();
|
return this->evaluateCDefines(filename, names, true);
|
||||||
return this->readCDefines(filename, names, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similar to readCDefines, but for cases where we only need to show a list of define names.
|
// Similar to readCDefinesByPrefix, but for cases where we only need to show a list of define names.
|
||||||
// We can skip reading/evaluating any expressions (and by extension skip reporting any errors from this process).
|
// We can skip evaluating any expressions (and by extension skip reporting any errors from this process).
|
||||||
QStringList ParseUtil::readCDefineNames(const QString &filename, const QStringList &prefixes) {
|
QStringList ParseUtil::readCDefineNames(const QString &filename, QStringList searchText) {
|
||||||
QStringList filteredNames;
|
// TODO: These will now be alphabetical. Is that ok?
|
||||||
|
return this->filterCDefineExpressions(this->readCDefineExpressions(filename), searchText, false).keys();
|
||||||
this->text = this->readCDefinesFile(filename);
|
|
||||||
if (this->text.isEmpty()) {
|
|
||||||
return filteredNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QRegularExpression re("#define\\s+(?<defineName>\\w+)[^\\S\\n]+");
|
|
||||||
QRegularExpressionMatchIterator iter = re.globalMatch(this->text);
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
QRegularExpressionMatch match = iter.next();
|
|
||||||
QString name = match.captured("defineName");
|
|
||||||
for (QString prefix : prefixes) {
|
|
||||||
if (name.startsWith(prefix) || QRegularExpression(prefix).match(name).hasMatch()) {
|
|
||||||
filteredNames.append(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filteredNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList ParseUtil::readCArray(const QString &filename, const QString &label) {
|
QStringList ParseUtil::readCArray(const QString &filename, const QString &label) {
|
||||||
|
|
Loading…
Reference in a new issue