action_stack.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. #include "explorer/interpreter/action_stack.h"
  5. #include "common/error.h"
  6. #include "explorer/interpreter/action.h"
  7. #include "llvm/ADT/StringExtras.h"
  8. #include "llvm/Support/Casting.h"
  9. #include "llvm/Support/Error.h"
  10. namespace Carbon {
  11. void ActionStack::Print(llvm::raw_ostream& out) const {
  12. llvm::ListSeparator sep(" ## ");
  13. for (const std::unique_ptr<Action>& action : todo_) {
  14. out << sep << *action;
  15. }
  16. }
  17. void ActionStack::Start(std::unique_ptr<Action> action) {
  18. result_ = std::nullopt;
  19. CARBON_CHECK(todo_.IsEmpty());
  20. todo_.Push(std::move(action));
  21. }
  22. void ActionStack::Initialize(ValueNodeView value_node,
  23. Nonnull<const Value*> value) {
  24. for (const std::unique_ptr<Action>& action : todo_) {
  25. if (action->scope().has_value()) {
  26. action->scope()->Initialize(value_node, value);
  27. return;
  28. }
  29. }
  30. globals_->Initialize(value_node, value);
  31. }
  32. auto ActionStack::ValueOfNode(ValueNodeView value_node,
  33. SourceLocation source_loc) const
  34. -> ErrorOr<Nonnull<const Value*>> {
  35. std::optional<const Value*> constant_value = value_node.constant_value();
  36. if (constant_value.has_value()) {
  37. return *constant_value;
  38. }
  39. for (const std::unique_ptr<Action>& action : todo_) {
  40. // TODO: have static name resolution identify the scope of value_node
  41. // as an AstNode, and then perform lookup _only_ on the Action associated
  42. // with that node. This will help keep unwanted dynamic-scoping behavior
  43. // from sneaking in.
  44. if (action->scope().has_value()) {
  45. std::optional<Nonnull<const Value*>> result =
  46. action->scope()->Get(value_node);
  47. if (result.has_value()) {
  48. return *result;
  49. }
  50. }
  51. }
  52. if (globals_.has_value()) {
  53. std::optional<Nonnull<const Value*>> result = globals_->Get(value_node);
  54. if (result.has_value()) {
  55. return *result;
  56. }
  57. }
  58. // We don't know the value of this node, but at compile time we may still be
  59. // able to form a symbolic value for it. For example, in
  60. //
  61. // fn F[T:! type](x: T) {}
  62. //
  63. // ... we don't know the value of `T` but can still symbolically evaluate it
  64. // to a `VariableType`. At runtime we need actual values.
  65. if (phase_ == Phase::CompileTime) {
  66. std::optional<const Value*> symbolic_identity =
  67. value_node.symbolic_identity();
  68. if (symbolic_identity.has_value()) {
  69. return *symbolic_identity;
  70. }
  71. }
  72. // TODO: Move these errors to compile time and explain them more clearly.
  73. return ProgramError(source_loc)
  74. << "could not find `" << value_node.base() << "`";
  75. }
  76. void ActionStack::MergeScope(RuntimeScope scope) {
  77. for (const std::unique_ptr<Action>& action : todo_) {
  78. if (action->scope().has_value()) {
  79. action->scope()->Merge(std::move(scope));
  80. return;
  81. }
  82. }
  83. if (globals_.has_value()) {
  84. globals_->Merge(std::move(scope));
  85. return;
  86. }
  87. CARBON_FATAL() << "No current scope";
  88. }
  89. namespace {
  90. // The way in which FinishAction should be called for a particular kind of
  91. // action.
  92. enum class FinishActionKind {
  93. // FinishAction should not be passed a value.
  94. NoValue,
  95. // FinishAction should be passed a value.
  96. Value,
  97. // FinishAction should not be called. The Action needs custom handling.
  98. NeverCalled,
  99. };
  100. } // namespace
  101. static auto FinishActionKindFor(Action::Kind kind) -> FinishActionKind {
  102. switch (kind) {
  103. case Action::Kind::ExpressionAction:
  104. case Action::Kind::WitnessAction:
  105. case Action::Kind::LocationAction:
  106. case Action::Kind::TypeInstantiationAction:
  107. return FinishActionKind::Value;
  108. case Action::Kind::StatementAction:
  109. case Action::Kind::DeclarationAction:
  110. case Action::Kind::RecursiveAction:
  111. return FinishActionKind::NoValue;
  112. case Action::Kind::ScopeAction:
  113. case Action::Kind::CleanUpAction:
  114. case Action::Kind::DestroyAction:
  115. return FinishActionKind::NeverCalled;
  116. }
  117. }
  118. auto ActionStack::FinishAction() -> ErrorOr<Success> {
  119. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  120. std::unique_ptr<Action> act = todo_.Pop();
  121. switch (FinishActionKindFor(act->kind())) {
  122. case FinishActionKind::Value:
  123. CARBON_FATAL() << "This kind of action must produce a result: " << *act;
  124. case FinishActionKind::NeverCalled:
  125. CARBON_FATAL() << "Should not call FinishAction for: " << *act;
  126. case FinishActionKind::NoValue:
  127. PopScopes(scopes_to_destroy);
  128. break;
  129. }
  130. PushCleanUpAction(std::move(act));
  131. PushCleanUpActions(std::move(scopes_to_destroy));
  132. return Success();
  133. }
  134. auto ActionStack::FinishAction(Nonnull<const Value*> result)
  135. -> ErrorOr<Success> {
  136. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  137. std::unique_ptr<Action> act = todo_.Pop();
  138. switch (FinishActionKindFor(act->kind())) {
  139. case FinishActionKind::NoValue:
  140. CARBON_FATAL() << "This kind of action cannot produce results: " << *act;
  141. case FinishActionKind::NeverCalled:
  142. CARBON_FATAL() << "Should not call FinishAction for: " << *act;
  143. case FinishActionKind::Value:
  144. PopScopes(scopes_to_destroy);
  145. SetResult(result);
  146. break;
  147. }
  148. PushCleanUpAction(std::move(act));
  149. PushCleanUpActions(std::move(scopes_to_destroy));
  150. return Success();
  151. }
  152. auto ActionStack::Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success> {
  153. Action& action = *todo_.Top();
  154. action.set_pos(action.pos() + 1);
  155. todo_.Push(std::move(child));
  156. return Success();
  157. }
  158. auto ActionStack::Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
  159. -> ErrorOr<Success> {
  160. Action& action = *todo_.Top();
  161. action.set_pos(action.pos() + 1);
  162. todo_.Push(std::make_unique<ScopeAction>(std::move(scope)));
  163. todo_.Push(std::move(child));
  164. return Success();
  165. }
  166. auto ActionStack::ReplaceWith(std::unique_ptr<Action> replacement)
  167. -> ErrorOr<Success> {
  168. std::unique_ptr<Action> old = todo_.Pop();
  169. CARBON_CHECK(FinishActionKindFor(old->kind()) ==
  170. FinishActionKindFor(replacement->kind()))
  171. << "Can't replace action " << *old << " with " << *replacement;
  172. todo_.Push(std::move(replacement));
  173. return Success();
  174. }
  175. auto ActionStack::RunAgain() -> ErrorOr<Success> {
  176. Action& action = *todo_.Top();
  177. action.set_pos(action.pos() + 1);
  178. return Success();
  179. }
  180. auto ActionStack::UnwindToWithCaptureScopesToDestroy(
  181. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  182. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  183. while (true) {
  184. if (const auto* statement_action =
  185. llvm::dyn_cast<StatementAction>(todo_.Top().get());
  186. statement_action != nullptr &&
  187. &statement_action->statement() == ast_node) {
  188. break;
  189. }
  190. auto item = todo_.Pop();
  191. auto& scope = item->scope();
  192. if (scope && item->kind() != Action::Kind::CleanUpAction) {
  193. std::unique_ptr<Action> cleanup_action =
  194. std::make_unique<CleanUpAction>(std::move(*scope));
  195. scopes_to_destroy.push(std::move(cleanup_action));
  196. }
  197. }
  198. return scopes_to_destroy;
  199. }
  200. auto ActionStack::UnwindTo(Nonnull<const Statement*> ast_node)
  201. -> ErrorOr<Success> {
  202. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  203. UnwindToWithCaptureScopesToDestroy(ast_node);
  204. PushCleanUpActions(std::move(scopes_to_destroy));
  205. return Success();
  206. }
  207. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node)
  208. -> ErrorOr<Success> {
  209. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  210. UnwindPastWithCaptureScopesToDestroy(ast_node);
  211. PushCleanUpActions(std::move(scopes_to_destroy));
  212. return Success();
  213. }
  214. auto ActionStack::UnwindPastWithCaptureScopesToDestroy(
  215. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  216. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  217. UnwindToWithCaptureScopesToDestroy(ast_node);
  218. auto item = todo_.Pop();
  219. scopes_to_destroy.push(std::move(item));
  220. PopScopes(scopes_to_destroy);
  221. return scopes_to_destroy;
  222. }
  223. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node,
  224. Nonnull<const Value*> result) -> ErrorOr<Success> {
  225. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  226. UnwindPastWithCaptureScopesToDestroy(ast_node);
  227. SetResult(result);
  228. PushCleanUpActions(std::move(scopes_to_destroy));
  229. return Success();
  230. }
  231. void ActionStack::PopScopes(
  232. std::stack<std::unique_ptr<Action>>& cleanup_stack) {
  233. while (!todo_.IsEmpty() && llvm::isa<ScopeAction>(*todo_.Top())) {
  234. auto act = todo_.Pop();
  235. if (act->scope()) {
  236. cleanup_stack.push(std::move(act));
  237. }
  238. }
  239. }
  240. void ActionStack::SetResult(Nonnull<const Value*> result) {
  241. if (todo_.IsEmpty()) {
  242. result_ = result;
  243. } else {
  244. todo_.Top()->AddResult(result);
  245. }
  246. }
  247. void ActionStack::PushCleanUpActions(
  248. std::stack<std::unique_ptr<Action>> actions) {
  249. while (!actions.empty()) {
  250. auto& act = actions.top();
  251. if (act->scope()) {
  252. std::unique_ptr<Action> cleanup_action =
  253. std::make_unique<CleanUpAction>(std::move(*act->scope()));
  254. todo_.Push(std::move(cleanup_action));
  255. }
  256. actions.pop();
  257. }
  258. }
  259. void ActionStack::PushCleanUpAction(std::unique_ptr<Action> act) {
  260. auto& scope = act->scope();
  261. if (scope && act->kind() != Action::Kind::CleanUpAction) {
  262. std::unique_ptr<Action> cleanup_action =
  263. std::make_unique<CleanUpAction>(std::move(*scope));
  264. todo_.Push(std::move(cleanup_action));
  265. }
  266. }
  267. } // namespace Carbon