diff options
Diffstat (limited to 'util/glgen/legacyspecparser.cpp')
-rw-r--r-- | util/glgen/legacyspecparser.cpp | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/util/glgen/legacyspecparser.cpp b/util/glgen/legacyspecparser.cpp new file mode 100644 index 0000000000..fc34eca80c --- /dev/null +++ b/util/glgen/legacyspecparser.cpp @@ -0,0 +1,305 @@ +/*************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the utilities of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "legacyspecparser.h" + +#include <QDebug> +#include <QFile> +#include <QRegExp> +#include <QStringList> +#include <QTextStream> + +#ifdef SPECPARSER_DEBUG +#define qLegacySpecParserDebug qDebug +#else +#define qLegacySpecParserDebug QT_NO_QDEBUG_MACRO +#endif + +bool LegacySpecParser::parse() +{ + // Get the mapping form generic types to specific types suitable for use in C-headers + if (!parseTypeMap()) + return false; + + // Open up a stream on the actual OpenGL function spec file + QFile file(specFileName()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Failed to open spec file:" << specFileName() << "Aborting"; + return false; + } + + QTextStream stream(&file); + + // Extract the info that we need + parseFunctions(stream); + return true; +} + +bool LegacySpecParser::parseTypeMap() +{ + QFile file(typeMapFileName()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Failed to open type file:" << typeMapFileName() << "Aborting"; + return false; + } + + QTextStream stream(&file); + + static QRegExp typeMapRegExp("([^,]+)\\W+([^,]+)"); + + while (!stream.atEnd()) { + QString line = stream.readLine(); + + if (line.startsWith(QStringLiteral("#"))) + continue; + + if (typeMapRegExp.indexIn(line) != -1) { + QString key = typeMapRegExp.cap(1).simplified(); + QString value = typeMapRegExp.cap(2).simplified(); + + // Special case for void + if (value == QStringLiteral("*")) + value = QStringLiteral("void"); + + m_typeMap.insert(key, value); + qLegacySpecParserDebug() << "Found type mapping from" << key << "=>" << value; + } + } + + return true; +} + +void LegacySpecParser::parseEnums() +{ +} + +void LegacySpecParser::parseFunctions(QTextStream &stream) +{ + static QRegExp functionRegExp("^(\\w+)\\(.*\\)"); + static QRegExp returnRegExp("^\\treturn\\s+(\\S+)"); + static QRegExp argumentRegExp("param\\s+(\\S+)\\s+(\\S+) (\\S+) (\\S+)"); + static QRegExp versionRegExp("^\\tversion\\s+(\\S+)"); + static QRegExp deprecatedRegExp("^\\tdeprecated\\s+(\\S+)"); + static QRegExp categoryRegExp("^\\tcategory\\s+(\\S+)"); + static QRegExp categoryVersionRegExp("VERSION_(\\d)_(\\d)"); + static QRegExp extToCoreVersionRegExp("passthru:\\s/\\*\\sOpenGL\\s(\\d)\\.(\\d)\\s.*\\sextensions:"); + static QRegExp extToCoreRegExp("passthru:\\s/\\*\\s(ARB_\\S*)\\s.*\\*/"); + + Function currentFunction; + VersionProfile currentVersionProfile; + QString currentCategory; + bool haveVersionInfo = false; + bool acceptCurrentFunctionInCore = false; + bool acceptCurrentFunctionInExtension = false; + + QHash<QString, Version> extensionsNowInCore; + Version extToCoreCurrentVersion; + int functionCount = 0; + + QSet<Version> versions; + + while (!stream.atEnd()) { + QString line = stream.readLine(); + if (line.startsWith("#")) + continue; + + if (functionRegExp.indexIn(line) != -1) { + + if (!currentFunction.name.isEmpty()) { + + // NB - Special handling! + // Versions 4.2 and 4.3 (and probably newer) add functionality by + // subsuming extensions such as ARB_texture_storage. However, some extensions + // also include functions to interact with the EXT_direct_state_access + // extension. These functions should be added to the DSA extension rather + // than the core functionality. The core will already contain non-DSA + // versions of these functions. + if (acceptCurrentFunctionInCore && currentFunction.name.endsWith(QStringLiteral("EXT"))) { + acceptCurrentFunctionInCore = false; + acceptCurrentFunctionInExtension = true; + currentCategory = QStringLiteral("EXT_direct_state_access"); + } + + // Finish off previous function (if any) by inserting it into the core + // functionality or extension functionality (or both) + if (acceptCurrentFunctionInCore) { + m_functions.insert(currentVersionProfile, currentFunction); + versions.insert(currentVersionProfile.version); + } + + if (acceptCurrentFunctionInExtension) { + FunctionProfile fp; + fp.profile = currentVersionProfile.profile; + fp.function = currentFunction; + m_extensionFunctions.insert(currentCategory, fp); + } + } + + // Start a new function + ++functionCount; + haveVersionInfo = false; + acceptCurrentFunctionInCore = true; + acceptCurrentFunctionInExtension = false; + currentCategory = QString(); + currentFunction = Function(); + + // We assume a core function unless we find a deprecated flag (see below) + currentVersionProfile = VersionProfile(); + currentVersionProfile.profile = VersionProfile::CoreProfile; + + // Extract the function name + QString functionName = functionRegExp.cap(1); + currentFunction.name = functionName; + qLegacySpecParserDebug() << "Found function:" << functionName; + + } else if (argumentRegExp.indexIn(line) != -1) { + // Extract info about this function argument + Argument arg; + arg.name = argumentRegExp.cap(1); + + QString type = argumentRegExp.cap(2); // Lookup in type map + arg.type = m_typeMap.value(type); + + QString direction = argumentRegExp.cap(3); + if (direction == QStringLiteral("in")) { + arg.direction = Argument::In; + } else if (direction == QStringLiteral("out")) { + arg.direction = Argument::Out; + } else { + qWarning() << "Invalid argument direction found:" << direction; + acceptCurrentFunctionInCore = false; + } + + QString mode = argumentRegExp.cap(4); + if (mode == QStringLiteral("value")) { + arg.mode = Argument::Value; + } else if (mode == QStringLiteral("array")) { + arg.mode = Argument::Array; + } else if (mode == QStringLiteral("reference")) { + arg.mode = Argument::Reference; + } else { + qWarning() << "Invalid argument mode found:" << mode; + acceptCurrentFunctionInCore = false; + } + + qLegacySpecParserDebug() << " argument:" << arg.type << arg.name; + currentFunction.arguments.append(arg); + + } else if (returnRegExp.indexIn(line) != -1) { + // Lookup the return type from the typemap + QString returnTypeKey = returnRegExp.cap(1).simplified(); + if (!m_typeMap.contains(returnTypeKey)) { + qWarning() << "Unknown return type found:" << returnTypeKey; + acceptCurrentFunctionInCore = false; + } + QString returnType = m_typeMap.value(returnTypeKey); + qLegacySpecParserDebug() << " return type:" << returnType; + currentFunction.returnType = returnType; + + } else if (versionRegExp.indexIn(line) != -1 && !haveVersionInfo) { // Only use version line if no other source + // Extract the OpenGL version in which this function was introduced + QString version = versionRegExp.cap(1); + qLegacySpecParserDebug() << " version:" << version; + QStringList parts = version.split(QLatin1Char('.')); + if (parts.size() != 2) { + qWarning() << "Found invalid version number"; + continue; + } + int majorVersion = parts.first().toInt(); + int minorVersion = parts.last().toInt(); + Version v; + v.major = majorVersion; + v.minor = minorVersion; + currentVersionProfile.version = v; + + } else if (deprecatedRegExp.indexIn(line) != -1) { + // Extract the OpenGL version in which this function was deprecated. + // If it is OpenGL 3.1 then it must be a compatibility profile function + QString deprecatedVersion = deprecatedRegExp.cap(1).simplified(); + if (deprecatedVersion == QStringLiteral("3.1") && !inDeprecationException(currentFunction.name)) + currentVersionProfile.profile = VersionProfile::CompatibilityProfile; + + } else if (categoryRegExp.indexIn(line) != -1) { + // Extract the category for this function + QString category = categoryRegExp.cap(1).simplified(); + qLegacySpecParserDebug() << " category:" << category; + + if (categoryVersionRegExp.indexIn(category) != -1) { + // Use the version info in the category in preference to the version + // entry as this is more applicable and consistent + int majorVersion = categoryVersionRegExp.cap(1).toInt(); + int minorVersion = categoryVersionRegExp.cap(2).toInt(); + + Version v; + v.major = majorVersion; + v.minor = minorVersion; + currentVersionProfile.version = v; + haveVersionInfo = true; + + } else { + // Make a note of the extension name and tag this function as being part of an extension + qLegacySpecParserDebug() << "Found category =" << category; + currentCategory = category; + acceptCurrentFunctionInExtension = true; + + // See if this category (extension) is in our set of extensions that + // have now been folded into the core feature set + if (extensionsNowInCore.contains(category)) { + currentVersionProfile.version = extensionsNowInCore.value(category); + haveVersionInfo = true; + } else { + acceptCurrentFunctionInCore = false; + } + } + + } else if (extToCoreVersionRegExp.indexIn(line) != -1) { + qLegacySpecParserDebug() << line; + int majorVersion = extToCoreVersionRegExp.cap(1).toInt(); + int minorVersion = extToCoreVersionRegExp.cap(2).toInt(); + extToCoreCurrentVersion.major = majorVersion; + extToCoreCurrentVersion.minor = minorVersion; + + } else if (extToCoreRegExp.indexIn(line) != -1) { + QString extension = extToCoreRegExp.cap(1); + extensionsNowInCore.insert(extension, extToCoreCurrentVersion); + } + } + + m_versions = versions.toList(); + qSort(m_versions); +} + +bool LegacySpecParser::inDeprecationException(const QString &functionName) const +{ + return (functionName == QStringLiteral("TexImage3D")); +} |