// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_ #define EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_ #include #include #include #include #include "common/ostream.h" #include "executable_semantics/ast/declaration.h" #include "executable_semantics/ast/statement.h" #include "executable_semantics/common/nonnull.h" #include "executable_semantics/interpreter/address.h" #include "executable_semantics/interpreter/field_path.h" #include "executable_semantics/interpreter/stack.h" #include "llvm/Support/Compiler.h" namespace Carbon { class Action; // Abstract base class of all AST nodes representing values. // // Value and its derived classes support LLVM-style RTTI, including // llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every // class derived from Value must provide a `classof` operation, and // every concrete derived class must have a corresponding enumerator // in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for // details. class Value { public: enum class Kind { IntValue, FunctionValue, LValue, BoolValue, StructValue, NominalClassValue, AlternativeValue, TupleValue, IntType, BoolType, TypeType, FunctionType, PointerType, AutoType, StructType, NominalClassType, ChoiceType, ContinuationType, // The type of a continuation. VariableType, // e.g., generic type parameters. BindingPlaceholderValue, AlternativeConstructorValue, ContinuationValue, // A first-class continuation value. StringType, StringValue, TypeOfClassType, TypeOfChoiceType, }; Value(const Value&) = delete; auto operator=(const Value&) -> Value& = delete; void Print(llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } // Returns the sub-Value specified by `path`, which must be a valid field // path for *this. auto GetField(Nonnull arena, const FieldPath& path, SourceLocation source_loc) const -> Nonnull; // Returns a copy of *this, but with the sub-Value specified by `path` // set to `field_value`. `path` must be a valid field path for *this. auto SetField(Nonnull arena, const FieldPath& path, Nonnull field_value, SourceLocation source_loc) const -> Nonnull; // Returns the enumerator corresponding to the most-derived type of this // object. auto kind() const -> Kind { return kind_; } protected: // Constructs a Value. `kind` must be the enumerator corresponding to the // most-derived type being constructed. explicit Value(Kind kind) : kind_(kind) {} private: const Kind kind_; }; // A NamedValue represents a value with a name, such as a single struct field. struct NamedValue { // The field name. std::string name; // The field's value. Nonnull value; }; // An integer value. class IntValue : public Value { public: explicit IntValue(int value) : Value(Kind::IntValue), value_(value) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::IntValue; } auto value() const -> int { return value_; } private: int value_; }; // A function value. class FunctionValue : public Value { public: explicit FunctionValue(Nonnull declaration) : Value(Kind::FunctionValue), declaration_(declaration) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::FunctionValue; } auto declaration() const -> const FunctionDeclaration& { return *declaration_; } private: Nonnull declaration_; }; // The value of a location in memory. class LValue : public Value { public: explicit LValue(Address value) : Value(Kind::LValue), value_(std::move(value)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::LValue; } auto address() const -> const Address& { return value_; } private: Address value_; }; // A bool value. class BoolValue : public Value { public: explicit BoolValue(bool value) : Value(Kind::BoolValue), value_(value) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::BoolValue; } auto value() const -> bool { return value_; } private: bool value_; }; // A non-empty value of a struct type. // // It can't be empty because `{}` is a struct type as well as a value of that // type, so for consistency we always represent it as a StructType rather than // let it oscillate unpredictably between the two. However, this means code // that handles StructValue instances may also need to be able to handle // StructType instances. class StructValue : public Value { public: explicit StructValue(std::vector elements) : Value(Kind::StructValue), elements_(std::move(elements)) { CHECK(!elements_.empty()) << "`{}` is represented as a StructType, not a StructValue."; } static auto classof(const Value* value) -> bool { return value->kind() == Kind::StructValue; } auto elements() const -> llvm::ArrayRef { return elements_; } // Returns the value of the field named `name` in this struct, or // nullopt if there is no such field. auto FindField(const std::string& name) const -> std::optional>; private: std::vector elements_; }; // A value of a nominal class type. class NominalClassValue : public Value { public: NominalClassValue(Nonnull type, Nonnull inits) : Value(Kind::NominalClassValue), type_(type), inits_(inits) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::NominalClassValue; } auto type() const -> const Value& { return *type_; } auto inits() const -> const Value& { return *inits_; } private: Nonnull type_; Nonnull inits_; }; // An alternative constructor value. class AlternativeConstructorValue : public Value { public: AlternativeConstructorValue(std::string alt_name, std::string choice_name) : Value(Kind::AlternativeConstructorValue), alt_name_(std::move(alt_name)), choice_name_(std::move(choice_name)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::AlternativeConstructorValue; } auto alt_name() const -> const std::string& { return alt_name_; } auto choice_name() const -> const std::string& { return choice_name_; } private: std::string alt_name_; std::string choice_name_; }; // An alternative value. class AlternativeValue : public Value { public: AlternativeValue(std::string alt_name, std::string choice_name, Nonnull argument) : Value(Kind::AlternativeValue), alt_name_(std::move(alt_name)), choice_name_(std::move(choice_name)), argument_(argument) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::AlternativeValue; } auto alt_name() const -> const std::string& { return alt_name_; } auto choice_name() const -> const std::string& { return choice_name_; } auto argument() const -> const Value& { return *argument_; } private: std::string alt_name_; std::string choice_name_; Nonnull argument_; }; // A function value. class TupleValue : public Value { public: // An empty tuple, also known as the unit type. static auto Empty() -> Nonnull { static const TupleValue empty = TupleValue(std::vector>()); return Nonnull(&empty); } explicit TupleValue(std::vector> elements) : Value(Kind::TupleValue), elements_(std::move(elements)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::TupleValue; } auto elements() const -> llvm::ArrayRef> { return elements_; } private: std::vector> elements_; }; // A binding placeholder value. class BindingPlaceholderValue : public Value { public: // Represents the `_` placeholder. explicit BindingPlaceholderValue() : Value(Kind::BindingPlaceholderValue) {} // Represents a named placeholder. explicit BindingPlaceholderValue(NamedEntityView named_entity) : Value(Kind::BindingPlaceholderValue), named_entity_(std::move(named_entity)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::BindingPlaceholderValue; } auto named_entity() const -> const std::optional& { return named_entity_; } private: std::optional named_entity_; }; // The int type. class IntType : public Value { public: IntType() : Value(Kind::IntType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::IntType; } }; // The bool type. class BoolType : public Value { public: BoolType() : Value(Kind::BoolType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::BoolType; } }; // A type type. class TypeType : public Value { public: TypeType() : Value(Kind::TypeType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::TypeType; } }; // A function type. class FunctionType : public Value { public: FunctionType(llvm::ArrayRef> deduced, Nonnull parameters, Nonnull return_type) : Value(Kind::FunctionType), deduced_(deduced), parameters_(parameters), return_type_(return_type) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::FunctionType; } auto deduced() const -> llvm::ArrayRef> { return deduced_; } auto parameters() const -> const Value& { return *parameters_; } auto return_type() const -> const Value& { return *return_type_; } private: std::vector> deduced_; Nonnull parameters_; Nonnull return_type_; }; // A pointer type. class PointerType : public Value { public: explicit PointerType(Nonnull type) : Value(Kind::PointerType), type_(type) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::PointerType; } auto type() const -> const Value& { return *type_; } private: Nonnull type_; }; // The `auto` type. class AutoType : public Value { public: AutoType() : Value(Kind::AutoType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::AutoType; } }; // A struct type. // // Code that handles this type may sometimes need to have special-case handling // for `{}`, which is a struct value in addition to being a struct type. class StructType : public Value { public: StructType() : StructType(std::vector{}) {} explicit StructType(std::vector fields) : Value(Kind::StructType), fields_(std::move(fields)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::StructType; } auto fields() const -> llvm::ArrayRef { return fields_; } private: std::vector fields_; }; // A class type. class NominalClassType : public Value { public: NominalClassType(std::string name, std::vector fields, std::vector methods) : Value(Kind::NominalClassType), name_(std::move(name)), fields_(std::move(fields)), methods_(std::move(methods)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::NominalClassType; } auto name() const -> const std::string& { return name_; } auto fields() const -> llvm::ArrayRef { return fields_; } auto methods() const -> llvm::ArrayRef { return methods_; } private: std::string name_; std::vector fields_; std::vector methods_; }; // A choice type. class ChoiceType : public Value { public: ChoiceType(std::string name, std::vector alternatives) : Value(Kind::ChoiceType), name_(std::move(name)), alternatives_(std::move(alternatives)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::ChoiceType; } auto name() const -> const std::string& { return name_; } // Returns the parameter types of the alternative with the given name, // or nullopt if no such alternative is present. auto FindAlternative(std::string_view name) const -> std::optional>; private: std::string name_; std::vector alternatives_; }; // A continuation type. class ContinuationType : public Value { public: ContinuationType() : Value(Kind::ContinuationType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::ContinuationType; } }; // A variable type. class VariableType : public Value { public: explicit VariableType(Nonnull binding) : Value(Kind::VariableType), binding_(binding) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::VariableType; } auto binding() const -> const GenericBinding& { return *binding_; } private: Nonnull binding_; }; // A first-class continuation representation of a fragment of the stack. // A continuation value behaves like a pointer to the underlying stack // fragment, which is exposed by `Stack()`. class ContinuationValue : public Value { public: class StackFragment { public: // Constructs an empty StackFragment. StackFragment() = default; // Requires *this to be empty, because by the time we're tearing down the // Arena, it's no longer safe to invoke ~Action. ~StackFragment(); StackFragment(StackFragment&&) = delete; auto operator=(StackFragment&&) -> StackFragment& = delete; // Store the given partial todo stack in *this, which must currently be // empty. The stack is represented with the top of the stack at the // beginning of the vector, the reverse of the usual order. void StoreReversed(std::vector> reversed_todo); // Restore the currently stored stack fragment to the top of `todo`, // leaving *this empty. void RestoreTo(Stack>& todo); // Destroy the currently stored stack fragment. void Clear(); void Print(llvm::raw_ostream& out) const; LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); } private: // The todo stack of a suspended continuation, starting with the top // Action. std::vector> reversed_todo_; }; explicit ContinuationValue(Nonnull stack) : Value(Kind::ContinuationValue), stack_(stack) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::ContinuationValue; } // The todo stack of the suspended continuation. Note that this provides // mutable access, even when *this is const, because of the reference-like // semantics of ContinuationValue. auto stack() const -> StackFragment& { return *stack_; } private: Nonnull stack_; }; // The String type. class StringType : public Value { public: StringType() : Value(Kind::StringType) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::StringType; } }; // A string value. class StringValue : public Value { public: explicit StringValue(std::string value) : Value(Kind::StringValue), value_(std::move(value)) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::StringValue; } auto value() const -> const std::string& { return value_; } private: std::string value_; }; // The type of an expression whose value is a class type. Currently there is no // way to explicitly name such a type in Carbon code, but we are tentatively // using `typeof(ClassName)` as the debug-printing format, in anticipation of // something like that becoming valid Carbon syntax. class TypeOfClassType : public Value { public: explicit TypeOfClassType(Nonnull class_type) : Value(Kind::TypeOfClassType), class_type_(class_type) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::TypeOfClassType; } auto class_type() const -> const NominalClassType& { return *class_type_; } private: Nonnull class_type_; }; // The type of an expression whose value is a choice type. Currently there is no // way to explicitly name such a type in Carbon code, but we are tentatively // using `typeof(ChoiceName)` as the debug-printing format, in anticipation of // something like that becoming valid Carbon syntax. class TypeOfChoiceType : public Value { public: explicit TypeOfChoiceType(Nonnull choice_type) : Value(Kind::TypeOfChoiceType), choice_type_(choice_type) {} static auto classof(const Value* value) -> bool { return value->kind() == Kind::TypeOfChoiceType; } auto choice_type() const -> const ChoiceType& { return *choice_type_; } private: Nonnull choice_type_; }; auto TypeEqual(Nonnull t1, Nonnull t2) -> bool; auto ValueEqual(Nonnull v1, Nonnull v2) -> bool; } // namespace Carbon #endif // EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_