static_scope.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef EXECUTABLE_SEMANTICS_AST_STATIC_SCOPE_H_
  5. #define EXECUTABLE_SEMANTICS_AST_STATIC_SCOPE_H_
  6. #include <functional>
  7. #include <string>
  8. #include <unordered_map>
  9. #include <variant>
  10. #include <vector>
  11. #include "common/check.h"
  12. #include "common/error.h"
  13. #include "executable_semantics/ast/ast_node.h"
  14. #include "executable_semantics/ast/value_category.h"
  15. #include "executable_semantics/common/nonnull.h"
  16. #include "executable_semantics/common/source_location.h"
  17. #include "llvm/Support/Error.h"
  18. namespace Carbon {
  19. class Value;
  20. // The placeholder name exposed by anonymous ValueNodes.
  21. static constexpr std::string_view AnonymousName = "_";
  22. // ImplementsValueNode is true if NodeType::ImplementsCarbonValueNode
  23. // is valid and names a type, indicating that NodeType implements the
  24. // ValueNode interface, defined below.
  25. template <typename NodeType, typename = void>
  26. static constexpr bool ImplementsValueNode = false;
  27. /*
  28. ValueNode is an interface implemented by AstNodes that can be associated
  29. with a value, such as declarations and bindings. The interface consists of
  30. the following methods:
  31. // Returns the constant associated with the node.
  32. // This is called by the interpreter, not the type checker.
  33. auto constant_value() const -> std::optional<Nonnull<const Value*>>;
  34. // Returns the symbolic compile-time identity of the node.
  35. // This is called by the type checker, not the interpreter.
  36. auto symbolic_identity() const -> std::optional<Nonnull<const Value*>>;
  37. // Returns the static type of an IdentifierExpression that names *this.
  38. auto static_type() const -> const Value&;
  39. // Returns the value category of an IdentifierExpression that names *this.
  40. auto value_category() const -> ValueCategory;
  41. // Print the node's identity (e.g. its name).
  42. void PrintID(llvm::raw_ostream& out) const;
  43. */
  44. // TODO: consider turning the above documentation into real code, as sketched
  45. // at https://godbolt.org/z/186oEozhc
  46. template <typename T>
  47. static constexpr bool
  48. ImplementsValueNode<T, typename T::ImplementsCarbonValueNode> = true;
  49. class ValueNodeView {
  50. public:
  51. template <typename NodeType,
  52. typename = std::enable_if_t<ImplementsValueNode<NodeType>>>
  53. // NOLINTNEXTLINE(google-explicit-constructor)
  54. ValueNodeView(Nonnull<const NodeType*> node)
  55. // Type-erase NodeType, retaining a pointer to the base class AstNode
  56. // and using std::function to encapsulate the ability to call
  57. // the derived class's methods.
  58. : base_(node),
  59. constant_value_(
  60. [](const AstNode& base) -> std::optional<Nonnull<const Value*>> {
  61. return llvm::cast<NodeType>(base).constant_value();
  62. }),
  63. symbolic_identity_(
  64. [](const AstNode& base) -> std::optional<Nonnull<const Value*>> {
  65. return llvm::cast<NodeType>(base).symbolic_identity();
  66. }),
  67. print_([](const AstNode& base, llvm::raw_ostream& out) -> void {
  68. // TODO: change this to print a summary of the node
  69. return llvm::cast<NodeType>(base).PrintID(out);
  70. }),
  71. static_type_([](const AstNode& base) -> const Value& {
  72. return llvm::cast<NodeType>(base).static_type();
  73. }),
  74. value_category_([](const AstNode& base) -> ValueCategory {
  75. return llvm::cast<NodeType>(base).value_category();
  76. }) {}
  77. ValueNodeView(const ValueNodeView&) = default;
  78. ValueNodeView(ValueNodeView&&) = default;
  79. auto operator=(const ValueNodeView&) -> ValueNodeView& = default;
  80. auto operator=(ValueNodeView&&) -> ValueNodeView& = default;
  81. // Returns `node` as an instance of the base class AstNode.
  82. auto base() const -> const AstNode& { return *base_; }
  83. // Returns node->constant_value()
  84. auto constant_value() const -> std::optional<Nonnull<const Value*>> {
  85. return constant_value_(*base_);
  86. }
  87. // Returns node->symbolic_identity()
  88. auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
  89. return symbolic_identity_(*base_);
  90. }
  91. void Print(llvm::raw_ostream& out) const { print_(*base_, out); }
  92. // Returns node->static_type()
  93. auto static_type() const -> const Value& { return static_type_(*base_); }
  94. // Returns node->value_category()
  95. auto value_category() const -> ValueCategory {
  96. return value_category_(*base_);
  97. }
  98. friend auto operator==(const ValueNodeView& lhs, const ValueNodeView& rhs)
  99. -> bool {
  100. return lhs.base_ == rhs.base_;
  101. }
  102. friend auto operator!=(const ValueNodeView& lhs, const ValueNodeView& rhs)
  103. -> bool {
  104. return lhs.base_ != rhs.base_;
  105. }
  106. friend auto operator<(const ValueNodeView& lhs, const ValueNodeView& rhs)
  107. -> bool {
  108. return std::less<>()(lhs.base_, rhs.base_);
  109. }
  110. private:
  111. Nonnull<const AstNode*> base_;
  112. std::function<std::optional<Nonnull<const Value*>>(const AstNode&)>
  113. constant_value_;
  114. std::function<std::optional<Nonnull<const Value*>>(const AstNode&)>
  115. symbolic_identity_;
  116. std::function<void(const AstNode&, llvm::raw_ostream&)> print_;
  117. std::function<const Value&(const AstNode&)> static_type_;
  118. std::function<ValueCategory(const AstNode&)> value_category_;
  119. };
  120. // Maps the names visible in a given scope to the entities they name.
  121. // A scope may have parent scopes, whose names will also be visible in the
  122. // child scope.
  123. class StaticScope {
  124. public:
  125. // Defines `name` to be `entity` in this scope, or reports a compilation error
  126. // if `name` is already defined to be a different entity in this scope.
  127. auto Add(std::string name, ValueNodeView entity) -> ErrorOr<Success>;
  128. // Make `parent` a parent of this scope.
  129. // REQUIRES: `parent` is not already a parent of this scope.
  130. void AddParent(Nonnull<StaticScope*> parent) {
  131. parent_scopes_.push_back(parent);
  132. }
  133. // Returns the nearest definition of `name` in the ancestor graph of this
  134. // scope, or reports a compilation error at `source_loc` there isn't exactly
  135. // one such definition.
  136. auto Resolve(const std::string& name, SourceLocation source_loc) const
  137. -> ErrorOr<ValueNodeView>;
  138. private:
  139. // Equivalent to Resolve, but returns `nullopt` instead of raising an error
  140. // if no definition can be found. Still raises a compilation error if more
  141. // than one definition is found.
  142. auto TryResolve(const std::string& name, SourceLocation source_loc) const
  143. -> ErrorOr<std::optional<ValueNodeView>>;
  144. // Maps locally declared names to their entities.
  145. std::unordered_map<std::string, ValueNodeView> declared_names_;
  146. // A list of scopes used for name lookup within this scope.
  147. std::vector<Nonnull<StaticScope*>> parent_scopes_;
  148. };
  149. } // namespace Carbon
  150. #endif // EXECUTABLE_SEMANTICS_AST_STATIC_SCOPE_H_