| // Copyright 2017-2020 The Verible 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. | |
| #include "verilog/tools/kythe/indexing_facts_tree_extractor.h" | |
| #include <iostream> | |
| #include <string> | |
| #include <vector> | |
| #include "absl/status/status.h" | |
| #include "absl/strings/strip.h" | |
| #include "common/text/concrete_syntax_tree.h" | |
| #include "common/text/tree_context_visitor.h" | |
| #include "common/text/tree_utils.h" | |
| #include "common/util/file_util.h" | |
| #include "common/util/logging.h" | |
| #include "common/util/tree_operations.h" | |
| #include "verilog/CST/class.h" | |
| #include "verilog/CST/declaration.h" | |
| #include "verilog/CST/functions.h" | |
| #include "verilog/CST/identifier.h" | |
| #include "verilog/CST/macro.h" | |
| #include "verilog/CST/module.h" | |
| #include "verilog/CST/net.h" | |
| #include "verilog/CST/package.h" | |
| #include "verilog/CST/parameters.h" | |
| #include "verilog/CST/port.h" | |
| #include "verilog/CST/statement.h" | |
| #include "verilog/CST/tasks.h" | |
| #include "verilog/CST/type.h" | |
| #include "verilog/CST/verilog_matchers.h" | |
| #include "verilog/CST/verilog_nonterminals.h" | |
| #include "verilog/CST/verilog_tree_print.h" | |
| #include "verilog/analysis/verilog_analyzer.h" | |
| #include "verilog/analysis/verilog_project.h" | |
| #include "verilog/tools/kythe/indexing_facts_tree.h" | |
| #include "verilog/tools/kythe/indexing_facts_tree_context.h" | |
| namespace verilog { | |
| namespace kythe { | |
| namespace { | |
| using verible::Symbol; | |
| using verible::SymbolKind; | |
| using verible::SyntaxTreeLeaf; | |
| using verible::SyntaxTreeNode; | |
| using verible::TokenInfo; | |
| using verible::TreeSearchMatch; | |
| struct VerilogExtractionState { | |
| // Multi-file tracker. | |
| VerilogProject* const project; | |
| // Keep track of which files (translation units, includes) have been | |
| // extracted. | |
| std::set<const VerilogSourceFile*> extracted_files; | |
| }; | |
| // This class is used for traversing CST and extracting different indexing | |
| // facts from CST nodes and constructs a tree of indexing facts. | |
| class IndexingFactsTreeExtractor : public verible::TreeContextVisitor { | |
| public: | |
| IndexingFactsTreeExtractor(IndexingFactNode& file_list_facts_tree, | |
| const VerilogSourceFile& source_file, | |
| VerilogExtractionState* extraction_state, | |
| std::vector<absl::Status>* errors) | |
| : file_list_facts_tree_(file_list_facts_tree), | |
| source_file_(source_file), | |
| extraction_state_(extraction_state), | |
| errors_(errors) { | |
| const absl::string_view base = source_file_.GetTextStructure()->Contents(); | |
| root_.Value().AppendAnchor( | |
| // Create the Anchor for file path node. | |
| Anchor(source_file_.ResolvedPath()), | |
| // Create the Anchor for text (code) node. | |
| Anchor(base)); | |
| } | |
| void Visit(const SyntaxTreeLeaf& leaf) final; | |
| void Visit(const SyntaxTreeNode& node) final; | |
| const IndexingFactNode& Root() const { return root_; } | |
| IndexingFactNode TakeRoot() { return std::move(root_); } | |
| private: // methods | |
| // Extracts facts from module, intraface and program declarations. | |
| void ExtractModuleOrInterfaceOrProgram(const SyntaxTreeNode& declaration_node, | |
| IndexingFactType node_type); | |
| // Extracts modules instantiations and creates its corresponding fact tree. | |
| void ExtractModuleInstantiation( | |
| const SyntaxTreeNode& data_declaration_node, | |
| const std::vector<TreeSearchMatch>& gate_instances); | |
| // Extracts endmodule, endinterface, endprogram and creates its corresponding | |
| // fact tree. | |
| void ExtractModuleOrInterfaceOrProgramEnd( | |
| const SyntaxTreeNode& module_declaration_node); | |
| // Extracts module, interface, program headers and creates its corresponding | |
| // fact tree. | |
| void ExtractModuleOrInterfaceOrProgramHeader( | |
| const SyntaxTreeNode& module_declaration_node); | |
| // Extracts modules ports and creates its corresponding fact tree. | |
| // "has_propagated_type" determines if this port is "Non-ANSI" or not. | |
| // e.g "module m(a, b, input c, d)" starting from "c" "has_propagated_type" | |
| // will be true. | |
| void ExtractModulePort(const SyntaxTreeNode& module_port_node, | |
| bool has_propagated_type); | |
| // Extracts "a" from "input a", "output a" and creates its corresponding fact | |
| // tree. | |
| void ExtractInputOutputDeclaration( | |
| const SyntaxTreeNode& identifier_unpacked_dimensions); | |
| // Extracts "a" from "wire a" and creates its corresponding fact tree. | |
| void ExtractNetDeclaration(const SyntaxTreeNode& net_declaration_node); | |
| // Extract package declarations and creates its corresponding facts tree. | |
| void ExtractPackageDeclaration( | |
| const SyntaxTreeNode& package_declaration_node); | |
| // Extract macro definitions and explores its arguments and creates its | |
| // corresponding facts tree. | |
| void ExtractMacroDefinition(const SyntaxTreeNode& preprocessor_definition); | |
| // Extract macro calls and explores its arguments and creates its | |
| // corresponding facts tree. | |
| void ExtractMacroCall(const SyntaxTreeNode& macro_call); | |
| // Extract macro names from "kMacroIdentifiers" which are considered | |
| // references to macros and creates its corresponding facts tree. | |
| void ExtractMacroReference(const SyntaxTreeLeaf& macro_identifier); | |
| // Extracts Include statements and creates its corresponding fact tree. | |
| void ExtractInclude(const SyntaxTreeNode& preprocessor_include); | |
| // Extracts function and creates its corresponding fact tree. | |
| void ExtractFunctionDeclaration( | |
| const SyntaxTreeNode& function_declaration_node); | |
| // Extracts class constructor and creates its corresponding fact tree. | |
| void ExtractClassConstructor(const SyntaxTreeNode& class_constructor); | |
| // Extracts task and creates its corresponding fact tree. | |
| void ExtractTaskDeclaration(const SyntaxTreeNode& task_declaration_node); | |
| // Extracts function or task call and creates its corresponding fact tree. | |
| void ExtractFunctionOrTaskCall(const SyntaxTreeNode& function_call_node); | |
| // Extracts function or task call tagged with "kMethodCallExtension" (treated | |
| // as kFunctionOrTaskCall in facts tree) and creates its corresponding fact | |
| // tree. | |
| void ExtractMethodCallExtension(const SyntaxTreeNode& call_extension_node); | |
| // Extracts members tagged with "kHierarchyExtension" (treated as | |
| // kMemberReference in facts tree) and creates its corresponding fact tree. | |
| void ExtractMemberExtension(const SyntaxTreeNode& hierarchy_extension_node); | |
| // Extracts function or task ports and parameters. | |
| void ExtractFunctionOrTaskOrConstructorPort( | |
| const SyntaxTreeNode& function_declaration_node); | |
| // Extracts classes and creates its corresponding fact tree. | |
| void ExtractClassDeclaration(const SyntaxTreeNode& class_declaration); | |
| // Extracts class instances and creates its corresponding fact tree. | |
| void ExtractClassInstances( | |
| const SyntaxTreeNode& data_declaration, | |
| const std::vector<TreeSearchMatch>& class_instances); | |
| // Extracts primitive types declarations tagged with kRegisterVariable and | |
| // creates its corresponding fact tree. | |
| void ExtractRegisterVariable(const SyntaxTreeNode& register_variable); | |
| // Extracts primitive types declarations tagged with | |
| // kVariableDeclarationAssignment and creates its corresponding fact tree. | |
| void ExtractVariableDeclarationAssignment( | |
| const SyntaxTreeNode& variable_declaration_assignment); | |
| // Extracts enum name and creates its corresponding fact tree. | |
| void ExtractEnumName(const SyntaxTreeNode& enum_name); | |
| // Extracts type declaration preceeded with "typedef" and creates its | |
| // corresponding fact tree. | |
| void ExtractTypeDeclaration(const SyntaxTreeNode& type_declaration); | |
| // Extracts pure virtual functions and creates its corresponding fact tree. | |
| void ExtractPureVirtualFunction(const SyntaxTreeNode& function_prototype); | |
| // Extracts pure virtual tasks and creates its corresponding fact tree. | |
| void ExtractPureVirtualTask(const SyntaxTreeNode& task_prototype); | |
| // Extracts function header and creates its corresponding fact tree. | |
| void ExtractFunctionHeader(const SyntaxTreeNode& function_header, | |
| IndexingFactNode& function_node); | |
| // Extracts task header and creates its corresponding fact tree. | |
| void ExtractTaskHeader(const SyntaxTreeNode& task_header, | |
| IndexingFactNode& task_node); | |
| // Extracts enum type declaration preceeded with "typedef" and creates its | |
| // corresponding fact tree. | |
| void ExtractEnumTypeDeclaration(const SyntaxTreeNode& enum_type_declaration); | |
| // Extracts struct type declaration preceeded with "typedef" and creates its | |
| // corresponding fact tree. | |
| void ExtractStructUnionTypeDeclaration(const SyntaxTreeNode& type_declaration, | |
| const SyntaxTreeNode& struct_type); | |
| // Extracts struct declaration and creates its corresponding fact tree. | |
| void ExtractStructUnionDeclaration( | |
| const SyntaxTreeNode& struct_type, | |
| const std::vector<TreeSearchMatch>& variables_matched); | |
| // Extracts struct and union members and creates its corresponding fact tree. | |
| void ExtractDataTypeImplicitIdDimensions( | |
| const SyntaxTreeNode& data_type_implicit_id_dimensions); | |
| // Extracts variable definitions preceeded with some data type and creates its | |
| // corresponding fact tree. | |
| // e.g "some_type var1;" | |
| void ExtractTypedVariableDefinition( | |
| const Symbol& type_identifier, | |
| const std::vector<TreeSearchMatch>& variables_matched); | |
| // Extracts leaves tagged with SymbolIdentifier and creates its facts | |
| // tree. This should only be reached in case of free variable references. | |
| // e.g "assign out = in & in2." | |
| // Other extraction functions should terminate in case the inner | |
| // SymbolIdentifiers are extracted. | |
| void ExtractSymbolIdentifier(const SyntaxTreeLeaf& symbol_identifier); | |
| // Extracts nodes tagged with "kUnqualifiedId". | |
| void ExtractUnqualifiedId(const SyntaxTreeNode& unqualified_id); | |
| // Extracts parameter declarations and creates its corresponding fact tree. | |
| void ExtractParamDeclaration(const SyntaxTreeNode& param_declaration); | |
| // Extracts module instantiation named ports and creates its corresponding | |
| // fact tree. | |
| void ExtractModuleNamedPort(const SyntaxTreeNode& actual_named_port); | |
| // Extracts package imports and creates its corresponding fact tree. | |
| void ExtractPackageImport(const SyntaxTreeNode& package_import_item); | |
| // Extracts qualified ids and creates its corresponding fact tree. | |
| // e.g "pkg::member" or "class::member". | |
| void ExtractQualifiedId(const SyntaxTreeNode& qualified_id); | |
| // Extracts initializations in for loop and creates its corresponding fact | |
| // tree. e.g from "for(int i = 0, j = k; ...)" extracts "i", "j" and "k". | |
| void ExtractForInitialization(const SyntaxTreeNode& for_initialization); | |
| // Extracts param references and the actual references names. | |
| // e.g from "counter #(.N(r))" extracts "N". | |
| void ExtractParamByName(const SyntaxTreeNode& param_by_name); | |
| // Extracts new scope and assign unique id to it. | |
| // specifically, intended for conditional/loop generate constructs. | |
| void ExtractAnonymousScope(const SyntaxTreeNode& node); | |
| // Determines how to deal with the given data declaration node as it may be | |
| // module instance, class instance or primitive variable. | |
| void ExtractDataDeclaration(const SyntaxTreeNode& data_declaration); | |
| // Moves the anchors and children from the the last extracted node in | |
| // "facts_tree_context_", adds them to the new_node and pops remove the last | |
| // extracted node. | |
| void MoveAndDeleteLastExtractedNode(IndexingFactNode& new_node); | |
| absl::string_view FileContent() { | |
| return source_file_.GetTextStructure()->Contents(); | |
| } | |
| private: // data members | |
| // The Root of the constructed facts tree. | |
| IndexingFactNode root_{IndexingNodeData(IndexingFactType::kFile)}; | |
| // Keeps track of indexing facts tree ancestors as the visitor traverses CST. | |
| IndexingFactsTreeContext facts_tree_context_; | |
| // "IndexingFactNode" with tag kFileList which holds the extracted indexing | |
| // facts trees of the files in the ordered file list. The extracted files will | |
| // be children of this node and ordered as they are given in the ordered file | |
| // list. | |
| IndexingFactNode& file_list_facts_tree_; | |
| // The current file being extracted. | |
| const VerilogSourceFile& source_file_; | |
| // The project configuration used to find included files. | |
| VerilogExtractionState* const extraction_state_; | |
| // Processing errors. | |
| std::vector<absl::Status>* errors_; | |
| // Counter used as an id for the anonymous scopes. | |
| int next_anonymous_id = 0; | |
| }; | |
| // Given a root to CST this function traverses the tree, extracts and constructs | |
| // the indexing facts tree for one file. | |
| IndexingFactNode BuildIndexingFactsTree( | |
| IndexingFactNode& file_list_facts_tree, | |
| const VerilogSourceFile& source_file, | |
| VerilogExtractionState* extraction_state, | |
| std::vector<absl::Status>* errors) { | |
| VLOG(1) << __FUNCTION__ << ": file: " << source_file; | |
| IndexingFactsTreeExtractor visitor(file_list_facts_tree, source_file, | |
| extraction_state, errors); | |
| if (source_file.Status().ok()) { | |
| const auto& syntax_tree = source_file.GetTextStructure()->SyntaxTree(); | |
| if (syntax_tree != nullptr) { | |
| VLOG(2) << "syntax:\n" << verible::RawTreePrinter(*syntax_tree); | |
| syntax_tree->Accept(&visitor); | |
| } | |
| } | |
| const PrintableIndexingFactNode debug_node( | |
| visitor.Root(), source_file.GetTextStructure()->Contents()); | |
| VLOG(2) << "built facts tree: " << debug_node; | |
| return visitor.TakeRoot(); | |
| } | |
| } // namespace | |
| IndexingFactNode ExtractFiles(absl::string_view file_list_path, | |
| VerilogProject* project, | |
| const std::vector<std::string>& file_names, | |
| std::vector<absl::Status>* errors) { | |
| VLOG(1) << __FUNCTION__; | |
| // Open all of the translation units. | |
| for (absl::string_view file_name : file_names) { | |
| const auto status_or_file = project->OpenTranslationUnit(file_name); | |
| if (!status_or_file.ok()) { | |
| if (errors != nullptr) { | |
| errors->push_back(status_or_file.status()); | |
| } else { | |
| LOG(ERROR) << "Failed to open file " << file_name << ": " | |
| << status_or_file.status(); | |
| } | |
| } | |
| // For now, collect all diagnostics at the end. | |
| // TODO(fangism): offer a mode to exit-early if there are file-not-found | |
| // or read-permission issues (fail-fast, alert-user). | |
| } | |
| // Create a node to hold the path and root of the ordered file list, group | |
| // all the files and acts as a ordered file list of these files. | |
| IndexingFactNode file_list_facts_tree( | |
| IndexingNodeData(IndexingFactType::kFileList, Anchor(file_list_path), | |
| Anchor(project->TranslationUnitRoot()))); | |
| VerilogExtractionState project_extraction_state{project}; | |
| // pre-allocate file nodes with the number of translation units | |
| file_list_facts_tree.Children().reserve(file_names.size()); | |
| for (absl::string_view file_name : file_names) { | |
| auto* translation_unit = project->LookupRegisteredFile(file_name); | |
| if (translation_unit == nullptr) continue; | |
| const auto parse_status = translation_unit->Parse(); | |
| // status is also stored in translation_unit for later retrieval. | |
| if (parse_status.ok()) { | |
| file_list_facts_tree.Children().push_back( | |
| BuildIndexingFactsTree(file_list_facts_tree, *translation_unit, | |
| &project_extraction_state, errors)); | |
| } else { | |
| if (errors != nullptr) { | |
| errors->push_back(parse_status); | |
| } else { | |
| LOG(WARNING) << "Failed to parse file " << file_name << ": " | |
| << parse_status; | |
| } | |
| } | |
| project->RemoveRegisteredFile(file_name); | |
| } | |
| VLOG(1) << "end of " << __FUNCTION__; | |
| return file_list_facts_tree; | |
| } | |
| void IndexingFactsTreeExtractor::Visit(const SyntaxTreeNode& node) { | |
| const auto tag = static_cast<verilog::NodeEnum>(node.Tag().tag); | |
| VLOG(3) << __FUNCTION__ << ", tag: " << tag; | |
| switch (tag) { | |
| case NodeEnum ::kDescriptionList: { | |
| // Adds the current root to facts tree context to keep track of the parent | |
| // node so that it can be used to construct the tree and add children to | |
| // it. | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, &root_); | |
| TreeContextVisitor::Visit(node); | |
| break; | |
| } | |
| case NodeEnum::kInterfaceDeclaration: { | |
| ExtractModuleOrInterfaceOrProgram(node, IndexingFactType::kInterface); | |
| break; | |
| } | |
| case NodeEnum::kModuleDeclaration: { | |
| ExtractModuleOrInterfaceOrProgram(node, IndexingFactType::kModule); | |
| break; | |
| } | |
| case NodeEnum::kProgramDeclaration: { | |
| ExtractModuleOrInterfaceOrProgram(node, IndexingFactType::kProgram); | |
| break; | |
| } | |
| case NodeEnum::kDataDeclaration: { | |
| ExtractDataDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kIdentifierUnpackedDimensions: { | |
| ExtractInputOutputDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum ::kNetDeclaration: { | |
| ExtractNetDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kPackageDeclaration: { | |
| ExtractPackageDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kPreprocessorDefine: { | |
| ExtractMacroDefinition(node); | |
| break; | |
| } | |
| case NodeEnum::kMacroCall: { | |
| ExtractMacroCall(node); | |
| break; | |
| } | |
| case NodeEnum::kFunctionDeclaration: { | |
| ExtractFunctionDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kTaskDeclaration: { | |
| ExtractTaskDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kClassConstructor: { | |
| ExtractClassConstructor(node); | |
| break; | |
| } | |
| case NodeEnum::kFunctionCall: { | |
| ExtractFunctionOrTaskCall(node); | |
| break; | |
| } | |
| case NodeEnum::kMethodCallExtension: { | |
| ExtractMethodCallExtension(node); | |
| break; | |
| } | |
| case NodeEnum::kHierarchyExtension: { | |
| ExtractMemberExtension(node); | |
| break; | |
| } | |
| case NodeEnum::kClassDeclaration: { | |
| ExtractClassDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kParamDeclaration: { | |
| ExtractParamDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kActualNamedPort: { | |
| ExtractModuleNamedPort(node); | |
| break; | |
| } | |
| case NodeEnum::kPackageImportItem: { | |
| ExtractPackageImport(node); | |
| break; | |
| } | |
| case NodeEnum::kQualifiedId: { | |
| ExtractQualifiedId(node); | |
| break; | |
| } | |
| case NodeEnum::kForInitialization: { | |
| ExtractForInitialization(node); | |
| break; | |
| } | |
| case NodeEnum::kDataTypeImplicitIdDimensions: { | |
| ExtractDataTypeImplicitIdDimensions(node); | |
| break; | |
| } | |
| case NodeEnum::kParamByName: { | |
| ExtractParamByName(node); | |
| break; | |
| } | |
| case NodeEnum::kPreprocessorInclude: { | |
| ExtractInclude(node); | |
| break; | |
| } | |
| case NodeEnum::kRegisterVariable: { | |
| ExtractRegisterVariable(node); | |
| break; | |
| } | |
| case NodeEnum::kFunctionPrototype: { | |
| ExtractPureVirtualFunction(node); | |
| break; | |
| } | |
| case NodeEnum::kTaskPrototype: { | |
| ExtractPureVirtualTask(node); | |
| break; | |
| } | |
| case NodeEnum::kVariableDeclarationAssignment: { | |
| ExtractVariableDeclarationAssignment(node); | |
| break; | |
| } | |
| case NodeEnum::kEnumName: { | |
| ExtractEnumName(node); | |
| break; | |
| } | |
| case NodeEnum::kTypeDeclaration: { | |
| ExtractTypeDeclaration(node); | |
| break; | |
| } | |
| case NodeEnum::kLoopGenerateConstruct: | |
| case NodeEnum::kIfClause: | |
| case NodeEnum::kFinalStatement: | |
| case NodeEnum::kInitialStatement: | |
| case NodeEnum::kGenerateElseBody: | |
| case NodeEnum::kElseClause: | |
| case NodeEnum::kGenerateIfClause: | |
| case NodeEnum::kForLoopStatement: | |
| case NodeEnum::kDoWhileLoopStatement: | |
| case NodeEnum::kWhileLoopStatement: | |
| case NodeEnum::kForeachLoopStatement: | |
| case NodeEnum::kRepeatLoopStatement: | |
| case NodeEnum::kForeverLoopStatement: { | |
| ExtractAnonymousScope(node); | |
| break; | |
| } | |
| case NodeEnum::kUnqualifiedId: { | |
| ExtractUnqualifiedId(node); | |
| break; | |
| } | |
| default: { | |
| TreeContextVisitor::Visit(node); | |
| } | |
| } | |
| VLOG(3) << "end of " << __FUNCTION__ << ", tag: " << tag; | |
| } | |
| void IndexingFactsTreeExtractor::Visit(const SyntaxTreeLeaf& leaf) { | |
| switch (leaf.get().token_enum()) { | |
| case verilog_tokentype::SymbolIdentifier: { | |
| ExtractSymbolIdentifier(leaf); | |
| break; | |
| } | |
| default: { | |
| break; | |
| } | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractSymbolIdentifier( | |
| const SyntaxTreeLeaf& symbol_identifier) { | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableReference, | |
| Anchor(symbol_identifier.get(), FileContent()))); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractDataDeclaration( | |
| const SyntaxTreeNode& data_declaration) { | |
| // For module instantiations | |
| const std::vector<TreeSearchMatch> gate_instances = | |
| FindAllGateInstances(data_declaration); | |
| if (!gate_instances.empty()) { | |
| ExtractModuleInstantiation(data_declaration, gate_instances); | |
| return; | |
| } | |
| // For bit, int and classes | |
| const std::vector<TreeSearchMatch> register_variables = | |
| FindAllRegisterVariables(data_declaration); | |
| if (!register_variables.empty()) { | |
| // for classes. | |
| const std::vector<TreeSearchMatch> class_instances = | |
| verible::SearchSyntaxTree(data_declaration, NodekClassNew()); | |
| if (!class_instances.empty()) { | |
| ExtractClassInstances(data_declaration, register_variables); | |
| return; | |
| } | |
| // for struct and union types. | |
| const SyntaxTreeNode* type_node = | |
| GetStructOrUnionOrEnumTypeFromDataDeclaration(data_declaration); | |
| // Ignore if this isn't a struct or union type. | |
| if (type_node != nullptr && | |
| NodeEnum(type_node->Tag().tag) != NodeEnum::kEnumType) { | |
| ExtractStructUnionDeclaration(*type_node, register_variables); | |
| return; | |
| } | |
| // In case "some_type var1". | |
| const Symbol* type_identifier = | |
| GetTypeIdentifierFromDataDeclaration(data_declaration); | |
| if (type_identifier != nullptr) { | |
| ExtractTypedVariableDefinition(*type_identifier, register_variables); | |
| return; | |
| } | |
| // Traverse the children to extract inner nodes. | |
| TreeContextVisitor::Visit(data_declaration); | |
| return; | |
| } | |
| const std::vector<TreeSearchMatch> variable_declaration_assign = | |
| FindAllVariableDeclarationAssignment(data_declaration); | |
| if (!variable_declaration_assign.empty()) { | |
| // for classes. | |
| const std::vector<TreeSearchMatch> class_instances = | |
| verible::SearchSyntaxTree(data_declaration, NodekClassNew()); | |
| if (!class_instances.empty()) { | |
| ExtractClassInstances(data_declaration, variable_declaration_assign); | |
| return; | |
| } | |
| // for struct and union types. | |
| const SyntaxTreeNode* type_node = | |
| GetStructOrUnionOrEnumTypeFromDataDeclaration(data_declaration); | |
| // Ignore if this isn't a struct or union type. | |
| if (type_node != nullptr && | |
| NodeEnum(type_node->Tag().tag) != NodeEnum::kEnumType) { | |
| ExtractStructUnionDeclaration(*type_node, variable_declaration_assign); | |
| return; | |
| } | |
| // In case "some_type var1". | |
| const Symbol* type_identifier = | |
| GetTypeIdentifierFromDataDeclaration(data_declaration); | |
| if (type_identifier != nullptr) { | |
| ExtractTypedVariableDefinition(*type_identifier, | |
| variable_declaration_assign); | |
| return; | |
| } | |
| // Traverse the children to extract inner nodes. | |
| TreeContextVisitor::Visit(data_declaration); | |
| return; | |
| } | |
| // Traverse the children to extract inner nodes. | |
| TreeContextVisitor::Visit(data_declaration); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractTypedVariableDefinition( | |
| const Symbol& type_identifier, | |
| const std::vector<TreeSearchMatch>& variables_matche) { | |
| IndexingFactNode type_node( | |
| IndexingNodeData{IndexingFactType::kDataTypeReference}); | |
| type_identifier.Accept(this); | |
| MoveAndDeleteLastExtractedNode(type_node); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, &type_node); | |
| for (const TreeSearchMatch& variable : variables_matche) { | |
| variable.match->Accept(this); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(type_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModuleOrInterfaceOrProgram( | |
| const SyntaxTreeNode& declaration_node, IndexingFactType node_type) { | |
| IndexingFactNode facts_node(IndexingNodeData{node_type}); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &facts_node); | |
| ExtractModuleOrInterfaceOrProgramHeader(declaration_node); | |
| ExtractModuleOrInterfaceOrProgramEnd(declaration_node); | |
| const SyntaxTreeNode* item_list = GetModuleItemList(declaration_node); | |
| if (item_list) Visit(*item_list); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(facts_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModuleOrInterfaceOrProgramHeader( | |
| const SyntaxTreeNode& module_declaration_node) { | |
| // Extract module name e.g from "module my_module" extracts "my_module". | |
| const SyntaxTreeLeaf* module_name_leaf = | |
| GetModuleName(module_declaration_node); | |
| if (!module_name_leaf) return; | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(module_name_leaf->get(), FileContent())); | |
| // Extract parameters if exist. | |
| const SyntaxTreeNode* param_declaration_list = | |
| GetParamDeclarationListFromModuleDeclaration(module_declaration_node); | |
| if (param_declaration_list != nullptr) { | |
| Visit(*param_declaration_list); | |
| } | |
| // Extracting module ports e.g. (input a, input b). | |
| // Ports are treated as children of the module. | |
| const SyntaxTreeNode* port_list = | |
| GetModulePortDeclarationList(module_declaration_node); | |
| if (port_list == nullptr) { | |
| return; | |
| } | |
| // This boolean is used to distinguish between ANSI and Non-ANSI module | |
| // ports. e.g in this case: module m(a, b); has_propagated_type will be | |
| // false as no type has been countered. | |
| // | |
| // in case like: | |
| // module m(a, b, input x, y) | |
| // for "a", "b" the boolean will be false but for "x", "y" the boolean will | |
| // be true. | |
| // | |
| // The boolean is used to determine whether this the fact for this variable | |
| // should be a reference or a defintiion. | |
| bool has_propagated_type = false; | |
| for (const auto& port : port_list->children()) { | |
| if (port->Kind() == SymbolKind::kLeaf) continue; | |
| const SyntaxTreeNode& port_node = SymbolCastToNode(*port); | |
| const auto tag = static_cast<verilog::NodeEnum>(port_node.Tag().tag); | |
| if (tag == NodeEnum::kPortDeclaration) { | |
| has_propagated_type = true; | |
| ExtractModulePort(port_node, has_propagated_type); | |
| } else if (tag == NodeEnum::kPort) { | |
| const SyntaxTreeNode* ref_port = GetPortReferenceFromPort(port_node); | |
| if (ref_port) ExtractModulePort(*ref_port, has_propagated_type); | |
| } | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModulePort( | |
| const SyntaxTreeNode& module_port_node, bool has_propagated_type) { | |
| const auto tag = static_cast<verilog::NodeEnum>(module_port_node.Tag().tag); | |
| // For extracting cases like: | |
| // module m(input a, input b); | |
| if (tag == NodeEnum::kPortDeclaration) { | |
| const SyntaxTreeLeaf* leaf = | |
| GetIdentifierFromModulePortDeclaration(module_port_node); | |
| if (!leaf) return; | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(leaf->get(), FileContent()))); | |
| } else if (tag == NodeEnum::kPortReference) { | |
| // For extracting Non-ANSI style ports: | |
| // module m(a, b); | |
| const SyntaxTreeLeaf* leaf = | |
| GetIdentifierFromPortReference(module_port_node); | |
| if (!leaf) return; | |
| if (has_propagated_type) { | |
| // Check if the last type was not a primitive type. | |
| // e.g module (interface_type x, y). | |
| if (is_leaf(facts_tree_context_.top()) || | |
| facts_tree_context_.top() | |
| .Children() | |
| .back() | |
| .Value() | |
| .GetIndexingFactType() != | |
| IndexingFactType::kDataTypeReference) { | |
| // Append this as a variable definition. | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(leaf->get(), FileContent()))); | |
| } else { | |
| // Append this as a child to previous kDataTypeReference. | |
| facts_tree_context_.top().Children().back().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(leaf->get(), FileContent()))); | |
| } | |
| } else { | |
| // In case no preceeded data type. | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableReference, | |
| Anchor(leaf->get(), FileContent()))); | |
| } | |
| } | |
| // Extract unpacked and packed dimensions. | |
| for (const auto& child : module_port_node.children()) { | |
| if (child == nullptr || child->Kind() == SymbolKind::kLeaf) { | |
| continue; | |
| } | |
| const auto tag = static_cast<verilog::NodeEnum>(child->Tag().tag); | |
| if (tag == NodeEnum::kUnqualifiedId) { | |
| continue; | |
| } | |
| if (tag == NodeEnum::kDataType) { | |
| const SyntaxTreeNode* data_type = GetTypeIdentifierFromDataType(*child); | |
| // If not null this is a non primitive type and should create | |
| // kDataTypeReference node for it. | |
| // This data_type may be some class or interface type. | |
| if (data_type != nullptr) { | |
| // Create a node for this data type and append its anchor. | |
| IndexingFactNode data_type_node( | |
| IndexingNodeData{IndexingFactType::kDataTypeReference}); | |
| data_type->Accept(this); | |
| MoveAndDeleteLastExtractedNode(data_type_node); | |
| // Make the current port node child of this data type, remove it from | |
| // the top node and push the kDataTypeRefernce Node. | |
| data_type_node.Children().push_back( | |
| std::move(facts_tree_context_.top().Children().back())); | |
| facts_tree_context_.top().Children().back() = std::move(data_type_node); | |
| continue; | |
| } | |
| } | |
| child->Accept(this); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModuleNamedPort( | |
| const SyntaxTreeNode& actual_named_port) { | |
| const SyntaxTreeLeaf* named_port = GetActualNamedPortName(actual_named_port); | |
| if (!named_port) return; | |
| IndexingFactNode actual_port_node( | |
| IndexingNodeData(IndexingFactType::kModuleNamedPort, | |
| Anchor(named_port->get(), FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &actual_port_node); | |
| const Symbol* paren_group = GetActualNamedPortParenGroup(actual_named_port); | |
| if (paren_group != nullptr) { | |
| paren_group->Accept(this); | |
| } | |
| } | |
| facts_tree_context_.top().Children().emplace_back( | |
| std::move(actual_port_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractInputOutputDeclaration( | |
| const SyntaxTreeNode& identifier_unpacked_dimension) { | |
| const SyntaxTreeLeaf* port_name_leaf = | |
| GetSymbolIdentifierFromIdentifierUnpackedDimensions( | |
| identifier_unpacked_dimension); | |
| if (port_name_leaf) { | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(port_name_leaf->get(), FileContent()))); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModuleOrInterfaceOrProgramEnd( | |
| const SyntaxTreeNode& module_declaration_node) { | |
| const SyntaxTreeLeaf* module_name = | |
| GetModuleEndLabel(module_declaration_node); | |
| if (module_name != nullptr) { | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(module_name->get(), FileContent())); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractModuleInstantiation( | |
| const SyntaxTreeNode& data_declaration_node, | |
| const std::vector<TreeSearchMatch>& gate_instances) { | |
| IndexingFactNode type_node( | |
| IndexingNodeData{IndexingFactType::kDataTypeReference}); | |
| // Extract module type name. | |
| const Symbol* type = | |
| GetTypeIdentifierFromDataDeclaration(data_declaration_node); | |
| if (type == nullptr) { | |
| return; | |
| } | |
| // Extract module instance type and parameters. | |
| type->Accept(this); | |
| MoveAndDeleteLastExtractedNode(type_node); | |
| // Module instantiations (data declarations) may declare multiple instances | |
| // sharing the same type in a single statement e.g. bar b1(), b2(). | |
| // | |
| // Loop through each instance and associate each declared id with the same | |
| // type and create its corresponding facts tree node. | |
| for (const TreeSearchMatch& instance : gate_instances) { | |
| IndexingFactNode module_instance_node( | |
| IndexingNodeData{IndexingFactType::kModuleInstance}); | |
| const TokenInfo* variable_name = | |
| GetModuleInstanceNameTokenInfoFromGateInstance(*instance.match); | |
| if (variable_name) { | |
| module_instance_node.Value().AppendAnchor( | |
| Anchor(*variable_name, FileContent())); | |
| } | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &module_instance_node); | |
| const SyntaxTreeNode* paren_group = | |
| GetParenGroupFromModuleInstantiation(*instance.match); | |
| if (paren_group) Visit(*paren_group); | |
| } | |
| type_node.Children().push_back(std::move(module_instance_node)); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(type_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractNetDeclaration( | |
| const SyntaxTreeNode& net_declaration_node) { | |
| // Nets are treated as children of the enclosing parent. | |
| // Net declarations may declare multiple instances sharing the same type in | |
| // a single statement. | |
| const std::vector<const TokenInfo*> identifiers = | |
| GetIdentifiersFromNetDeclaration(net_declaration_node); | |
| // Loop through each instance and associate each declared id with the same | |
| // type. | |
| for (const TokenInfo* wire_token_info : identifiers) { | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(*wire_token_info, FileContent()))); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractPackageDeclaration( | |
| const SyntaxTreeNode& package_declaration_node) { | |
| IndexingFactNode package_node(IndexingNodeData{IndexingFactType::kPackage}); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &package_node); | |
| // Extract package name. | |
| const SyntaxTreeLeaf* pname = GetPackageNameLeaf(package_declaration_node); | |
| if (pname) { | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(pname->get(), FileContent())); | |
| } | |
| // Extract package name after endpackage if exists. | |
| const SyntaxTreeLeaf* package_end_name = | |
| GetPackageNameEndLabel(package_declaration_node); | |
| if (package_end_name != nullptr) { | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(package_end_name->get(), FileContent())); | |
| } | |
| // Visit package body it exists. | |
| const Symbol* package_item_list = | |
| GetPackageItemList(package_declaration_node); | |
| if (package_item_list != nullptr) { | |
| package_item_list->Accept(this); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(package_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractMacroDefinition( | |
| const SyntaxTreeNode& preprocessor_definition) { | |
| const SyntaxTreeLeaf* macro_name = GetMacroName(preprocessor_definition); | |
| if (!macro_name) return; | |
| IndexingFactNode macro_node(IndexingNodeData( | |
| IndexingFactType::kMacro, Anchor(macro_name->get(), FileContent()))); | |
| // TODO(fangism): access directly, instead of searching. | |
| const std::vector<TreeSearchMatch> args = | |
| FindAllMacroDefinitionsArgs(preprocessor_definition); | |
| for (const TreeSearchMatch& arg : args) { | |
| const SyntaxTreeLeaf* macro_arg_name = GetMacroArgName(*arg.match); | |
| if (macro_arg_name) { | |
| macro_node.Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(macro_arg_name->get(), FileContent()))); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(macro_node)); | |
| } | |
| Anchor GetMacroAnchorFromTokenInfo(const TokenInfo& macro_token_info, | |
| absl::string_view file_content) { | |
| // Strip the prefix "`". | |
| // e.g. | |
| // `define TEN 0 | |
| // `TEN --> removes the ` | |
| const absl::string_view macro_name = | |
| absl::StripPrefix(macro_token_info.text(), "`"); | |
| int begin = std::distance(file_content.begin(), macro_name.begin()); | |
| return Anchor(macro_name, begin, macro_name.size()); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractMacroCall( | |
| const SyntaxTreeNode& macro_call) { | |
| const TokenInfo* macro_call_name_token = GetMacroCallId(macro_call); | |
| if (!macro_call_name_token) return; | |
| IndexingFactNode macro_node(IndexingNodeData( | |
| IndexingFactType::kMacroCall, | |
| GetMacroAnchorFromTokenInfo(*macro_call_name_token, FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| ¯o_node); | |
| const SyntaxTreeNode* macro_call_args = GetMacroCallArgs(macro_call); | |
| if (macro_call_args) Visit(*macro_call_args); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(macro_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractMacroReference( | |
| const SyntaxTreeLeaf& macro_identifier) { | |
| facts_tree_context_.top().Children().emplace_back(IndexingNodeData( | |
| IndexingFactType::kMacroCall, | |
| GetMacroAnchorFromTokenInfo(macro_identifier.get(), FileContent()))); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractClassConstructor( | |
| const SyntaxTreeNode& class_constructor) { | |
| const SyntaxTreeLeaf* new_keyword = | |
| GetNewKeywordFromClassConstructor(class_constructor); | |
| if (!new_keyword) return; | |
| IndexingFactNode constructor_node( | |
| IndexingNodeData(IndexingFactType::kConstructor, | |
| Anchor(new_keyword->get(), FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &constructor_node); | |
| // Extract ports. | |
| ExtractFunctionOrTaskOrConstructorPort(class_constructor); | |
| // Extract constructor body. | |
| const SyntaxTreeNode* constructor_body = | |
| GetClassConstructorStatementList(class_constructor); | |
| if (constructor_body) Visit(*constructor_body); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(constructor_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractPureVirtualFunction( | |
| const SyntaxTreeNode& function_prototype) { | |
| IndexingFactNode function_node( | |
| IndexingNodeData{IndexingFactType::kFunctionOrTaskForwardDeclaration}); | |
| // Extract function header. | |
| const SyntaxTreeNode* function_header = | |
| GetFunctionPrototypeHeader(function_prototype); | |
| if (function_header) ExtractFunctionHeader(*function_header, function_node); | |
| facts_tree_context_.top().Children().push_back(std::move(function_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractPureVirtualTask( | |
| const SyntaxTreeNode& task_prototype) { | |
| IndexingFactNode task_node( | |
| IndexingNodeData{IndexingFactType::kFunctionOrTaskForwardDeclaration}); | |
| // Extract task header. | |
| const SyntaxTreeNode* task_header = GetTaskPrototypeHeader(task_prototype); | |
| if (task_header) ExtractTaskHeader(*task_header, task_node); | |
| facts_tree_context_.top().Children().push_back(std::move(task_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractFunctionDeclaration( | |
| const SyntaxTreeNode& function_declaration_node) { | |
| IndexingFactNode function_node( | |
| IndexingNodeData{IndexingFactType::kFunctionOrTask}); | |
| // Extract function header. | |
| const SyntaxTreeNode* function_header = | |
| GetFunctionHeader(function_declaration_node); | |
| if (function_header) ExtractFunctionHeader(*function_header, function_node); | |
| { | |
| // Extract function body. | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &function_node); | |
| const SyntaxTreeNode* function_body = | |
| GetFunctionBlockStatementList(function_declaration_node); | |
| if (function_body) Visit(*function_body); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(function_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractTaskDeclaration( | |
| const SyntaxTreeNode& task_declaration_node) { | |
| IndexingFactNode task_node( | |
| IndexingNodeData{IndexingFactType::kFunctionOrTask}); | |
| // Extract task header. | |
| const SyntaxTreeNode* task_header = GetTaskHeader(task_declaration_node); | |
| if (task_header) ExtractTaskHeader(*task_header, task_node); | |
| { | |
| // Extract task body. | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, &task_node); | |
| const SyntaxTreeNode* task_body = | |
| GetTaskStatementList(task_declaration_node); | |
| if (task_body) Visit(*task_body); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(task_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractFunctionHeader( | |
| const SyntaxTreeNode& function_header, IndexingFactNode& function_node) { | |
| // Extract function name. | |
| const Symbol* function_name = GetFunctionHeaderId(function_header); | |
| if (function_name == nullptr) { | |
| return; | |
| } | |
| function_name->Accept(this); | |
| MoveAndDeleteLastExtractedNode(function_node); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &function_node); | |
| // Extract function ports. | |
| ExtractFunctionOrTaskOrConstructorPort(function_header); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractTaskHeader( | |
| const SyntaxTreeNode& task_header, IndexingFactNode& task_node) { | |
| // Extract task name. | |
| const Symbol* task_name = GetTaskHeaderId(task_header); | |
| if (task_name == nullptr) { | |
| return; | |
| } | |
| task_name->Accept(this); | |
| MoveAndDeleteLastExtractedNode(task_node); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, &task_node); | |
| // Extract task ports. | |
| ExtractFunctionOrTaskOrConstructorPort(task_header); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractFunctionOrTaskOrConstructorPort( | |
| const SyntaxTreeNode& function_declaration_node) { | |
| const std::vector<TreeSearchMatch> ports = | |
| FindAllTaskFunctionPortDeclarations(function_declaration_node); | |
| for (const TreeSearchMatch& port : ports) { | |
| const Symbol* port_type = GetTypeOfTaskFunctionPortItem(*port.match); | |
| if (port_type != nullptr) { | |
| // port variable name. | |
| const SyntaxTreeLeaf* port_identifier = | |
| GetIdentifierFromTaskFunctionPortItem(*port.match); | |
| if (!port_identifier) continue; | |
| // variable identifier node. | |
| IndexingFactNode variable_node( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(port_identifier->get(), FileContent()))); | |
| // if this port has struct/union/enum data type. | |
| const SyntaxTreeNode* struct_type = | |
| GetStructOrUnionOrEnumTypeFromDataType(*port_type); | |
| if (struct_type != nullptr) { | |
| // Then this data type is struct/union/enum | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| struct_type->Accept(this); | |
| } | |
| facts_tree_context_.top().Children().push_back( | |
| std::move(variable_node)); | |
| continue; | |
| } | |
| const SyntaxTreeNode* type_identifier = | |
| GetTypeIdentifierFromDataType(*port_type); | |
| if (type_identifier == nullptr) { | |
| // Then this is a primitive data type. | |
| // e.g "task f1(int x);" | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| const SyntaxTreeNode* packed_dim = | |
| GetPackedDimensionFromDataType(*port_type); | |
| if (packed_dim != nullptr) { | |
| packed_dim->Accept(this); | |
| } | |
| const SyntaxTreeNode* unpacked_dimension = | |
| GetUnpackedDimensionsFromTaskFunctionPortItem(*port.match); | |
| if (unpacked_dimension) unpacked_dimension->Accept(this); | |
| } | |
| facts_tree_context_.top().Children().push_back( | |
| std::move(variable_node)); | |
| continue; | |
| } | |
| // else this is a user defined type. | |
| // e.g "task f1(some_class var1);". | |
| IndexingFactNode type_node( | |
| IndexingNodeData{IndexingFactType::kDataTypeReference}); | |
| type_identifier->Accept(this); | |
| MoveAndDeleteLastExtractedNode(type_node); | |
| type_node.Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(port_identifier->get(), FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &type_node); | |
| const SyntaxTreeNode* packed_dim = | |
| GetPackedDimensionFromDataType(*port_type); | |
| if (packed_dim != nullptr) { | |
| packed_dim->Accept(this); | |
| } | |
| const SyntaxTreeNode* unpacked_dimension = | |
| GetUnpackedDimensionsFromTaskFunctionPortItem(*port.match); | |
| if (unpacked_dimension) unpacked_dimension->Accept(this); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(type_node)); | |
| } | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractFunctionOrTaskCall( | |
| const SyntaxTreeNode& function_call_node) { | |
| IndexingFactNode function_node( | |
| IndexingNodeData{IndexingFactType::kFunctionCall}); | |
| // Extract function or task name. | |
| // It can be single or preceeded with a pkg or class names. | |
| const SyntaxTreeNode* identifier = | |
| GetIdentifiersFromFunctionCall(function_call_node); | |
| if (identifier == nullptr) { | |
| return; | |
| } | |
| Visit(*identifier); | |
| // Move the data from the last extracted node to the current node and delete | |
| // that last node. | |
| MoveAndDeleteLastExtractedNode(function_node); | |
| // Terminate if no function name is found. | |
| // in case of built-in functions: "sin(x)"; | |
| if (function_node.Value().Anchors().empty()) { | |
| return; | |
| } | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &function_node); | |
| const SyntaxTreeNode* arguments = GetParenGroupFromCall(function_call_node); | |
| // Extract function or task parameters. | |
| if (arguments) Visit(*arguments); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(function_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractMethodCallExtension( | |
| const SyntaxTreeNode& call_extension_node) { | |
| IndexingFactNode function_node( | |
| IndexingNodeData{IndexingFactType::kFunctionCall}); | |
| // Move the data from the last extracted node to the current node and delete | |
| // that last node. | |
| MoveAndDeleteLastExtractedNode(function_node); | |
| // Terminate if no function name is found. | |
| // in case of built-in functions: "q.sort()"; | |
| if (function_node.Value().Anchors().empty()) { | |
| return; | |
| } | |
| { | |
| const SyntaxTreeLeaf* fun_call = | |
| GetFunctionCallNameFromCallExtension(call_extension_node); | |
| if (fun_call) { | |
| function_node.Value().AppendAnchor( | |
| Anchor(fun_call->get(), FileContent())); | |
| } | |
| } | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &function_node); | |
| const SyntaxTreeNode* arguments = | |
| GetParenGroupFromCallExtension(call_extension_node); | |
| // parameters. | |
| if (arguments) Visit(*arguments); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(function_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractMemberExtension( | |
| const SyntaxTreeNode& hierarchy_extension_node) { | |
| IndexingFactNode member_node( | |
| IndexingNodeData{IndexingFactType::kMemberReference}); | |
| // Move the data from the last extracted node to the current node and delete | |
| // that last node. | |
| MoveAndDeleteLastExtractedNode(member_node); | |
| { | |
| const verible::SyntaxTreeLeaf* unqualified = | |
| GetUnqualifiedIdFromHierarchyExtension(hierarchy_extension_node); | |
| // member name | |
| if (unqualified) { | |
| member_node.Value().AppendAnchor( | |
| Anchor(unqualified->get(), FileContent())); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(member_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractClassDeclaration( | |
| const SyntaxTreeNode& class_declaration) { | |
| IndexingFactNode class_node(IndexingNodeData{IndexingFactType::kClass}); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &class_node); | |
| // Extract class name. | |
| const SyntaxTreeLeaf* class_name = GetClassName(class_declaration); | |
| if (class_name) { | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(class_name->get(), FileContent())); | |
| } | |
| // Extract class name after endclass. | |
| const SyntaxTreeLeaf* class_end_name = GetClassEndLabel(class_declaration); | |
| if (class_end_name != nullptr) { | |
| facts_tree_context_.top().Value().AppendAnchor( | |
| Anchor(class_end_name->get(), FileContent())); | |
| } | |
| const SyntaxTreeNode* param_list = | |
| GetParamDeclarationListFromClassDeclaration(class_declaration); | |
| if (param_list != nullptr) { | |
| Visit(*param_list); | |
| } | |
| const SyntaxTreeNode* extended_class = GetExtendedClass(class_declaration); | |
| if (extended_class != nullptr) { | |
| IndexingFactNode extends_node( | |
| IndexingNodeData{IndexingFactType::kExtends}); | |
| // In case of => class X extends Y. | |
| if (NodeEnum(extended_class->Tag().tag) == NodeEnum::kUnqualifiedId) { | |
| extends_node.Value().AppendAnchor(Anchor( | |
| AutoUnwrapIdentifier(*extended_class)->get(), FileContent())); | |
| } else { | |
| // In case of => class X extends pkg1::Y. | |
| ExtractQualifiedId(*extended_class); | |
| // Construct extends node from the last node which is kMemberReference, | |
| // remove kMemberReference node and append the new extends node. | |
| MoveAndDeleteLastExtractedNode(extends_node); | |
| } | |
| // Add the extends node as a child of this class node. | |
| class_node.Children().push_back(std::move(extends_node)); | |
| } | |
| // Visit class body. | |
| const SyntaxTreeNode* class_item_list = GetClassItemList(class_declaration); | |
| if (class_item_list) Visit(*class_item_list); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(class_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractClassInstances( | |
| const SyntaxTreeNode& data_declaration_node, | |
| const std::vector<TreeSearchMatch>& class_instances) { | |
| IndexingFactNode type_node( | |
| IndexingNodeData{IndexingFactType::kDataTypeReference}); | |
| const Symbol* type = | |
| GetTypeIdentifierFromDataDeclaration(data_declaration_node); | |
| if (type == nullptr) { | |
| return; | |
| } | |
| // Extract class type and parameters. | |
| type->Accept(this); | |
| MoveAndDeleteLastExtractedNode(type_node); | |
| // Class instances may may appear as multiple instances sharing the same | |
| // type in a single statement e.g. myClass b1 = new, b2 = new. LRM 8.8 Typed | |
| // constructor calls | |
| // | |
| // Loop through each instance and associate each declared id with the same | |
| // type and create its corresponding facts tree node. | |
| for (const TreeSearchMatch& instance : class_instances) { | |
| IndexingFactNode class_instance_node( | |
| IndexingNodeData{IndexingFactType::kClassInstance}); | |
| // Re-use the kRegisterVariable and kVariableDeclarationAssignment tag | |
| // resolver. | |
| instance.match->Accept(this); | |
| MoveAndDeleteLastExtractedNode(class_instance_node); | |
| type_node.Children().push_back(std::move(class_instance_node)); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(type_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractRegisterVariable( | |
| const SyntaxTreeNode& register_variable) { | |
| const TokenInfo* instance_name = | |
| GetInstanceNameTokenInfoFromRegisterVariable(register_variable); | |
| if (!instance_name) return; | |
| IndexingFactNode variable_node( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(*instance_name, FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| const SyntaxTreeNode* unpacked_dimension = | |
| GetUnpackedDimensionFromRegisterVariable(register_variable); | |
| if (unpacked_dimension) Visit(*unpacked_dimension); | |
| const SyntaxTreeNode* expression = | |
| GetTrailingExpressionFromRegisterVariable(register_variable); | |
| if (expression != nullptr) { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| // Visit Trailing Assignment Expression. | |
| Visit(*expression); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(variable_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractVariableDeclarationAssignment( | |
| const SyntaxTreeNode& variable_declaration_assignment) { | |
| const SyntaxTreeLeaf* unqualified_id = | |
| GetUnqualifiedIdFromVariableDeclarationAssignment( | |
| variable_declaration_assignment); | |
| if (!unqualified_id) return; | |
| IndexingFactNode variable_node( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(unqualified_id->get(), FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| const SyntaxTreeNode* unpacked_dimension = | |
| GetUnpackedDimensionFromVariableDeclarationAssign( | |
| variable_declaration_assignment); | |
| if (unpacked_dimension) Visit(*unpacked_dimension); | |
| const SyntaxTreeNode* expression = | |
| GetTrailingExpressionFromVariableDeclarationAssign( | |
| variable_declaration_assignment); | |
| if (expression != nullptr) { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| // Visit Trailing Assignment Expression. | |
| Visit(*expression); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(variable_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractUnqualifiedId( | |
| const SyntaxTreeNode& unqualified_id) { | |
| const SyntaxTreeLeaf* identifier = AutoUnwrapIdentifier(unqualified_id); | |
| if (identifier == nullptr) { | |
| return; | |
| } | |
| switch (identifier->get().token_enum()) { | |
| case verilog_tokentype::MacroIdentifier: { | |
| ExtractMacroReference(*identifier); | |
| break; | |
| } | |
| case verilog_tokentype::SymbolIdentifier: { | |
| IndexingFactNode variable_reference( | |
| IndexingNodeData{IndexingFactType::kVariableReference}); | |
| ExtractSymbolIdentifier(*identifier); | |
| MoveAndDeleteLastExtractedNode(variable_reference); | |
| const SyntaxTreeNode* param_list = | |
| GetParamListFromUnqualifiedId(unqualified_id); | |
| if (param_list != nullptr) { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_reference); | |
| param_list->Accept(this); | |
| } | |
| facts_tree_context_.top().Children().push_back( | |
| std::move(variable_reference)); | |
| break; | |
| } | |
| default: { | |
| break; | |
| } | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractParamDeclaration( | |
| const SyntaxTreeNode& param_declaration) { | |
| IndexingFactNode param_node( | |
| IndexingNodeData{IndexingFactType::kParamDeclaration}); | |
| const SyntaxTreeNode* type_assignment = | |
| GetTypeAssignmentFromParamDeclaration(param_declaration); | |
| // Parameters can be in two cases: | |
| // 1st => parameter type x; | |
| if (type_assignment != nullptr) { | |
| param_node.Value().AppendAnchor(Anchor( | |
| ABSL_DIE_IF_NULL(GetIdentifierLeafFromTypeAssignment(*type_assignment)) | |
| ->get(), | |
| FileContent())); | |
| const SyntaxTreeNode* expression = | |
| GetExpressionFromTypeAssignment(*type_assignment); | |
| if (expression != nullptr) { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| ¶m_node); | |
| Visit(*expression); | |
| } | |
| } else { | |
| // 2nd => parameter int x; | |
| // Extract Param name. | |
| const TokenInfo* parameter_name = GetParameterNameToken(param_declaration); | |
| if (!parameter_name) return; | |
| param_node.Value().AppendAnchor(Anchor(*parameter_name, FileContent())); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| ¶m_node); | |
| const Symbol* assign_expression = | |
| GetParamAssignExpression(param_declaration); | |
| if (assign_expression != nullptr && | |
| assign_expression->Kind() == SymbolKind::kNode) { | |
| // Extract trailing expression. | |
| assign_expression->Accept(this); | |
| } | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(param_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractParamByName( | |
| const SyntaxTreeNode& param_by_name) { | |
| const verible::SyntaxTreeLeaf* named_param = | |
| GetNamedParamFromActualParam(param_by_name); | |
| if (!named_param) return; | |
| IndexingFactNode named_param_node( | |
| IndexingNodeData(IndexingFactType::kNamedParam, | |
| Anchor(named_param->get(), FileContent()))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &named_param_node); | |
| const SyntaxTreeNode* paren_group = | |
| GetParenGroupFromActualParam(param_by_name); | |
| if (paren_group != nullptr) { | |
| Visit(*paren_group); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(named_param_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractPackageImport( | |
| const SyntaxTreeNode& package_import_item) { | |
| const SyntaxTreeLeaf* package_name = | |
| GetImportedPackageName(package_import_item); | |
| if (!package_name) return; | |
| IndexingNodeData package_import_data( | |
| IndexingFactType::kPackageImport, | |
| Anchor(package_name->get(), FileContent())); | |
| // Get the name of the imported item (if exists). | |
| // e.g pkg::var1 ==> return var1. | |
| // will be nullptr in case of pkg::*. | |
| const SyntaxTreeLeaf* imported_item = | |
| GeImportedItemNameFromPackageImportItem(package_import_item); | |
| if (imported_item != nullptr) { | |
| package_import_data.AppendAnchor( | |
| Anchor(imported_item->get(), FileContent())); | |
| } | |
| facts_tree_context_.top().Children().emplace_back( | |
| std::move(package_import_data)); | |
| } | |
| // This deep-copy works even if the IndexingNodeData's copy-constructor is | |
| // deleted. | |
| // Defining this here because the following function is the only place in the | |
| // codebase that needs this workaround. | |
| static IndexingNodeData CopyNodeData(const IndexingNodeData& src) { | |
| IndexingNodeData copy(src.GetIndexingFactType()); | |
| for (const auto& anchor : src.Anchors()) { | |
| copy.AppendAnchor(Anchor(anchor)); // copy | |
| } | |
| return copy; | |
| } | |
| void IndexingFactsTreeExtractor::ExtractQualifiedId( | |
| const SyntaxTreeNode& qualified_id) { | |
| IndexingNodeData member_reference_data(IndexingFactType::kMemberReference); | |
| // Get all the variable names in the qualified id. | |
| // e.g. split "A#(...)::B#(...)" into components "A#(...)" and "B#(...)" | |
| for (const auto& child : qualified_id.children()) { | |
| if (child == nullptr || | |
| NodeEnum(child->Tag().tag) != NodeEnum::kUnqualifiedId) { | |
| continue; | |
| } | |
| member_reference_data.AppendAnchor( | |
| Anchor(AutoUnwrapIdentifier(*child)->get(), FileContent())); | |
| const SyntaxTreeNode* param_list = GetParamListFromUnqualifiedId(*child); | |
| if (param_list != nullptr) { | |
| // Create a copy from the current "member_reference" node to be used for | |
| // this param reference. | |
| // Copying inside this for loop costs O(N^2), where N is the | |
| // depth of a reference (on "A::B::C::D", N=4). | |
| // Downstream, the lookup for "A" is being done repeatedly. | |
| // TODO(fangism): rewrite this and its consumer to eliminate the linear | |
| // copy in a loop and avoid re-lookup. | |
| IndexingFactNode param_member_reference( | |
| CopyNodeData(member_reference_data)); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| ¶m_member_reference); | |
| Visit(*param_list); | |
| } | |
| facts_tree_context_.top().Children().push_back( | |
| std::move(param_member_reference)); | |
| } | |
| } | |
| facts_tree_context_.top().Children().emplace_back( | |
| std::move(member_reference_data)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractForInitialization( | |
| const SyntaxTreeNode& for_initialization) { | |
| // Extracts the variable name from for initialization. | |
| // e.g from "int i = 0"; ==> extracts "i". | |
| const SyntaxTreeLeaf* variable_name = | |
| GetVariableNameFromForInitialization(for_initialization); | |
| if (variable_name) { | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(variable_name->get(), FileContent()))); | |
| } | |
| // Extracts the data the in case it contains packed or unpacked dimension. | |
| // e.g bit [x : y] var [x : y]. | |
| const SyntaxTreeNode* data_type_node = | |
| GetDataTypeFromForInitialization(for_initialization); | |
| if (data_type_node != nullptr) { | |
| Visit(*data_type_node); | |
| } | |
| // Extracts the RHS of the declaration. | |
| // e.g int i = x; ==> extracts "x". | |
| const SyntaxTreeNode* expression = | |
| GetExpressionFromForInitialization(for_initialization); | |
| if (expression) Visit(*expression); | |
| } | |
| // Returns string_view of `text` with outermost double-quotes removed. | |
| // If `text` is not wrapped in quotes, return it as-is. | |
| absl::string_view StripOuterQuotes(absl::string_view text) { | |
| return absl::StripSuffix(absl::StripPrefix(text, "\""), "\""); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractInclude( | |
| const SyntaxTreeNode& preprocessor_include) { | |
| VLOG(1) << __FUNCTION__; | |
| const SyntaxTreeLeaf* included_filename = | |
| GetFileFromPreprocessorInclude(preprocessor_include); | |
| if (included_filename == nullptr) { | |
| return; | |
| } | |
| const absl::string_view filename_text = included_filename->get().text(); | |
| // Remove the double quotes from the filesname. | |
| const absl::string_view filename_unquoted = StripOuterQuotes(filename_text); | |
| VLOG(1) << "got: `include \"" << filename_unquoted << "\""; | |
| VerilogProject* const project = extraction_state_->project; | |
| // Open this file (could be first time, or previously opened). | |
| const auto status_or_file = project->OpenIncludedFile(filename_unquoted); | |
| if (!status_or_file.ok()) { | |
| if (errors_ != nullptr) { | |
| errors_->push_back(status_or_file.status()); | |
| } else { | |
| LOG(ERROR) << "Failed to open the include file " << filename_unquoted | |
| << ": " << status_or_file.status(); | |
| } | |
| // Skip | |
| return; | |
| } | |
| VerilogSourceFile* const included_file = *status_or_file; | |
| if (included_file == nullptr) return; | |
| VLOG(1) << "opened include file: " << included_file->ResolvedPath(); | |
| { | |
| // Check whether or not this file was already extracted. | |
| const auto p = extraction_state_->extracted_files.insert(included_file); | |
| if (!p.second) { | |
| // If already extracted, skip re-extraction. | |
| VLOG(1) << "File was previously extracted."; | |
| } else { | |
| // Parse included file and extract. | |
| const auto parse_status = included_file->Parse(); | |
| if (parse_status.ok()) { | |
| file_list_facts_tree_.Children().push_back(BuildIndexingFactsTree( | |
| file_list_facts_tree_, *included_file, extraction_state_, errors_)); | |
| } else { | |
| if (errors_ != nullptr) { | |
| errors_->push_back(parse_status); | |
| } else { | |
| LOG(WARNING) << "Failed to parse the include file " | |
| << filename_unquoted << ": " << parse_status; | |
| } | |
| } | |
| } | |
| } | |
| // Create a node for include statement with two Anchors: | |
| // 1st one holds the actual text in the include statement. | |
| // 2nd one holds the path of the included file relative to the file list. | |
| facts_tree_context_.top().Children().emplace_back(IndexingNodeData( | |
| IndexingFactType::kInclude, | |
| Anchor(filename_text, included_filename->get().left(FileContent()), | |
| filename_text.size()), | |
| Anchor(included_file->ResolvedPath()))); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractEnumName( | |
| const SyntaxTreeNode& enum_name) { | |
| const SyntaxTreeLeaf* symbol_id = GetSymbolIdentifierFromEnumName(enum_name); | |
| if (!symbol_id) return; | |
| IndexingFactNode enum_node(IndexingNodeData( | |
| IndexingFactType::kConstant, Anchor(symbol_id->get(), FileContent()))); | |
| // Iterate over the children and traverse them to extract facts from inner | |
| // nodes and ignore the leaves. | |
| // e.g enum {RED[x] = 1, OLD=y} => explores "[x]", "=y". | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, &enum_node); | |
| for (const auto& child : enum_name.children()) { | |
| if (child == nullptr || child->Kind() == SymbolKind::kLeaf) { | |
| continue; | |
| } | |
| child->Accept(this); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(enum_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractEnumTypeDeclaration( | |
| const SyntaxTreeNode& enum_type_declaration) { | |
| // Extract enum type name. | |
| const SyntaxTreeLeaf* enum_type_name = | |
| GetIdentifierFromTypeDeclaration(enum_type_declaration); | |
| if (!enum_type_name) return; | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(enum_type_name->get(), FileContent()))); | |
| // Explore the children of this enum type to extract. | |
| for (const auto& child : enum_type_declaration.children()) { | |
| if (child == nullptr || child->Kind() == SymbolKind::kLeaf) { | |
| continue; | |
| } | |
| child->Accept(this); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractStructUnionTypeDeclaration( | |
| const SyntaxTreeNode& type_declaration, const SyntaxTreeNode& struct_type) { | |
| IndexingFactNode struct_type_node(IndexingNodeData( | |
| IndexingFactType::kStructOrUnion, | |
| Anchor( | |
| ABSL_DIE_IF_NULL(GetIdentifierFromTypeDeclaration(type_declaration)) | |
| ->get(), | |
| FileContent()))); | |
| // Explore the children of this enum type to extract. | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &struct_type_node); | |
| Visit(struct_type); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(struct_type_node)); | |
| } | |
| void IndexingFactsTreeExtractor::ExtractStructUnionDeclaration( | |
| const SyntaxTreeNode& struct_type, | |
| const std::vector<TreeSearchMatch>& variables_matched) { | |
| VLOG(2) << __FUNCTION__; | |
| // Dummy data type to hold the extracted struct members because there is no | |
| // data type here. Its temporary children will be moved out before this | |
| // returns. | |
| IndexingFactNode struct_node( | |
| IndexingNodeData{IndexingFactType::kStructOrUnion}); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &struct_node); | |
| // Extract struct members. | |
| Visit(struct_type); | |
| } | |
| for (const TreeSearchMatch& variable : variables_matched) { | |
| // Extract this variable. | |
| // This can be kRegisterVariable or kVariableDeclarationAssign. | |
| variable.match->Accept(this); | |
| CHECK(!facts_tree_context_.top().Children().empty()); | |
| IndexingFactNode& recent(facts_tree_context_.top().Children().back()); | |
| // Append the struct members to be a children of this variable. | |
| // TODO(fangism): move instead of copying chidren | |
| // However, std::move-ing each child in the loop crashes, | |
| // and so does recent.AdoptSubtreesFrom(&struct_node). | |
| recent.Children().reserve(struct_node.Children().size()); | |
| for (const auto& child : struct_node.Children()) { | |
| recent.Children().push_back(child); // copy | |
| } | |
| } | |
| VLOG(2) << "end of " << __FUNCTION__; | |
| } | |
| void IndexingFactsTreeExtractor::ExtractDataTypeImplicitIdDimensions( | |
| const SyntaxTreeNode& data_type_implicit_id_dimensions) { | |
| // This node has 2 cases: | |
| // 1st case: | |
| // typedef struct { | |
| // data_type var_name; | |
| // } my_struct; | |
| // In this case this should be a kDataTypeReference with var_name as a | |
| // child. | |
| // | |
| // 2nd case: | |
| // typedef struct { | |
| // struct {int xx;} var_name; | |
| // } my_struct; | |
| // In this case var_name should contain "xx" inside it. | |
| std::pair<const SyntaxTreeLeaf*, int> variable_name = | |
| GetSymbolIdentifierFromDataTypeImplicitIdDimensions( | |
| data_type_implicit_id_dimensions); | |
| if (!variable_name.first) return; | |
| IndexingFactNode variable_node( | |
| IndexingNodeData(IndexingFactType::kVariableDefinition, | |
| Anchor(variable_name.first->get(), FileContent()))); | |
| if (variable_name.second == 1) { | |
| const SyntaxTreeLeaf* type_identifier = | |
| GetNonprimitiveTypeOfDataTypeImplicitDimensions( | |
| data_type_implicit_id_dimensions); | |
| if (type_identifier == nullptr) return; | |
| IndexingFactNode type_node( | |
| IndexingNodeData(IndexingFactType::kDataTypeReference, | |
| Anchor(type_identifier->get(), FileContent()))); | |
| type_node.Children().push_back(std::move(variable_node)); | |
| facts_tree_context_.top().Children().push_back(std::move(type_node)); | |
| } else if (variable_name.second == 2) { | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &variable_node); | |
| for (const auto& child : data_type_implicit_id_dimensions.children()) { | |
| if (child == nullptr || child->Kind() == SymbolKind::kLeaf) { | |
| continue; | |
| } | |
| child->Accept(this); | |
| } | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(variable_node)); | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractTypeDeclaration( | |
| const SyntaxTreeNode& type_declaration) { | |
| const SyntaxTreeNode* type = | |
| GetReferencedTypeOfTypeDeclaration(type_declaration); | |
| if (type == nullptr) return; | |
| // Look for enum/struct/union in the referenced type. | |
| const auto tag = static_cast<NodeEnum>(type->Tag().tag); | |
| if (tag != NodeEnum::kDataType) return; | |
| const SyntaxTreeNode* primitive = | |
| GetStructOrUnionOrEnumTypeFromDataType(*type); | |
| if (primitive == nullptr) { | |
| // Then this is a user-defined type. | |
| // Extract type name. | |
| const SyntaxTreeLeaf* type_name = | |
| GetIdentifierFromTypeDeclaration(type_declaration); | |
| if (type_name == nullptr) return; | |
| facts_tree_context_.top().Children().emplace_back( | |
| IndexingNodeData(IndexingFactType::kTypeDeclaration, | |
| Anchor(type_name->get(), FileContent()))); | |
| return; | |
| } | |
| switch (NodeEnum(primitive->Tag().tag)) { | |
| case NodeEnum::kEnumType: { | |
| ExtractEnumTypeDeclaration(type_declaration); | |
| break; | |
| } | |
| case NodeEnum::kStructType: { | |
| ExtractStructUnionTypeDeclaration(type_declaration, *type); | |
| break; | |
| } | |
| case NodeEnum::kUnionType: { | |
| ExtractStructUnionTypeDeclaration(type_declaration, *type); | |
| break; | |
| } | |
| default: { | |
| break; | |
| } | |
| } | |
| } | |
| void IndexingFactsTreeExtractor::ExtractAnonymousScope( | |
| const SyntaxTreeNode& node) { | |
| IndexingFactNode temp_scope_node(IndexingNodeData( | |
| IndexingFactType::kAnonymousScope, | |
| // Generate unique id for this scope. | |
| Anchor(absl::StrCat("anonymous-scope-", next_anonymous_id++)))); | |
| { | |
| const IndexingFactsTreeContext::AutoPop p(&facts_tree_context_, | |
| &temp_scope_node); | |
| TreeContextVisitor::Visit(node); | |
| } | |
| facts_tree_context_.top().Children().push_back(std::move(temp_scope_node)); | |
| } | |
| void IndexingFactsTreeExtractor::MoveAndDeleteLastExtractedNode( | |
| IndexingFactNode& new_node) { | |
| // Terminate if there is no parent or the parent has no children. | |
| if (facts_tree_context_.empty() || is_leaf(facts_tree_context_.top())) { | |
| return; | |
| } | |
| // Get The last extracted child. | |
| IndexingFactNode& previous_node = facts_tree_context_.top().Children().back(); | |
| // Fill the anchors of the previous node to the current node. | |
| new_node.Value().SwapAnchors(&previous_node.Value()); | |
| // Move the children of the previous node to this node. | |
| AdoptSubtreesFrom(new_node, &previous_node); | |
| // Remove the last extracted node. | |
| facts_tree_context_.top().Children().pop_back(); | |
| } | |
| } // namespace kythe | |
| } // namespace verilog |