1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <map> 6 7 #include "banjo/raw_ast.h" 8 #include "banjo/tree_visitor.h" 9 10 namespace banjo { 11 namespace raw { 12 OnFile(std::unique_ptr<File> const & element)13void DeclarationOrderTreeVisitor::OnFile(std::unique_ptr<File> const& element) { 14 OnSourceElementStart(*element); 15 16 OnCompoundIdentifier(element->library_name); 17 for (auto i = element->using_list.begin(); 18 i != element->using_list.end(); 19 ++i) { 20 OnUsing(*i); 21 } 22 23 auto const_decls_it = element->const_declaration_list.begin(); 24 auto enum_decls_it = element->enum_declaration_list.begin(); 25 auto interface_decls_it = element->interface_declaration_list.begin(); 26 auto struct_decls_it = element->struct_declaration_list.begin(); 27 auto union_decls_it = element->union_declaration_list.begin(); 28 29 enum Next { 30 const_t, 31 enum_t, 32 interface_t, 33 struct_t, 34 union_t 35 }; 36 37 std::map<const char*, Next> m; 38 do { 39 // We want to visit these in declaration order, rather than grouped 40 // by type of declaration. std::map is sorted by key. For each of 41 // these lists of declarations, we make a map where the key is "the 42 // next start location of the earliest element in the list" to a 43 // variable representing the type. We then identify which type was 44 // put earliest in the map. That will be the earliest declaration 45 // in the file. We then visit the declaration accordingly. 46 m.clear(); 47 if (const_decls_it != element->const_declaration_list.end()) { 48 m[(*const_decls_it)->start_.previous_end().data().data()] = const_t; 49 } 50 if (enum_decls_it != element->enum_declaration_list.end()) { 51 m[(*enum_decls_it)->start_.previous_end().data().data()] = enum_t; 52 } 53 if (interface_decls_it != element->interface_declaration_list.end()) { 54 if (*interface_decls_it == nullptr) { 55 // Used to indicate empty, so let's wind it forward. 56 interface_decls_it = element->interface_declaration_list.end(); 57 } else { 58 m[(*interface_decls_it)->start_.previous_end().data().data()] = interface_t; 59 } 60 } 61 if (struct_decls_it != element->struct_declaration_list.end()) { 62 m[(*struct_decls_it)->start_.previous_end().data().data()] = struct_t; 63 } 64 if (union_decls_it != element->union_declaration_list.end()) { 65 m[(*union_decls_it)->start_.previous_end().data().data()] = union_t; 66 } 67 if (m.size() == 0) 68 break; 69 70 // And the earliest top level declaration is... 71 switch (m.begin()->second) { 72 case const_t: 73 OnConstDeclaration(*const_decls_it); 74 ++const_decls_it; 75 break; 76 case enum_t: 77 OnEnumDeclaration(*enum_decls_it); 78 ++enum_decls_it; 79 break; 80 case interface_t: 81 OnInterfaceDeclaration(*interface_decls_it); 82 ++interface_decls_it; 83 break; 84 case struct_t: 85 OnStructDeclaration(*struct_decls_it); 86 ++struct_decls_it; 87 break; 88 case union_t: 89 OnUnionDeclaration(*union_decls_it); 90 ++union_decls_it; 91 break; 92 } 93 } while (1); 94 OnSourceElementEnd(*element); 95 } 96 97 } // namespace raw 98 } // namespace banjo 99