blob: a02db62e8642b1b25793743e6c0efe45a34e7012 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fidl/tree_visitor.h"
#include <map>
#include "fidl/raw_ast.h"
namespace fidl {
namespace raw {
void DeclarationOrderTreeVisitor::OnFile(std::unique_ptr<File> const& element) {
OnSourceElementStart(*element);
if (element->attributes != nullptr) {
OnAttributeList(element->attributes);
}
OnCompoundIdentifier(element->library_name);
auto alias_decls_it = element->alias_list.begin();
auto bits_decls_it = element->bits_declaration_list.begin();
auto const_decls_it = element->const_declaration_list.begin();
auto enum_decls_it = element->enum_declaration_list.begin();
auto protocol_decls_it = element->protocol_declaration_list.begin();
auto resource_decls_it = element->resource_declaration_list.begin();
auto service_decls_it = element->service_declaration_list.begin();
auto struct_decls_it = element->struct_declaration_list.begin();
auto table_decls_it = element->table_declaration_list.begin();
auto union_decls_it = element->union_declaration_list.begin();
auto using_decls_it = element->using_list.begin();
enum Next {
alias_t,
bits_t,
const_t,
enum_t,
protocol_t,
resource_t,
service_t,
struct_t,
table_t,
union_t,
using_t,
};
std::map<const char*, Next> m;
for (;;) {
// We want to visit these in declaration order, rather than grouped
// by type of declaration. std::map is sorted by key. For each of
// these lists of declarations, we make a map where the key is "the
// next start location of the earliest element in the list" to a
// variable representing the type. We then identify which type was
// put earliest in the map. That will be the earliest declaration
// in the file. We then visit the declaration accordingly.
m.clear();
if (alias_decls_it != element->alias_list.end()) {
m[(*alias_decls_it)->start_.previous_end().data().data()] = alias_t;
}
if (bits_decls_it != element->bits_declaration_list.end()) {
m[(*bits_decls_it)->start_.previous_end().data().data()] = bits_t;
}
if (const_decls_it != element->const_declaration_list.end()) {
m[(*const_decls_it)->start_.previous_end().data().data()] = const_t;
}
if (enum_decls_it != element->enum_declaration_list.end()) {
m[(*enum_decls_it)->start_.previous_end().data().data()] = enum_t;
}
if (protocol_decls_it != element->protocol_declaration_list.end()) {
if (*protocol_decls_it == nullptr) {
// Used to indicate empty, so let's wind it forward.
protocol_decls_it = element->protocol_declaration_list.end();
} else {
m[(*protocol_decls_it)->start_.previous_end().data().data()] = protocol_t;
}
}
if (resource_decls_it != element->resource_declaration_list.end()) {
m[(*resource_decls_it)->start_.previous_end().data().data()] = resource_t;
}
if (service_decls_it != element->service_declaration_list.end()) {
m[(*service_decls_it)->start_.previous_end().data().data()] = service_t;
}
if (struct_decls_it != element->struct_declaration_list.end()) {
m[(*struct_decls_it)->start_.previous_end().data().data()] = struct_t;
}
if (table_decls_it != element->table_declaration_list.end()) {
m[(*table_decls_it)->start_.previous_end().data().data()] = table_t;
}
if (union_decls_it != element->union_declaration_list.end()) {
m[(*union_decls_it)->start_.previous_end().data().data()] = union_t;
}
if (using_decls_it != element->using_list.end()) {
m[(*using_decls_it)->start_.previous_end().data().data()] = using_t;
}
if (m.size() == 0)
break;
// And the earliest top level declaration is...
switch (m.begin()->second) {
case alias_t:
OnAliasDeclaration(*alias_decls_it);
++alias_decls_it;
break;
case bits_t:
OnBitsDeclaration(*bits_decls_it);
++bits_decls_it;
break;
case const_t:
OnConstDeclaration(*const_decls_it);
++const_decls_it;
break;
case enum_t:
OnEnumDeclaration(*enum_decls_it);
++enum_decls_it;
break;
case protocol_t:
OnProtocolDeclaration(*protocol_decls_it);
++protocol_decls_it;
break;
case resource_t:
OnResourceDeclaration(*resource_decls_it);
++resource_decls_it;
break;
case service_t:
OnServiceDeclaration(*service_decls_it);
++service_decls_it;
break;
case struct_t:
OnStructDeclaration(*struct_decls_it);
++struct_decls_it;
break;
case table_t:
OnTableDeclaration(*table_decls_it);
++table_decls_it;
break;
case union_t:
OnUnionDeclaration(*union_decls_it);
++union_decls_it;
break;
case using_t:
OnUsing(*using_decls_it);
++using_decls_it;
break;
}
}
OnSourceElementEnd(*element);
}
void DeclarationOrderTreeVisitor::OnProtocolDeclaration(
std::unique_ptr<ProtocolDeclaration> const& element) {
SourceElementMark sem(this, *element);
if (element->attributes != nullptr) {
OnAttributeList(element->attributes);
}
OnIdentifier(element->identifier);
auto compose_it = element->composed_protocols.begin();
auto methods_it = element->methods.begin();
enum Next {
compose_t,
method_t,
};
std::map<const char*, Next> m;
for (;;) {
// Sort in declaration order.
m.clear();
if (compose_it != element->composed_protocols.end()) {
m[(*compose_it)->start_.previous_end().data().data()] = compose_t;
}
if (methods_it != element->methods.end()) {
m[(*methods_it)->start_.previous_end().data().data()] = method_t;
}
if (m.size() == 0)
return;
// And the earliest declaration is...
switch (m.begin()->second) {
case compose_t:
OnComposeProtocol(*compose_it);
++compose_it;
break;
case method_t:
OnProtocolMethod(*methods_it);
++methods_it;
break;
}
}
}
} // namespace raw
} // namespace fidl