blob: 45316a55fd752bb3d78402236905d2d29bc62acb [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.
#include "tools/fidl/fidlc/src/values.h"
#include <zircon/assert.h>
#include "tools/fidl/fidlc/src/utils.h"
namespace fidlc {
// TODO(https://fxbug.dev/42064981): Use std::cmp_* functions when we're on C++20.
// https://en.cppreference.com/w/cpp/utility/intcmp#Possible_implementation
template <class T, class U>
constexpr bool cmp_less(T t, U u) noexcept {
if constexpr (std::is_signed_v<T> == std::is_signed_v<U>)
return t < u;
if constexpr (std::is_signed_v<T>)
return t < 0 || std::make_unsigned_t<T>(t) < u;
return u >= 0 && t < std::make_unsigned_t<U>(u);
}
// TODO(https://fxbug.dev/42064981): Use std::in_range when we're on C++20.
template <class R, class T>
constexpr bool in_range(T t) noexcept {
return !cmp_less(t, std::numeric_limits<R>::min()) && !cmp_less(std::numeric_limits<R>::max(), t);
}
// Explicit instantiations.
template struct NumericConstantValue<int8_t>;
template struct NumericConstantValue<int16_t>;
template struct NumericConstantValue<int32_t>;
template struct NumericConstantValue<int64_t>;
template struct NumericConstantValue<uint8_t>;
template struct NumericConstantValue<uint16_t>;
template struct NumericConstantValue<uint32_t>;
template struct NumericConstantValue<uint64_t>;
template struct NumericConstantValue<float>;
template struct NumericConstantValue<double>;
template <typename ValueType>
bool NumericConstantValue<ValueType>::Convert(Kind kind,
std::unique_ptr<ConstantValue>* out_value) const {
ZX_ASSERT(out_value != nullptr);
switch (kind) {
case Kind::kInt8:
return ConvertTo<int8_t>(out_value);
case Kind::kInt16:
return ConvertTo<int16_t>(out_value);
case Kind::kInt32:
return ConvertTo<int32_t>(out_value);
case Kind::kInt64:
return ConvertTo<int64_t>(out_value);
case Kind::kUint8:
case Kind::kZxUchar:
return ConvertTo<uint8_t>(out_value);
case Kind::kUint16:
return ConvertTo<uint16_t>(out_value);
case Kind::kUint32:
return ConvertTo<uint32_t>(out_value);
case Kind::kUint64:
case Kind::kZxUsize64:
case Kind::kZxUintptr64:
return ConvertTo<uint64_t>(out_value);
case Kind::kFloat32:
return ConvertTo<float>(out_value);
case Kind::kFloat64:
return ConvertTo<double>(out_value);
case Kind::kDocComment:
case Kind::kString:
case Kind::kBool:
return false;
}
}
template <typename ValueType>
template <typename TargetType>
bool NumericConstantValue<ValueType>::ConvertTo(std::unique_ptr<ConstantValue>* out_value) const {
if constexpr (std::is_integral_v<ValueType>) {
if constexpr (!std::is_integral_v<TargetType>) {
return false;
} else if (!in_range<TargetType>(value)) {
return false;
}
} else if constexpr (std::is_floating_point_v<ValueType>) {
if constexpr (!std::is_floating_point_v<TargetType>) {
return false;
} else if (value < std::numeric_limits<TargetType>::lowest() ||
value > std::numeric_limits<TargetType>::max()) {
return false;
}
} else {
static_assert(false, "NumericConstantValue must hold integer or float");
}
*out_value = std::make_unique<NumericConstantValue<TargetType>>(value);
return true;
}
bool BoolConstantValue::Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const {
ZX_ASSERT(out_value != nullptr);
switch (kind) {
case Kind::kBool:
*out_value = std::make_unique<BoolConstantValue>(value);
return true;
default:
return false;
}
}
bool DocCommentConstantValue::Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const {
ZX_ASSERT(out_value != nullptr);
switch (kind) {
case Kind::kDocComment:
*out_value = std::make_unique<DocCommentConstantValue>(std::string_view(value));
return true;
default:
return false;
}
}
bool StringConstantValue::Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const {
ZX_ASSERT(out_value != nullptr);
switch (kind) {
case Kind::kString:
*out_value = std::make_unique<StringConstantValue>(std::string_view(value));
return true;
default:
return false;
}
}
void Constant::ResolveTo(std::unique_ptr<ConstantValue> value, const Type* type) {
ZX_ASSERT(value != nullptr);
ZX_ASSERT_MSG(!IsResolved(), "constants should only be resolved once");
value_ = std::move(value);
this->type = type;
}
const ConstantValue& Constant::Value() const {
ZX_ASSERT_MSG(IsResolved(), "accessing the value of an unresolved Constant: %s",
std::string(span.data()).c_str());
return *value_;
}
std::unique_ptr<Constant> Constant::Clone() const {
auto cloned = CloneImpl();
cloned->compiled = compiled;
cloned->type = type;
cloned->value_ = value_ ? value_->Clone() : nullptr;
return cloned;
}
} // namespace fidlc