blob: ead65e5f1e15c1154b9b43a758f27f556da0c595 [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_SRC_VALUES_H_
#define TOOLS_FIDL_FIDLC_SRC_VALUES_H_
#include <type_traits>
#include "tools/fidl/fidlc/src/properties.h"
#include "tools/fidl/fidlc/src/raw_ast.h"
#include "tools/fidl/fidlc/src/reference.h"
#include "tools/fidl/fidlc/src/source_span.h"
namespace fidlc {
struct Type;
// 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() = default;
enum class Kind : uint8_t {
kInt8,
kInt16,
kInt32,
kInt64,
kUint8,
kZxUchar,
kUint16,
kUint32,
kUint64,
kZxUsize64,
kZxUintptr64,
kFloat32,
kFloat64,
kBool,
kString,
kDocComment,
};
virtual bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const = 0;
virtual std::unique_ptr<ConstantValue> Clone() const = 0;
// If this is a NumericConstantValue<ValueType>, returns the ValueType.
template <typename ValueType>
std::optional<ValueType> AsNumeric() const;
// If this is a NumericConstantValue<uint??_t>, returns it widened to uint64_t.
std::optional<uint64_t> AsUnsigned() const;
// If this is a NumericConstantValue<int??_t> returns it widened to int64_t.
std::optional<int64_t> AsSigned() const;
// If this is StringConstantValue, returns the std::string_view.
std::optional<std::string_view> AsString() const;
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");
explicit NumericConstantValue(ValueType value) : ConstantValue(GetKind()), value(value) {}
bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
std::unique_ptr<ConstantValue> Clone() const override {
return std::make_unique<NumericConstantValue<ValueType>>(value);
}
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;
}
ValueType value;
private:
template <typename TargetType>
bool ConvertTo(std::unique_ptr<ConstantValue>* out_value) const;
};
// A size constant value, e.g. in array<T, size> or vector<T>:size.
using SizeValue = NumericConstantValue<uint32_t>;
// A sentinel value meaning unbounded size, e.g. in vector<T>:MAX.
const uint32_t kMaxSize = UINT32_MAX;
// Handle subtype/rights constant values, e.g. in zx.Handle:<subtype, rights>.
using HandleSubtypeValue = NumericConstantValue<uint32_t>;
using HandleRightsValue = NumericConstantValue<RightsWrappedType>;
template <typename ValueType>
std::optional<ValueType> ConstantValue::AsNumeric() const {
if (kind == NumericConstantValue<ValueType>::GetKind())
return static_cast<const NumericConstantValue<ValueType>*>(this)->value;
return std::nullopt;
}
struct BoolConstantValue final : ConstantValue {
explicit BoolConstantValue(bool value)
: ConstantValue(ConstantValue::Kind::kBool), value(value) {}
bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
std::unique_ptr<ConstantValue> Clone() const override {
return std::make_unique<BoolConstantValue>(value);
}
bool value;
};
struct DocCommentConstantValue final : ConstantValue {
explicit DocCommentConstantValue(std::string_view value)
: ConstantValue(ConstantValue::Kind::kDocComment), value(value) {}
bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
std::unique_ptr<ConstantValue> Clone() const override {
return std::make_unique<DocCommentConstantValue>(value);
}
// Refers to the std::string owned by the RawDocCommentLiteral.
std::string_view value;
};
struct StringConstantValue final : ConstantValue {
explicit StringConstantValue(std::string_view value)
: ConstantValue(ConstantValue::Kind::kString), value(value) {}
bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
std::unique_ptr<ConstantValue> Clone() const override {
return std::make_unique<StringConstantValue>(value);
}
// Refers to the std::string owned by the RawStringLiteral.
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). Every Constant resolves to a concrete ConstantValue.
struct Constant {
virtual ~Constant() = default;
enum class Kind : uint8_t { kIdentifier, kLiteral, kBinaryOperator };
Constant(Kind kind, SourceSpan span) : kind(kind), span(span), value_(nullptr) {}
bool IsResolved() const { return value_ != nullptr; }
void ResolveTo(std::unique_ptr<ConstantValue> value, const Type* type);
const ConstantValue& Value() const;
std::unique_ptr<Constant> Clone() const;
const Kind kind;
const SourceSpan span;
// True if we have attempted to resolve the constant.
bool compiled = false;
// Set when the constant is resolved.
const Type* type = nullptr;
protected:
std::unique_ptr<ConstantValue> value_;
private:
// Helper to implement Clone(). Clones without including compilation state.
virtual std::unique_ptr<Constant> CloneImpl() const = 0;
};
struct IdentifierConstant final : Constant {
IdentifierConstant(Reference reference, SourceSpan span)
: Constant(Kind::kIdentifier, span), reference(std::move(reference)) {}
Reference reference;
private:
std::unique_ptr<Constant> CloneImpl() const override {
return std::make_unique<IdentifierConstant>(reference, span);
}
};
struct LiteralConstant final : Constant {
explicit LiteralConstant(const RawLiteral* literal)
: Constant(Kind::kLiteral, literal->span()), literal(literal) {}
std::unique_ptr<LiteralConstant> CloneLiteralConstant() const {
return std::make_unique<LiteralConstant>(literal);
}
// Owned by Library::raw_literals.
const RawLiteral* literal;
private:
std::unique_ptr<Constant> CloneImpl() const override { return CloneLiteralConstant(); }
};
struct BinaryOperatorConstant final : Constant {
enum class Operator : uint8_t { kOr };
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;
private:
std::unique_ptr<Constant> CloneImpl() const override {
return std::make_unique<BinaryOperatorConstant>(left_operand->Clone(), right_operand->Clone(),
op, span);
}
};
} // namespace fidlc
#endif // TOOLS_FIDL_FIDLC_SRC_VALUES_H_