blob: d0c3a0629530c2c136354531b5ede994c0fb85c1 [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.
#ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_JSON_GENERATOR_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_JSON_GENERATOR_H_
#include <memory>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include "flat_ast.h"
#include "json_writer.h"
namespace fidl {
struct NameSpan {
explicit NameSpan(const SourceSpan& span)
: filename(span.source_file().filename()), length(span.data().length()) {
span.SourceLine(&position);
}
// TODO(fxbug.dev/7920): We are incorrectly assuming that the provided name is not
// anonymous, and relying on callers to avoid derefencing a nullptr
// location.
explicit NameSpan(const flat::Name& name) : NameSpan(name.span().value()) {
assert(name.span().has_value() && "NameSpan was passed an anonymous name");
}
const std::string filename;
SourceFile::Position position;
const size_t length;
};
// Methods or functions named "Emit..." are the actual interface to
// the JSON output.
// Methods named "Generate..." directly generate JSON output via the
// "Emit" routines.
// Methods named "Produce..." indirectly generate JSON output by calling
// the Generate methods, and should not call the "Emit" functions
// directly.
// |JsonWriter| requires the derived type as a template parameter so it can
// match methods declared with parameter overrides in the derived class.
class JSONGenerator : public utils::JsonWriter<JSONGenerator> {
public:
// "using" is required for overridden methods, so the implementations in
// both the base class and in this derived class are visible when matching
// parameter types
using utils::JsonWriter<JSONGenerator>::Generate;
using utils::JsonWriter<JSONGenerator>::GenerateArray;
explicit JSONGenerator(const flat::Library* library, bool omit_locations = false)
: JsonWriter(json_file_), library_(library), omit_locations_(omit_locations) {}
~JSONGenerator() = default;
std::ostringstream Produce();
// Specializing for structs to avoid printing request/response structs, which are
// handled separately.
void GenerateArray(std::vector<std::unique_ptr<flat::Struct>>::const_iterator begin,
std::vector<std::unique_ptr<flat::Struct>>::const_iterator end) {
EmitArrayBegin();
bool is_first = true;
for (std::vector<std::unique_ptr<flat::Struct>>::const_iterator it = begin; it != end; ++it) {
if ((*it)->is_request_or_response)
continue;
if (is_first) {
Indent();
EmitNewlineWithIndent();
is_first = false;
} else {
EmitArraySeparator();
}
Generate(**it);
}
if (!is_first) {
Outdent();
EmitNewlineWithIndent();
}
EmitArrayEnd();
}
void Generate(const flat::Decl* decl);
void Generate(SourceSpan value);
void Generate(NameSpan value);
void Generate(types::HandleSubtype value);
void Generate(types::Nullability value);
void Generate(const raw::Identifier& value);
void Generate(const raw::Attribute& value);
void Generate(const raw::AttributeList& value);
void Generate(const raw::Ordinal64& value);
void Generate(const TypeShape& type_shape);
void Generate(const FieldShape& type_shape);
void Generate(const flat::Name& value);
void Generate(const flat::Type* value);
void Generate(const flat::Constant& value);
void Generate(const flat::ConstantValue& value);
void Generate(const flat::Bits& value);
void Generate(const flat::Bits::Member& value);
void Generate(const flat::Const& value);
void Generate(const flat::Enum& value);
void Generate(const flat::Enum::Member& value);
void Generate(const flat::Protocol& value);
void Generate(const flat::Protocol::MethodWithInfo& value);
void Generate(const flat::LiteralConstant& value);
void Generate(const flat::Resource& value);
void Generate(const flat::Resource::Property& value);
void Generate(const flat::Service& value);
void Generate(const flat::Service::Member& value);
void Generate(const flat::Struct& value);
void Generate(const flat::Struct* value);
void Generate(const flat::Struct::Member& value, bool is_request_or_response = false);
void Generate(const flat::Table& value);
void Generate(const flat::Table::Member& value);
void Generate(const flat::Union& value);
void Generate(const flat::Union::Member& value);
void Generate(const flat::TypeConstructor::FromTypeAlias& value);
void Generate(const flat::TypeConstructor& value);
void Generate(const flat::TypeAlias& value);
void Generate(const flat::Library* library);
private:
void GenerateTypeAndFromTypeAlias(const flat::TypeConstructor& value,
Position position = Position::kSubsequent);
void GenerateRequest(const std::string& prefix, const flat::Struct& value);
void GenerateDeclarationsEntry(int count, const flat::Name& name, std::string_view decl_kind);
void GenerateDeclarationsMember(const flat::Library* library,
Position position = Position::kSubsequent);
void GenerateExternalDeclarationsEntry(int count, const flat::Name& name,
std::string_view decl_kind,
std::optional<types::Resourceness> maybe_resourceness);
void GenerateExternalDeclarationsMember(const flat::Library* library,
Position position = Position::kSubsequent);
void GenerateTypeShapes(const flat::Object& object);
void GenerateTypeShapes(std::string prefix, const flat::Object& object,
bool is_request_or_response = false);
void GenerateFieldShapes(const flat::Struct::Member& struct_member,
bool is_request_or_response = false);
const flat::Library* library_;
// TODO(fxbug.dev/70247): this is a temporary setting used during the syntax
// migration to allow directly comparing the IR from the old and new syntax
// to ensure that no semantic information has changed.
const bool omit_locations_;
std::ostringstream json_file_;
};
} // namespace fidl
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_JSON_GENERATOR_H_