blob: ddf2842096a4b0a3f7594185fc489f2e344dbcc4 [file] [log] [blame]
// Copyright 2020 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_FLAT_VALUES_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_VALUES_H_
namespace fidl {
namespace flat {
// ConstantValue represents the concrete _value_ of a constant. (For the
// _declaration_, see Const. For the _use_, see Constant.) ConstantValue has
// derived classes for all the different kinds of constants.
struct ConstantValue {
virtual ~ConstantValue() {}
enum struct Kind {
kInt8,
kInt16,
kInt32,
kInt64,
kUint8,
kUint16,
kUint32,
kUint64,
kFloat32,
kFloat64,
kBool,
kString,
};
virtual bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const = 0;
const Kind kind;
protected:
explicit ConstantValue(Kind kind) : kind(kind) {}
};
template <typename ValueType>
struct NumericConstantValue final : ConstantValue {
static_assert(std::is_arithmetic<ValueType>::value && !std::is_same<ValueType, bool>::value,
"NumericConstantValue can only be used with a numeric ValueType!");
NumericConstantValue(ValueType value) : ConstantValue(GetKind()), value(value) {}
operator ValueType() const { return value; }
friend bool operator==(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value == r.value;
}
friend bool operator<(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value < r.value;
}
friend bool operator>(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value > r.value;
}
friend bool operator!=(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value != r.value;
}
friend bool operator<=(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value <= r.value;
}
friend bool operator>=(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
return l.value >= r.value;
}
friend NumericConstantValue<ValueType> operator|(const NumericConstantValue<ValueType>& l,
const NumericConstantValue<ValueType>& r) {
static_assert(!std::is_same_v<ValueType, float> && !std::is_same_v<ValueType, double>);
return NumericConstantValue<ValueType>(l.value | r.value);
}
friend std::ostream& operator<<(std::ostream& os, const NumericConstantValue<ValueType>& v) {
if constexpr (GetKind() == Kind::kInt8)
os << static_cast<int>(v.value);
else if constexpr (GetKind() == Kind::kUint8)
os << static_cast<unsigned>(v.value);
else
os << v.value;
return os;
}
virtual bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override {
assert(out_value != nullptr);
auto checked_value = safemath::CheckedNumeric<ValueType>(value);
switch (kind) {
case Kind::kInt8: {
int8_t casted_value;
if (!checked_value.template Cast<int8_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<int8_t>>(casted_value);
return true;
}
case Kind::kInt16: {
int16_t casted_value;
if (!checked_value.template Cast<int16_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<int16_t>>(casted_value);
return true;
}
case Kind::kInt32: {
int32_t casted_value;
if (!checked_value.template Cast<int32_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<int32_t>>(casted_value);
return true;
}
case Kind::kInt64: {
int64_t casted_value;
if (!checked_value.template Cast<int64_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<int64_t>>(casted_value);
return true;
}
case Kind::kUint8: {
uint8_t casted_value;
if (!checked_value.template Cast<uint8_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<uint8_t>>(casted_value);
return true;
}
case Kind::kUint16: {
uint16_t casted_value;
if (!checked_value.template Cast<uint16_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<uint16_t>>(casted_value);
return true;
}
case Kind::kUint32: {
uint32_t casted_value;
if (!checked_value.template Cast<uint32_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<uint32_t>>(casted_value);
return true;
}
case Kind::kUint64: {
uint64_t casted_value;
if (!checked_value.template Cast<uint64_t>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<uint64_t>>(casted_value);
return true;
}
case Kind::kFloat32: {
float casted_value;
if (!checked_value.template Cast<float>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<float>>(casted_value);
return true;
}
case Kind::kFloat64: {
double casted_value;
if (!checked_value.template Cast<double>().AssignIfValid(&casted_value)) {
return false;
}
*out_value = std::make_unique<NumericConstantValue<double>>(casted_value);
return true;
}
case Kind::kString:
case Kind::kBool:
return false;
}
}
static NumericConstantValue<ValueType> Min() {
return NumericConstantValue<ValueType>(std::numeric_limits<ValueType>::lowest());
}
static NumericConstantValue<ValueType> Max() {
return NumericConstantValue<ValueType>(std::numeric_limits<ValueType>::max());
}
ValueType value;
private:
constexpr static Kind GetKind() {
if constexpr (std::is_same_v<ValueType, uint64_t>)
return Kind::kUint64;
if constexpr (std::is_same_v<ValueType, int64_t>)
return Kind::kInt64;
if constexpr (std::is_same_v<ValueType, uint32_t>)
return Kind::kUint32;
if constexpr (std::is_same_v<ValueType, int32_t>)
return Kind::kInt32;
if constexpr (std::is_same_v<ValueType, uint16_t>)
return Kind::kUint16;
if constexpr (std::is_same_v<ValueType, int16_t>)
return Kind::kInt16;
if constexpr (std::is_same_v<ValueType, uint8_t>)
return Kind::kUint8;
if constexpr (std::is_same_v<ValueType, int8_t>)
return Kind::kInt8;
if constexpr (std::is_same_v<ValueType, double>)
return Kind::kFloat64;
if constexpr (std::is_same_v<ValueType, float>)
return Kind::kFloat32;
}
};
using Size = NumericConstantValue<uint32_t>;
struct BoolConstantValue final : ConstantValue {
BoolConstantValue(bool value) : ConstantValue(ConstantValue::Kind::kBool), value(value) {}
operator bool() const { return value; }
friend bool operator==(const BoolConstantValue& l, const BoolConstantValue& r) {
return l.value == r.value;
}
friend bool operator!=(const BoolConstantValue& l, const BoolConstantValue& r) {
return l.value != r.value;
}
friend std::ostream& operator<<(std::ostream& os, const BoolConstantValue& v) {
os << v.value;
return os;
}
virtual bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override {
assert(out_value != nullptr);
switch (kind) {
case Kind::kBool:
*out_value = std::make_unique<BoolConstantValue>(value);
return true;
default:
return false;
}
}
bool value;
};
struct StringConstantValue final : ConstantValue {
explicit StringConstantValue(std::string_view value)
: ConstantValue(ConstantValue::Kind::kString), value(value) {}
friend std::ostream& operator<<(std::ostream& os, const StringConstantValue& v) {
os << v.value.data();
return os;
}
virtual bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override {
assert(out_value != nullptr);
switch (kind) {
case Kind::kString:
*out_value = std::make_unique<StringConstantValue>(std::string_view(value));
return true;
default:
return false;
}
}
std::string_view value;
};
// Constant represents the _use_ of a constant. (For the _declaration_, see
// Const. For the _value_, see ConstantValue.) A Constant can either be a
// reference to another constant (IdentifierConstant), a literal value
// (LiteralConstant), or synthesized by the compiler (SynthesizedConstant).
// Every Constant resolves to a concrete ConstantValue.
struct Constant {
virtual ~Constant() {}
enum struct Kind { kIdentifier, kLiteral, kSynthesized, kBinaryOperator };
explicit Constant(Kind kind, SourceSpan span) : kind(kind), span(span), value_(nullptr) {}
bool IsResolved() const { return value_ != nullptr; }
void ResolveTo(std::unique_ptr<ConstantValue> value) {
assert(value != nullptr);
assert(!IsResolved() && "Constants should only be resolved once!");
value_ = std::move(value);
}
const ConstantValue& Value() const {
if (!IsResolved()) {
std::cout << span.data() << std::endl;
}
assert(IsResolved() && "Accessing the value of an unresolved Constant!");
return *value_;
}
const Kind kind;
const SourceSpan span;
// compiled tracks whether we attempted to resolve this constant, to avoid
// resolving twice a constant which cannot be resolved.
bool compiled = false;
protected:
std::unique_ptr<ConstantValue> value_;
};
struct IdentifierConstant final : Constant {
explicit IdentifierConstant(Name name, SourceSpan span)
: Constant(Kind::kIdentifier, span), name(std::move(name)) {}
const Name name;
};
struct LiteralConstant final : Constant {
explicit LiteralConstant(std::unique_ptr<raw::Literal> literal)
: Constant(Kind::kLiteral, literal->span()), literal(std::move(literal)) {}
std::unique_ptr<raw::Literal> literal;
};
struct SynthesizedConstant final : Constant {
explicit SynthesizedConstant(std::unique_ptr<ConstantValue> value)
: Constant(Kind::kSynthesized, SourceSpan()) {
ResolveTo(std::move(value));
}
};
struct BinaryOperatorConstant final : Constant {
enum struct Operator { kOr };
explicit BinaryOperatorConstant(std::unique_ptr<Constant> left_operand,
std::unique_ptr<Constant> right_operand, Operator op,
SourceSpan span)
: Constant(Kind::kBinaryOperator, span),
left_operand(std::move(left_operand)),
right_operand(std::move(right_operand)),
op(op) {}
const std::unique_ptr<Constant> left_operand;
const std::unique_ptr<Constant> right_operand;
const Operator op;
};
} // namespace flat
} // namespace fidl
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_FLAT_VALUES_H_