blob: b4d81439282ba39e825e3447a4fae7a8a772abae [file] [log] [blame]
// Copyright 2019 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/kazoo/output_util.h"
#include <zircon/assert.h>
#include "tools/kazoo/string_util.h"
bool CopyrightHeaderWithCppComments(Writer* writer) {
return writer->Puts(R"(// Copyright 2019 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.
// WARNING: THIS FILE IS MACHINE GENERATED BY //tools/kazoo. DO NOT EDIT.
)");
}
bool CopyrightHeaderWithHashComments(Writer* writer) {
return writer->Puts(R"(# Copyright 2019 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.
# WARNING: THIS FILE IS MACHINE GENERATED BY //tools/kazoo. DO NOT EDIT.
)");
}
std::string ToLowerAscii(const std::string& input) {
std::string ret = input;
std::transform(ret.begin(), ret.end(), ret.begin(), ToLowerASCII);
return ret;
}
std::string CamelToSnake(const std::string& camel_fidl) {
auto is_transition = [](char prev, char cur, char peek) {
enum { Upper, Lower, Other };
auto categorize = [](char c) {
if (c == 0)
return Other;
if (c >= 'a' && c <= 'z')
return Lower;
if (c >= 'A' && c <= 'Z')
return Upper;
if ((c >= '0' && c <= '9') || c == '_')
return Other;
ZX_ASSERT(false);
return Other;
};
auto prev_type = categorize(prev);
auto cur_type = categorize(cur);
auto peek_type = categorize(peek);
bool lower_to_upper = prev_type != Upper && cur_type == Upper;
bool multiple_caps_to_lower =
peek && (prev_type == Upper && cur_type == Upper && peek_type == Lower);
return lower_to_upper || multiple_caps_to_lower;
};
std::vector<std::string> parts;
char prev = 0;
std::string current_word;
for (size_t i = 0; i < camel_fidl.size(); ++i) {
char cur = camel_fidl[i];
char peek = i + 1 < camel_fidl.size() ? camel_fidl[i + 1] : 0;
if (current_word.size() > 1 && is_transition(prev, cur, peek)) {
parts.push_back(ToLowerAscii(current_word));
current_word = cur;
} else {
current_word += cur;
}
prev = cur;
}
if (!current_word.empty()) {
parts.push_back(ToLowerAscii(current_word));
}
return JoinStrings(parts, "_");
}
namespace {
// Most of the implementation of GetCUserModeName() and GetCKernelModeName(), other than for
// pointers.
std::string CNameImpl(const Type& type) {
struct {
public:
void operator()(const std::monostate&) { ret = "<TODO!>"; }
void operator()(const TypeBool&) { ret = "bool"; }
void operator()(const TypeChar&) { ret = "char"; }
void operator()(const TypeInt32&) { ret = "int32_t"; }
void operator()(const TypeInt64&) { ret = "int64_t"; }
void operator()(const TypeSizeT&) { ret = "size_t"; }
void operator()(const TypeUint16&) { ret = "uint16_t"; }
void operator()(const TypeUint32&) { ret = "uint32_t"; }
void operator()(const TypeUint64&) { ret = "uint64_t"; }
void operator()(const TypeUint8&) { ret = "uint8_t"; }
void operator()(const TypeUintptrT&) { ret = "uintptr_t"; }
void operator()(const TypeVoid&) { ret = "void"; }
void operator()(const TypeZxBasicAlias& zx_basic_alias) { ret = zx_basic_alias.name(); }
void operator()(const TypeEnum& enm) { ret = enm.enum_data().name(); }
void operator()(const TypeHandle& handle) {
ret = "zx_handle_t";
// TOOD(syscall-fidl-transition): Once we're not trying to match abigen, it might be nice to
// add the underlying handle type here like "zx_handle_t /*vmo*/ handle" or similar.
}
void operator()(const TypePointer& pointer) {
ZX_ASSERT(false && "pointers should be handled by caller");
ret = "<!>";
}
void operator()(const TypeString&) {
ZX_ASSERT(false && "can't convert string to C directly");
ret = "<!>";
}
void operator()(const TypeStruct& strukt) { ret = strukt.struct_data().name(); }
void operator()(const TypeVector&) {
ZX_ASSERT(false && "can't convert vector to C directly");
ret = "<!>";
}
Constness constness;
std::string ret;
} name_visitor;
name_visitor.constness = type.constness();
std::visit(name_visitor, type.type_data());
return name_visitor.ret;
}
} // namespace
std::string GetCUserModeName(const Type& type) {
if (type.IsPointer()) {
ZX_ASSERT(type.constness() != Constness::kUnspecified &&
"Pointer should be explictly const or mutable by output time");
return (type.constness() == Constness::kConst ? "const " : "") +
GetCUserModeName(type.DataAsPointer().pointed_to_type()) + "*";
}
return CNameImpl(type);
}
std::string GetCKernelModeName(const Type& type) {
if (type.IsPointer()) {
ZX_ASSERT(type.constness() != Constness::kUnspecified &&
"Pointer should be explictly const or mutable by output time");
std::string pointed_to = GetCKernelModeName(type.DataAsPointer().pointed_to_type());
if (type.constness() == Constness::kConst) {
return StringPrintf("user_in_ptr<const %s>", pointed_to.c_str());
} else if (type.constness() == Constness::kMutable) {
if (pointed_to == "zx_handle_t" && !type.DataAsPointer().was_vector()) {
return "user_out_handle*";
}
if (type.optionality() == Optionality::kInputArgument) {
return StringPrintf("user_inout_ptr<%s>", pointed_to.c_str());
} else {
return StringPrintf("user_out_ptr<%s>", pointed_to.c_str());
}
}
}
return CNameImpl(type);
}
JsonTypeNameData GetJsonName(const Type& type) {
JsonTypeNameData ret;
if (type.IsPointer()) {
ret.name = GetCUserModeName(type.DataAsPointer().pointed_to_type());
ret.is_pointer = true;
if (type.constness() == Constness::kConst) {
ret.attribute = "IN";
} else if (type.constness() == Constness::kMutable) {
if (type.optionality() == Optionality::kInputArgument) {
ret.attribute = "INOUT";
} else if (type.optionality() == Optionality::kOutputNonOptional) {
ret.attribute = "OUT";
} else if (type.optionality() == Optionality::kOutputOptional) {
ret.attribute = "optional";
}
}
if (ret.name == "void") {
ret.name = "any";
}
} else {
ret.name = GetCUserModeName(type);
}
return ret;
}
void CSignatureLine(const Syscall& syscall, const char* prefix, const char* name_prefix,
Writer* writer, SignatureNewlineStyle newline_style,
std::vector<std::string>* non_nulls) {
const char* newline = newline_style == SignatureNewlineStyle::kAllOneLine ? "" : "\n";
const char* indent = newline_style == SignatureNewlineStyle::kAllOneLine ? "" : " ";
writer->Puts(prefix);
writer->Printf("%s ", GetCUserModeName(syscall.kernel_return_type()).c_str());
writer->Printf("%s%s(%s", name_prefix, syscall.name().c_str(), newline);
if (syscall.kernel_arguments().size() == 0) {
if (newline_style == SignatureNewlineStyle::kOnePerLine) {
writer->Puts(indent);
}
writer->Puts("void");
} else {
for (size_t i = 0; i < syscall.kernel_arguments().size(); ++i) {
const StructMember& arg = syscall.kernel_arguments()[i];
const bool last = i == syscall.kernel_arguments().size() - 1;
if (newline_style == SignatureNewlineStyle::kOnePerLine) {
writer->Puts(" "); // All indented if one per line.
} else if (i != 0) {
writer->Puts(" "); // No space after open ( for single line.
}
writer->Printf("%s %s", GetCUserModeName(arg.type()).c_str(), arg.name().c_str());
if (!last) {
writer->Printf(",%s", newline);
}
if (arg.type().IsPointer() && arg.type().optionality() == Optionality::kOutputNonOptional) {
if (non_nulls) {
non_nulls->push_back(StringPrintf("%zu", i + 1));
}
}
}
}
writer->Printf(")");
}
void CDeclaration(const Syscall& syscall, const char* prefix, const char* name_prefix,
Writer* writer) {
std::vector<std::string> non_nulls;
CSignatureLine(syscall, prefix, name_prefix, writer, SignatureNewlineStyle::kOnePerLine,
&non_nulls);
// TODO(syscall-fidl-transition): The order of these post-declaration markup is maintained, but
// perhaps it could be simplified once it doesn't need to match.
if (!non_nulls.empty()) {
// TODO(syscall-fidl-transition): abigen only tags non-optional arguments as non-null, but
// other input pointers could also perhaps be usefully tagged as well.
writer->Printf(" __NONNULL((%s))", JoinStrings(non_nulls, ", ").c_str());
}
writer->Printf(" __LEAF_FN");
if (syscall.HasAttribute("Const")) {
writer->Puts(" __CONST");
}
if (syscall.HasAttribute("Noreturn")) {
writer->Puts(" __NO_RETURN");
}
writer->Puts(";\n\n");
}