| // Copyright 2020 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_READER_SPIRV_NAMER_H_ | 
 | #define SRC_READER_SPIRV_NAMER_H_ | 
 |  | 
 | #include <string> | 
 | #include <unordered_map> | 
 | #include <vector> | 
 |  | 
 | #include "src/reader/spirv/fail_stream.h" | 
 |  | 
 | namespace tint { | 
 | namespace reader { | 
 | namespace spirv { | 
 |  | 
 | /// A Namer maps SPIR-V IDs to strings. | 
 | /// | 
 | /// Sanitization: | 
 | /// Some names are user-suggested, but "sanitized" in the sense that an | 
 | /// unusual character (e.g. invalid for use in WGSL identifiers) is remapped | 
 | /// to a safer character such as an underscore.  Also, sanitized names | 
 | /// never start with an underscore. | 
 | class Namer { | 
 |  public: | 
 |   /// Creates a new namer | 
 |   /// @param fail_stream the error reporting stream | 
 |   explicit Namer(const FailStream& fail_stream); | 
 |   /// Destructor | 
 |   ~Namer(); | 
 |  | 
 |   /// Sanitizes the given string, to replace unusual characters with | 
 |   /// obviously-valid idenfier characters. An empy string yields "empty". | 
 |   /// A sanitized name never starts with an underscore. | 
 |   /// @param suggested_name input string | 
 |   /// @returns sanitized name, suitable for use as an identifier | 
 |   static std::string Sanitize(const std::string& suggested_name); | 
 |  | 
 |   /// Registers a failure. | 
 |   /// @returns a fail stream to accumulate diagnostics. | 
 |   FailStream& Fail() { return fail_stream_.Fail(); } | 
 |  | 
 |   /// @param id the SPIR-V ID | 
 |   /// @returns true if we the given ID already has a registered name. | 
 |   bool HasName(uint32_t id) { | 
 |     return id_to_name_.find(id) != id_to_name_.end(); | 
 |   } | 
 |  | 
 |   /// @param id the SPIR-V ID | 
 |   /// @returns the name for the ID. It must have been registered. | 
 |   const std::string& GetName(uint32_t id) const { | 
 |     return id_to_name_.find(id)->second; | 
 |   } | 
 |  | 
 |   /// Gets a unique name for the ID. If one already exists, then return | 
 |   /// that, otherwise synthesize a name and remember it for later. | 
 |   /// @param id the SPIR-V ID | 
 |   /// @returns a name for the given ID. Generates a name if non exists. | 
 |   const std::string& Name(uint32_t id) { | 
 |     if (!HasName(id)) { | 
 |       SuggestSanitizedName(id, "x_" + std::to_string(id)); | 
 |     } | 
 |     return GetName(id); | 
 |   } | 
 |  | 
 |   /// Gets the registered name for a struct member. If no name has | 
 |   /// been registered for this member, then returns the empty string. | 
 |   /// member index is in bounds. | 
 |   /// @param id the SPIR-V ID of the struct type | 
 |   /// @param member_index the index of the member, counting from 0 | 
 |   /// @returns the registered name for the ID, or an empty string if | 
 |   /// nothing has been registered. | 
 |   std::string GetMemberName(uint32_t id, uint32_t member_index) const; | 
 |  | 
 |   /// Returns an unregistered name based on a given base name. | 
 |   /// @param base_name the base name | 
 |   /// @returns a new name | 
 |   std::string FindUnusedDerivedName(const std::string& base_name) const; | 
 |  | 
 |   /// Returns a newly registered name based on a given base name. | 
 |   /// In the internal table `name_to_id_`, it is mapped to the invalid | 
 |   /// SPIR-V ID 0.  It does not have an entry in `id_to_name_`. | 
 |   /// @param base_name the base name | 
 |   /// @returns a new name | 
 |   std::string MakeDerivedName(const std::string& base_name); | 
 |  | 
 |   /// Records a mapping from the given ID to a name. Emits a failure | 
 |   /// if the ID already has a registered name. | 
 |   /// @param id the SPIR-V ID | 
 |   /// @param name the name to map to the ID | 
 |   /// @returns true if the ID did not have a previously registered name. | 
 |   bool SaveName(uint32_t id, const std::string& name); | 
 |  | 
 |   /// Saves a sanitized name for the given ID, if that ID does not yet | 
 |   /// have a registered name, and if the sanitized name has not already | 
 |   /// been registered to a different ID. | 
 |   /// @param id the SPIR-V ID | 
 |   /// @param suggested_name the suggested name | 
 |   /// @returns true if a name was newly registered for the ID | 
 |   bool SuggestSanitizedName(uint32_t id, const std::string& suggested_name); | 
 |  | 
 |   /// Saves a sanitized name for a member of a struct, if that member | 
 |   /// does not yet have a registered name. | 
 |   /// @param struct_id the SPIR-V ID for the struct | 
 |   /// @param member_index the index of the member inside the struct | 
 |   /// @param suggested_name the suggested name | 
 |   /// @returns true if a name was newly registered | 
 |   bool SuggestSanitizedMemberName(uint32_t struct_id, | 
 |                                   uint32_t member_index, | 
 |                                   const std::string& suggested_name); | 
 |  | 
 |   /// Ensure there are member names registered for members of the given struct | 
 |   /// such that: | 
 |   /// - Each member has a non-empty sanitized name. | 
 |   /// - No two members in the struct have the same name. | 
 |   /// @param struct_id the SPIR-V ID for the struct | 
 |   /// @param num_members the number of members in the struct | 
 |   void ResolveMemberNamesForStruct(uint32_t struct_id, uint32_t num_members); | 
 |  | 
 |  private: | 
 |   FailStream fail_stream_; | 
 |  | 
 |   // Maps an ID to its registered name. | 
 |   std::unordered_map<uint32_t, std::string> id_to_name_; | 
 |   // Maps a name to a SPIR-V ID, or 0 (the case for derived names). | 
 |   std::unordered_map<std::string, uint32_t> name_to_id_; | 
 |  | 
 |   // Maps a struct id and member index to a suggested sanitized name. | 
 |   // If entry k in the vector is an empty string, then a suggestion | 
 |   // was recorded for a higher-numbered index, but not for index k. | 
 |   std::unordered_map<uint32_t, std::vector<std::string>> struct_member_names_; | 
 | }; | 
 |  | 
 | }  // namespace spirv | 
 | }  // namespace reader | 
 | }  // namespace tint | 
 |  | 
 | #endif  // SRC_READER_SPIRV_NAMER_H_ |