blob: 7d145bac2f4c4d1dcb934f980979900709dce04f [file] [log] [blame]
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_TINT_LANG_WGSL_RESOLVER_DEPENDENCY_GRAPH_H_
#define SRC_TINT_LANG_WGSL_RESOLVER_DEPENDENCY_GRAPH_H_
#include <string>
#include <vector>
#include "src/tint/lang/core/access.h"
#include "src/tint/lang/core/builtin.h"
#include "src/tint/lang/core/builtin_value.h"
#include "src/tint/lang/core/function.h"
#include "src/tint/lang/core/interpolation_sampling.h"
#include "src/tint/lang/core/interpolation_type.h"
#include "src/tint/lang/core/texel_format.h"
#include "src/tint/lang/wgsl/ast/module.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
namespace tint::resolver {
/// UnresolvedIdentifier is the variant value used by ResolvedIdentifier
struct UnresolvedIdentifier {
/// Name of the unresolved identifier
std::string name;
};
/// ResolvedIdentifier holds the resolution of an ast::Identifier.
/// Can hold one of:
/// - UnresolvedIdentifier
/// - const ast::TypeDecl* (as const ast::Node*)
/// - const ast::Variable* (as const ast::Node*)
/// - const ast::Function* (as const ast::Node*)
/// - core::Function
/// - core::Access
/// - core::AddressSpace
/// - core::Builtin
/// - core::BuiltinValue
/// - core::InterpolationSampling
/// - core::InterpolationType
/// - core::TexelFormat
class ResolvedIdentifier {
public:
/// Constructor
/// @param value the resolved identifier value
template <typename T>
ResolvedIdentifier(T value) : value_(value) {} // NOLINT(runtime/explicit)
/// @return the UnresolvedIdentifier if the identifier was not resolved
const UnresolvedIdentifier* Unresolved() const {
if (auto n = std::get_if<UnresolvedIdentifier>(&value_)) {
return n;
}
return nullptr;
}
/// @return the node pointer if the ResolvedIdentifier holds an AST node, otherwise nullptr
const ast::Node* Node() const {
if (auto n = std::get_if<const ast::Node*>(&value_)) {
return *n;
}
return nullptr;
}
/// @return the builtin function if the ResolvedIdentifier holds core::Function, otherwise
/// core::Function::kNone
core::Function BuiltinFunction() const {
if (auto n = std::get_if<core::Function>(&value_)) {
return *n;
}
return core::Function::kNone;
}
/// @return the access if the ResolvedIdentifier holds core::Access, otherwise
/// core::Access::kUndefined
core::Access Access() const {
if (auto n = std::get_if<core::Access>(&value_)) {
return *n;
}
return core::Access::kUndefined;
}
/// @return the address space if the ResolvedIdentifier holds core::AddressSpace, otherwise
/// core::AddressSpace::kUndefined
core::AddressSpace AddressSpace() const {
if (auto n = std::get_if<core::AddressSpace>(&value_)) {
return *n;
}
return core::AddressSpace::kUndefined;
}
/// @return the builtin type if the ResolvedIdentifier holds core::Builtin, otherwise
/// core::Builtin::kUndefined
core::Builtin BuiltinType() const {
if (auto n = std::get_if<core::Builtin>(&value_)) {
return *n;
}
return core::Builtin::kUndefined;
}
/// @return the builtin value if the ResolvedIdentifier holds core::BuiltinValue, otherwise
/// core::BuiltinValue::kUndefined
core::BuiltinValue BuiltinValue() const {
if (auto n = std::get_if<core::BuiltinValue>(&value_)) {
return *n;
}
return core::BuiltinValue::kUndefined;
}
/// @return the texel format if the ResolvedIdentifier holds type::InterpolationSampling,
/// otherwise type::InterpolationSampling::kUndefined
core::InterpolationSampling InterpolationSampling() const {
if (auto n = std::get_if<core::InterpolationSampling>(&value_)) {
return *n;
}
return core::InterpolationSampling::kUndefined;
}
/// @return the texel format if the ResolvedIdentifier holds type::InterpolationType,
/// otherwise type::InterpolationType::kUndefined
core::InterpolationType InterpolationType() const {
if (auto n = std::get_if<core::InterpolationType>(&value_)) {
return *n;
}
return core::InterpolationType::kUndefined;
}
/// @return the texel format if the ResolvedIdentifier holds type::TexelFormat, otherwise
/// type::TexelFormat::kUndefined
core::TexelFormat TexelFormat() const {
if (auto n = std::get_if<core::TexelFormat>(&value_)) {
return *n;
}
return core::TexelFormat::kUndefined;
}
/// @param value the value to compare the ResolvedIdentifier to
/// @return true if the ResolvedIdentifier is equal to @p value
template <typename T>
bool operator==(const T& value) const {
if (auto n = std::get_if<T>(&value_)) {
return *n == value;
}
return false;
}
/// @param other the other value to compare to this
/// @return true if this ResolvedIdentifier and @p other are not equal
template <typename T>
bool operator!=(const T& other) const {
return !(*this == other);
}
/// @return a description of the resolved symbol
std::string String() const;
private:
std::variant<UnresolvedIdentifier,
const ast::Node*,
core::Function,
core::Access,
core::AddressSpace,
core::Builtin,
core::BuiltinValue,
core::InterpolationSampling,
core::InterpolationType,
core::TexelFormat>
value_;
};
/// DependencyGraph holds information about module-scope declaration dependency
/// analysis and symbol resolutions.
struct DependencyGraph {
/// Constructor
DependencyGraph();
/// Move-constructor
DependencyGraph(DependencyGraph&&);
/// Destructor
~DependencyGraph();
/// Build() performs symbol resolution and dependency analysis on `module`,
/// populating `output` with the resulting dependency graph.
/// @param module the AST module to analyse
/// @param diagnostics the diagnostic list to populate with errors / warnings
/// @param output the resulting DependencyGraph
/// @returns true on success, false on error
static bool Build(const ast::Module& module, diag::List& diagnostics, DependencyGraph& output);
/// All globals in dependency-sorted order.
Vector<const ast::Node*, 32> ordered_globals;
/// Map of ast::Identifier to a ResolvedIdentifier
Hashmap<const ast::Identifier*, ResolvedIdentifier, 64> resolved_identifiers;
/// Map of ast::Variable to a type, function, or variable that is shadowed by
/// the variable key. A declaration (X) shadows another (Y) if X and Y use
/// the same symbol, and X is declared in a sub-scope of the scope that
/// declares Y.
Hashmap<const ast::Variable*, const ast::Node*, 16> shadows;
};
} // namespace tint::resolver
#endif // SRC_TINT_LANG_WGSL_RESOLVER_DEPENDENCY_GRAPH_H_