blob: 1e153f5266aa8988094ea351c5e9687f04430c20 [file] [log] [blame]
// Copyright 2021 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.
#ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_NEW_SYNTAX_CONVERTER_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_NEW_SYNTAX_CONVERTER_H_
// The ConvertingTreeVisitor takes a raw::File, and translates its textual
// representation from one syntax to another.
#include <stack>
#include "flat/name.h"
#include "flat_ast.h"
#include "new_syntax_conversion.h"
#include "tree_visitor.h"
#include "underlying_type.h"
namespace fidl::conv {
class Converting;
class ConvertingTreeVisitor : public raw::DeclarationOrderTreeVisitor {
friend Converting;
public:
explicit ConvertingTreeVisitor(fidl::utils::Syntax syntax, const flat::Library* library)
: to_syntax_(syntax), last_conversion_end_(nullptr), last_comment_(0), library_(library) {}
// TODO(azaslavsky): I'll eventually remove the commented out block below. At
// the moment it serves as a useful list of TreeVisitor methods that are
// intended to be left unmodified by the ConvertingTreeVisitor.
// void OnBinaryOperatorConstant(std::unique_ptr<BinaryOperatorConstant> const&) override;
// void OnComposeProtocol(std::unique_ptr<raw::ComposeProtocol> const&) override;
// void OnCompoundIdentifier(std::unique_ptr<CompoundIdentifier> const&) override;
// void OnConstant(std::unique_ptr<Constant> const&) override;
// void OnEnumMember(std::unique_ptr<raw::EnumMember> const&) override;
// void OnIdentifier(std::unique_ptr<Identifier> const&) override;
// void OnIdentifierConstant(std::unique_ptr<IdentifierConstant> const&) override;
// void OnLiteral(std::unique_ptr<fidl::raw::Literal> const&) override;
// void OnLiteralConstant(std::unique_ptr<LiteralConstant> const&) override;
// void OnNullability(types::Nullability nullability) override;
// void OnParameterList(std::unique_ptr<ParameterList> const&) override;
// void OnPrimitiveSubtype(types::PrimitiveSubtype subtype) override;
// void OnProtocolDeclaration(std::unique_ptr<ProtocolDeclaration> const&) override;
// void OnProtocolMethod(std::unique_ptr<ProtocolMethod> const&) override;
// void OnResourceDeclaration(std::unique_ptr<fidl::raw::ResourceDeclaration> const&) override;
// void OnServiceDeclaration(std::unique_ptr<raw::ServiceDeclaration> const&) override;
// void OnServiceMember(std::unique_ptr<raw::ServiceMember> const&) override;
// void OnSourceElementStart(const raw::SourceElement&) override;
// void OnSourceElementEnd(const raw::SourceElement&) override;
// The remaining "On*" methods are loosely organized by keyword. All of them
// must be overwritten by the implementation.
// Attributes.
void OnAttribute(const raw::Attribute& element) override;
void OnAttributeList(std::unique_ptr<raw::AttributeList> const& element) override;
// Bits.
void OnBitsDeclaration(std::unique_ptr<raw::BitsDeclaration> const& element) override;
void OnBitsMember(std::unique_ptr<raw::BitsMember> const& element) override;
// Constants.
void OnConstDeclaration(std::unique_ptr<raw::ConstDeclaration> const& element) override;
// Enums.
void OnEnumDeclaration(std::unique_ptr<raw::EnumDeclaration> const& element) override;
void OnEnumMember(std::unique_ptr<raw::EnumMember> const& element) override;
// Files.
void OnFile(std::unique_ptr<raw::File> const& element) override;
// Method Parameters.
void OnParameter(std::unique_ptr<raw::Parameter> const& element) override;
// Resource Property.
void OnResourceProperty(std::unique_ptr<fidl::raw::ResourceProperty> const& element) override;
// Structs.
void OnStructDeclaration(std::unique_ptr<raw::StructDeclaration> const& element) override;
void OnStructMember(std::unique_ptr<raw::StructMember> const& element) override;
// Tables.
void OnTableDeclaration(std::unique_ptr<raw::TableDeclaration> const& element) override;
void OnTableMember(std::unique_ptr<raw::TableMember> const& element) override;
// Types.
void OnTypeConstructorOld(std::unique_ptr<raw::TypeConstructorOld> const& element) override;
// Unions.
void OnUnionDeclaration(std::unique_ptr<raw::UnionDeclaration> const& element) override;
void OnUnionMember(std::unique_ptr<raw::UnionMember> const& element) override;
// Using.
void OnUsing(std::unique_ptr<raw::Using> const& element) override;
// Used to return a string with the converted output upon converter
// completion.
std::string* converted_output() { return &converted_output_; }
private:
// String built over the course of the visitor's execution containing the
// converted output.
std::string converted_output_;
// Tracks which syntax we will be converting to. Setting this value to
// kExisting is useful to validate that ConvertingTreeVisitor is working
// properly: any compile-able FIDL file should be returned from this converter
// with no changes if kOld is used.
const fidl::utils::Syntax to_syntax_;
// A stack of currently active conversions. Each conversion in the stack
// operates on a set of characters that are strictly contained within those of
// its parent (ex, if the first entry in the stack is converting the "bar baz"
// portion of "foo bar baz quux," the second entry may only convert spans
// within that range, like "bar" or "baz").
std::stack<std::unique_ptr<Conversion>> open_conversions_;
// A char pointer tracing the last end point of the last conversion seen thus
// far. This is used to verify that prefix ranges are not copied multiple
// times when doing nested conversions, and to ensure that the remaining text
// after the final conversion gets copied.
const char* last_conversion_end_;
// A list of all C-Style "//"-leading comments in the file (ie, all comments
// except doc comments). We need to store this because some of the conversion
// spans may include weirdly-placed comments that we do not want to lose.
// Instead, such comments should be appended to the conversion's prefix.
std::vector<std::unique_ptr<Token>> comments_;
// Attributes are something of a special case. Consider this struct with no
// attributes, where the top-level StructDeclaration conversion span
// (bounded by single arrows: «___») necessarily precedes all of its child
// spans (each bounded by inside of ««___»»):
//
// «struct S» {
// ««bool foo»»;
// ««int8 vector<bar>»»;
// };
//
// In fact, every conversion (except for attributes) exhibits this property.
// But if we add an attribute to the declaration above, this no longer holds:
//
// ««[MaxBytes]»»
// «struct S» {
// ««bool foo»»;
// ««int8 vector<bar>»»;
// };
//
// Running AddChildText() on the children of this StructDeclaration in order
// would result in the [MaxBytes] appearing after the top-level
// type S = struct statement, which is not correct.
//
// The solution to this problem is for every raw AST node that can carry
// attributes to visit its AttributeList child twice: once prior to starting
// the conversion for the parent node itself, and then again as part of the
// normal flow of the default TreeVisitor. To prevent attributes from
// appearing twice, each time an AttributeList is visited, it adds its pointer
// to this set if it is not already present. If it is already present
// (meaning this is the second visit), then the visit is a noop, resulting in
// only one conversion in the correct place.
std::set<raw::AttributeList*> attribute_lists_seen_;
// Keeps track of the last comment in the comments_ list to have been "tested"
// for being inside a conversion span. The char pointer at the vector index
// pointed to by this member should never exceed the char pointer held in
// last_conversion_end_.
std::size_t last_comment_;
// A pointer to the flat::Library representation of the file being visited.
// This will be used when resolving and converting type definitions that
// are behind aliases, defined in the imported libraries, and so forth.
const flat::Library* library_;
// Meant to be called from inside the "OnTypeConstructor" method in the
// implementation. For that method to do its work properly, it must be able
// to deduce the built-in type underpinning the type declaration. For
// example, if OnTypeConstructor is currently looking at the type declaration
// "Foo<Bar>:4," what do "Foo" and "Bar" represent? The conversion applied
// will look very different depending on which built-ins those identifiers
// resolve to.
std::optional<UnderlyingType> resolve(const std::unique_ptr<raw::TypeConstructorOld>& type_ctor);
};
class Converting {
public:
// Helper method for starting a new conversion. It takes three arguments: a
// Conversion object specifying the type of conversion being attempted, as
// well as two tokens representing the start and end point of the span that
// will need to be modified. For example, if we are attempting to convert the
// element "const uint8 FOO = 5;" the first argument will be a unique_ptr to a
// NameAndTypeConversion (to re-order "uint8" after "FOO"), the second will be
// a token pointing to "uint8," and the third a token pointing to "FOO."
//
// By specifying the start and end points within the element being converted,
// we are able to advance the last_conversion_end_ pointer to the end, which
// prevents double conversion. Further, all text between the previous value
// of last_conversion_end_ and the start token may be blindly copied, since we
// are now sure that there are not conversions taking place in that span.
Converting(ConvertingTreeVisitor* ctv, std::unique_ptr<Conversion> conversion, const Token& start,
const Token& end);
// If a conversion is not the last remaining entry in the open_conversions_
// stack, its stringified output is simply passed to the top entry of that
// stack, to be incorporated as a nested element in that entry. If it is the
// last entry, the text is written to the output string instead.
~Converting();
private:
ConvertingTreeVisitor* ctv_;
};
} // namespace fidl::conv
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_NEW_SYNTAX_CONVERTER_H_