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 "fidl/raw_ast.h"
8 #include "fidl/tree_visitor.h"
9 
10 namespace fidl {
11 namespace raw {
12 
OnFile(std::unique_ptr<File> const & element)13 void 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 table_decls_it = element->table_declaration_list.begin();
28     auto union_decls_it = element->union_declaration_list.begin();
29 
30     enum Next {
31         const_t,
32         enum_t,
33         interface_t,
34         struct_t,
35         table_t,
36         union_t
37     };
38 
39     std::map<const char*, Next> m;
40     do {
41         // We want to visit these in declaration order, rather than grouped
42         // by type of declaration.  std::map is sorted by key.  For each of
43         // these lists of declarations, we make a map where the key is "the
44         // next start location of the earliest element in the list" to a
45         // variable representing the type.  We then identify which type was
46         // put earliest in the map.  That will be the earliest declaration
47         // in the file.  We then visit the declaration accordingly.
48         m.clear();
49         if (const_decls_it != element->const_declaration_list.end()) {
50             m[(*const_decls_it)->start_.previous_end().data().data()] = const_t;
51         }
52         if (enum_decls_it != element->enum_declaration_list.end()) {
53             m[(*enum_decls_it)->start_.previous_end().data().data()] = enum_t;
54         }
55         if (interface_decls_it != element->interface_declaration_list.end()) {
56             if (*interface_decls_it == nullptr) {
57                 // Used to indicate empty, so let's wind it forward.
58                 interface_decls_it = element->interface_declaration_list.end();
59             } else {
60                 m[(*interface_decls_it)->start_.previous_end().data().data()] = interface_t;
61             }
62         }
63         if (struct_decls_it != element->struct_declaration_list.end()) {
64             m[(*struct_decls_it)->start_.previous_end().data().data()] = struct_t;
65         }
66         if (table_decls_it != element->table_declaration_list.end()) {
67             m[(*table_decls_it)->start_.previous_end().data().data()] = table_t;
68         }
69         if (union_decls_it != element->union_declaration_list.end()) {
70             m[(*union_decls_it)->start_.previous_end().data().data()] = union_t;
71         }
72         if (m.size() == 0)
73             break;
74 
75         // And the earliest top level declaration is...
76         switch (m.begin()->second) {
77         case const_t:
78             OnConstDeclaration(*const_decls_it);
79             ++const_decls_it;
80             break;
81         case enum_t:
82             OnEnumDeclaration(*enum_decls_it);
83             ++enum_decls_it;
84             break;
85         case interface_t:
86             OnInterfaceDeclaration(*interface_decls_it);
87             ++interface_decls_it;
88             break;
89         case struct_t:
90             OnStructDeclaration(*struct_decls_it);
91             ++struct_decls_it;
92             break;
93         case table_t:
94             OnTableDeclaration(*table_decls_it);
95             ++table_decls_it;
96             break;
97         case union_t:
98             OnUnionDeclaration(*union_decls_it);
99             ++union_decls_it;
100             break;
101         }
102     } while (1);
103     OnSourceElementEnd(*element);
104 }
105 
106 } // namespace raw
107 } // namespace fidl
108