blob: e44f3222b10d4b3302e87d386eb4443433ff1afe [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 "tools/fidl/fidlc/src/tree_visitor.h"
#include <map>
#include "tools/fidl/fidlc/src/raw_ast.h"
namespace fidlc {
void DeclarationOrderTreeVisitor::OnFile(const std::unique_ptr<File>& element) {
OnSourceElementStart(*element);
OnLibraryDeclaration(element->library_decl);
auto alias_decls_it = element->alias_list.begin();
auto const_decls_it = element->const_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 type_decls_it = element->type_decls.begin();
auto using_decls_it = element->using_list.begin();
enum Next {
kAlias,
kConst,
kProtocol,
kResource,
kService,
kTypeDecl,
kUsing,
};
std::map<const char*, Next> m;
for (;;) {
// We want to visit these in declaration order, rather than grouped by type
// of declaration, so we put them in a map keyed by source position.
m.clear();
if (alias_decls_it != element->alias_list.end()) {
m[(*alias_decls_it)->start_token.ptr()] = kAlias;
}
if (const_decls_it != element->const_declaration_list.end()) {
m[(*const_decls_it)->start_token.ptr()] = kConst;
}
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_token.ptr()] = kProtocol;
}
}
if (resource_decls_it != element->resource_declaration_list.end()) {
m[(*resource_decls_it)->start_token.ptr()] = kResource;
}
if (service_decls_it != element->service_declaration_list.end()) {
m[(*service_decls_it)->start_token.ptr()] = kService;
}
if (type_decls_it != element->type_decls.end()) {
m[(*type_decls_it)->start_token.ptr()] = kTypeDecl;
}
if (using_decls_it != element->using_list.end()) {
m[(*using_decls_it)->start_token.ptr()] = kUsing;
}
if (m.empty())
break;
// And the earliest top level declaration is...
switch (m.begin()->second) {
case kAlias:
OnAliasDeclaration(*alias_decls_it);
++alias_decls_it;
break;
case kConst:
OnConstDeclaration(*const_decls_it);
++const_decls_it;
break;
case kProtocol:
OnProtocolDeclaration(*protocol_decls_it);
++protocol_decls_it;
break;
case kResource:
OnResourceDeclaration(*resource_decls_it);
++resource_decls_it;
break;
case kService:
OnServiceDeclaration(*service_decls_it);
++service_decls_it;
break;
case kTypeDecl:
OnTypeDeclaration(*type_decls_it);
++type_decls_it;
break;
case kUsing:
OnUsing(*using_decls_it);
++using_decls_it;
break;
}
}
OnSourceElementEnd(*element);
}
void DeclarationOrderTreeVisitor::OnProtocolDeclaration(
const std::unique_ptr<RawProtocolDeclaration>& element) {
SourceElementMark sem(this, *element);
if (element->attributes != nullptr) {
OnAttributeList(element->attributes);
}
if (element->modifiers != nullptr) {
OnModifierList(element->modifiers);
}
OnIdentifier(element->identifier);
auto compose_it = element->composed_protocols.begin();
auto methods_it = element->methods.begin();
enum Next {
kCompose,
kMethod,
};
std::map<const char*, Next> m;
for (;;) {
// Sort in declaration order.
m.clear();
if (compose_it != element->composed_protocols.end()) {
m[(*compose_it)->start_token.ptr()] = kCompose;
}
if (methods_it != element->methods.end()) {
m[(*methods_it)->start_token.ptr()] = kMethod;
}
if (m.empty())
return;
// And the earliest declaration is...
switch (m.begin()->second) {
case kCompose:
OnProtocolCompose(*compose_it);
++compose_it;
break;
case kMethod:
OnProtocolMethod(*methods_it);
++methods_it;
break;
}
}
}
} // namespace fidlc