static_scope.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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 CARBON_EXPLORER_AST_STATIC_SCOPE_H_
  5. #define CARBON_EXPLORER_AST_STATIC_SCOPE_H_
  6. #include <string>
  7. #include <string_view>
  8. #include "common/error.h"
  9. #include "explorer/ast/value_node.h"
  10. #include "explorer/base/nonnull.h"
  11. #include "explorer/base/source_location.h"
  12. #include "explorer/base/trace_stream.h"
  13. #include "llvm/ADT/StringMap.h"
  14. namespace Carbon {
  15. // Maps the names visible in a given scope to the entities they name.
  16. // A scope may have parent scopes, whose names will also be visible in the
  17. // child scope.
  18. class StaticScope {
  19. public:
  20. // The status of a name. Later enumerators with higher values correspond to
  21. // more completely declared names.
  22. enum class NameStatus {
  23. // The name is known to exist in this scope, and any lookups finding it
  24. // should be rejected because it's not declared yet.
  25. KnownButNotDeclared,
  26. // We've started processing a declaration of this name, but it's not yet
  27. // fully declared, so any lookups finding it should be rejected.
  28. DeclaredButNotUsable,
  29. // The name is usable in this context.
  30. Usable,
  31. };
  32. // Construct a root scope.
  33. explicit StaticScope(Nonnull<TraceStream*> trace_stream)
  34. : ast_node_(std::nullopt), trace_stream_(trace_stream) {}
  35. // Construct a scope that is nested within the given scope.
  36. explicit StaticScope(Nonnull<const StaticScope*> parent,
  37. std::optional<Nonnull<const AstNode*>> ast_node)
  38. : parent_scope_(parent),
  39. ast_node_(ast_node),
  40. trace_stream_(parent->trace_stream_) {}
  41. StaticScope() = default;
  42. // Defines `name` to be `entity` in this scope, or reports a compilation error
  43. // if `name` is already defined to be a different entity in this scope.
  44. // If `usable` is `false`, `name` cannot yet be referenced and `Resolve()`
  45. // methods will fail for it.
  46. auto Add(std::string_view name, ValueNodeView entity,
  47. NameStatus status = NameStatus::Usable) -> ErrorOr<Success>;
  48. template <typename Action>
  49. void PrintCommon(Action action) const;
  50. void Print(llvm::raw_ostream& out) const;
  51. void PrintID(llvm::raw_ostream& out) const;
  52. // Marks `name` as being past its point of declaration.
  53. void MarkDeclared(std::string_view name);
  54. // Marks `name` as being completely declared and hence usable.
  55. void MarkUsable(std::string_view name);
  56. // Returns the nearest declaration of `name` in the ancestor graph of this
  57. // scope, or reports a compilation error at `source_loc` there isn't such a
  58. // declaration.
  59. // TODO: This should also diagnose if there's a shadowed declaration of the
  60. // name in an enclosing scope, but does not do so yet.
  61. auto Resolve(std::string_view name, SourceLocation source_loc) const
  62. -> ErrorOr<ValueNodeView>;
  63. // Returns the declaration of `name` in this scope, or reports a compilation
  64. // error at `source_loc` if the name is not declared in this scope. If
  65. // `allow_undeclared` is `true`, names that have been added but not yet marked
  66. // declared or usable do not result in an error.
  67. auto ResolveHere(std::optional<ValueNodeView> this_scope,
  68. std::string_view name, SourceLocation source_loc,
  69. bool allow_undeclared) const -> ErrorOr<ValueNodeView>;
  70. // Returns the value node of the BindingPattern of the returned var definition
  71. // if it exists in the ancestor graph.
  72. auto ResolveReturned() const -> std::optional<ValueNodeView>;
  73. // Adds the value node of the BindingPattern of the returned var definition to
  74. // this scope. Returns a compilation error when there is an existing returned
  75. // var in the ancestor graph.
  76. auto AddReturnedVar(ValueNodeView returned_var_def_view) -> ErrorOr<Success>;
  77. private:
  78. // Equivalent to Resolve, but returns `nullopt` instead of raising an error
  79. // if no declaration can be found.
  80. auto TryResolve(std::string_view name, SourceLocation source_loc) const
  81. -> ErrorOr<std::optional<ValueNodeView>>;
  82. // Equivalent to ResolveHere, but returns `nullopt` if no definition can be
  83. // found. Raises an error if the name is found but is not usable yet.
  84. auto TryResolveHere(std::string_view name, SourceLocation source_loc,
  85. bool allow_undeclared) const
  86. -> ErrorOr<std::optional<ValueNodeView>>;
  87. struct Entry {
  88. ValueNodeView entity;
  89. NameStatus status;
  90. };
  91. // Maps locally declared names to their entities.
  92. llvm::StringMap<Entry> declared_names_;
  93. // The parent scope of this scope, if it not the root scope.
  94. std::optional<Nonnull<const StaticScope*>> parent_scope_;
  95. // Stores the value node of the BindingPattern of the returned var definition.
  96. std::optional<ValueNodeView> returned_var_def_view_;
  97. std::optional<Nonnull<const AstNode*>> ast_node_;
  98. Nonnull<TraceStream*> trace_stream_;
  99. };
  100. } // namespace Carbon
  101. #endif // CARBON_EXPLORER_AST_STATIC_SCOPE_H_