blob: cfd2bfe462ee6296c4f577101df0d02072f5f0ad [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 <string_view>
#include "tools/kazoo/string_util.h"
void CopyrightHeaderWithCppComments(Writer* writer) {
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.
)");
}
void CopyrightHeaderWithHashComments(Writer* writer) {
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 ToUpperAscii(const std::string& input) {
std::string ret = input;
std::transform(ret.begin(), ret.end(), ret.begin(), ToUpperASCII);
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_MSG(false, "%c is unexpected character", c);
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 TypeAlias& alias) { ret = "zx_" + alias.alias_data().base_name() + "_t"; }
void operator()(const TypeEnum& enm) { ret = "zx_" + enm.enum_data().base_name() + "_t"; }
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 = "zx_" + strukt.struct_data().base_name() + "_t";
}
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 explicitly 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;
}
namespace {
std::string GetGoNameImpl(const Type& type) {
struct {
public:
void operator()(const std::monostate&) { ret = "<TODO!>"; }
void operator()(const TypeBool&) { ret = "bool"; }
void operator()(const TypeChar&) { ret = "uint8"; }
void operator()(const TypeInt32&) { ret = "int32"; }
void operator()(const TypeInt64&) { ret = "int64"; }
void operator()(const TypeSizeT&) { ret = "uint"; }
void operator()(const TypeUint16&) { ret = "uint16"; }
void operator()(const TypeUint32&) { ret = "uint32"; }
void operator()(const TypeUint64&) { ret = "uint64"; }
void operator()(const TypeUint8&) { ret = "uint8"; }
void operator()(const TypeUintptrT&) { ret = "uintptr"; }
void operator()(const TypeVoid&) { ret = "void"; }
void operator()(const TypeZxBasicAlias& zx_basic_alias) { ret = zx_basic_alias.go_name(); }
void operator()(const TypeAlias& alias) { ret = "<TODO!>"; }
void operator()(const TypeEnum& enm) { ret = "zx_" + enm.enum_data().base_name() + "_t"; }
void operator()(const TypeHandle& handle) { ret = "Handle"; }
void operator()(const TypePointer& pointer) {
if (pointer.pointed_to_type().IsVoid()) {
ret = "unsafe.Pointer";
} else {
ret = "*" + GetGoName(pointer.pointed_to_type());
}
}
void operator()(const TypeString&) {
ZX_ASSERT(false && "can't convert string directly");
ret = "<!>";
}
void operator()(const TypeStruct& strukt) {
ret = "zx_" + strukt.struct_data().base_name() + "_t";
}
void operator()(const TypeVector&) {
ZX_ASSERT(false && "can't convert vector 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 GetGoName(const Type& type) {
// Most of the "normal" implementation is in GetGoNameImpl(), and then we do
// a few hacks here to make it match the previous output of the Go-written
// tool that parsed abigen directly.
// TODO(scottmg|dhobsd): Remove or rationalize these over time.
std::string name = GetGoNameImpl(type);
if (name == "Futex")
return "int32";
if (name == "Koid")
return "uint64";
if (name == "Ticks")
return "int64";
if (name == "Vm_option")
return "VMFlag";
if (name == "zx_channel_call_args_t")
return "ChannelCallArgs";
if (name == "zx_clock_t")
return "uint32";
if (name == "zx_handle_disposition_t")
return "HandleDisposition";
if (name == "zx_handle_info_t")
return "int";
if (name == "zx_pci_bar_t")
return "uintptr";
if (name == "zx_pci_init_arg_t")
return "uintptr";
if (name == "zx_pcie_device_info_t")
return "uintptr";
if (name == "zx_port_packet_t")
return "int";
if (name == "zx_profile_info_t")
return "int";
if (name == "zx_rights_t")
return "Rights";
if (name == "zx_smc_parameters_t")
return "SMCParameters";
if (name == "zx_smc_result_t")
return "SMCResult";
if (name == "zx_system_powerctl_arg_t")
return "int";
if (name == "zx_wait_item_t")
return "WaitItem";
return name;
}
// Returns a size-compatible Go native type.
std::string GetNativeGoName(const Type& type) {
if (type.IsPointer()) {
return "unsafe.Pointer";
}
std::string name = GetGoNameImpl(type);
// Most of the "normal" implementation is in GetGoNameImpl(), and then we do
// a few hacks here to make it match the previous output of the Go-written
// tool that parsed abigen directly.
// TODO(scottmg|dhobsd): Remove or rationalize these over time.
if (name == "Duration")
return "int64";
if (name == "Futex")
return "int32";
if (name == "Handle")
return "uint32";
if (name == "Koid")
return "uint64";
if (name == "Paddr")
return "uintptr";
if (name == "Signals")
return "uint32";
if (name == "Status")
return "int32";
if (name == "Ticks")
return "int64";
if (name == "Time")
return "int64";
if (name == "Vaddr")
return "uintptr";
if (name == "Vm_option")
return "uint32";
if (name == "zx_channel_call_args_t")
return "uintptr";
if (name == "zx_clock_t")
return "uint32";
if (name == "zx_handle_disposition_t")
return "uintptr";
if (name == "zx_handle_info_t")
return "int";
if (name == "zx_pci_bar_t")
return "uintptr";
if (name == "zx_pci_init_arg_t")
return "uintptr";
if (name == "zx_pcie_device_info_t")
return "uintptr";
if (name == "zx_port_packet_t")
return "int";
if (name == "zx_profile_info_t")
return "int";
if (name == "zx_rights_t")
return "uint32";
if (name == "zx_smc_parameters_t")
return "uintptr";
if (name == "zx_smc_result_t")
return "uintptr";
if (name == "zx_system_powerctl_arg_t")
return "int";
if (name == "zx_wait_item_t")
return "uintptr";
return name;
}
std::string RemapReservedGoName(const std::string& name) {
// Probably more of these and/or a better way to do this, but this handles current syscalls.
if (name == "type")
return "typ";
if (name == "func")
return "funk";
if (name == "g")
return "g_";
return name;
}
// http://www.cse.yorku.ca/~oz/hash.html
// Used by Go output, taken from
// https://fuchsia.googlesource.com/third_party/go/+/ae00e6ff359966a496acacc3aa386c79e972279d/src/runtime/mkfuchsiavdso.go#36
// TODO(scottmg): Not clear on whether this must match something in Go internals.
uint32_t DJBHash(const std::string& str) {
uint32_t h = 5381;
for (const auto& c : str) {
h = (h << 5) + h + static_cast<uint32_t>(c);
}
return h;
}