action_stack.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 "executable_semantics/interpreter/action_stack.h"
  5. #include "executable_semantics/interpreter/action.h"
  6. #include "llvm/ADT/StringExtras.h"
  7. #include "llvm/Support/Casting.h"
  8. #include "llvm/Support/Error.h"
  9. namespace Carbon {
  10. void ActionStack::Print(llvm::raw_ostream& out) const {
  11. llvm::ListSeparator sep(" :: ");
  12. for (const std::unique_ptr<Action>& action : todo_) {
  13. out << sep << *action;
  14. }
  15. }
  16. void ActionStack::PrintScopes(llvm::raw_ostream& out) const {
  17. llvm::ListSeparator sep(" :: ");
  18. for (const std::unique_ptr<Action>& action : todo_) {
  19. if (action->scope().has_value()) {
  20. out << sep << *action->scope();
  21. }
  22. }
  23. if (globals_.has_value()) {
  24. out << sep << *globals_;
  25. }
  26. // TODO: should we print constants as well?
  27. }
  28. void ActionStack::Start(std::unique_ptr<Action> action) {
  29. result_ = std::nullopt;
  30. CHECK(todo_.IsEmpty());
  31. todo_.Push(std::move(action));
  32. }
  33. void ActionStack::Initialize(ValueNodeView value_node,
  34. Nonnull<const Value*> value) {
  35. for (const std::unique_ptr<Action>& action : todo_) {
  36. if (action->scope().has_value()) {
  37. action->scope()->Initialize(value_node, value);
  38. return;
  39. }
  40. }
  41. globals_->Initialize(value_node, value);
  42. }
  43. auto ActionStack::ValueOfNode(ValueNodeView value_node,
  44. SourceLocation source_loc) const
  45. -> ErrorOr<Nonnull<const Value*>> {
  46. std::optional<const Value*> value = (phase_ == Phase::CompileTime)
  47. ? value_node.symbolic_identity()
  48. : value_node.constant_value();
  49. if (value.has_value()) {
  50. return *value;
  51. }
  52. for (const std::unique_ptr<Action>& action : todo_) {
  53. // TODO: have static name resolution identify the scope of value_node
  54. // as an AstNode, and then perform lookup _only_ on the Action associated
  55. // with that node. This will help keep unwanted dynamic-scoping behavior
  56. // from sneaking in.
  57. if (action->scope().has_value()) {
  58. std::optional<Nonnull<const Value*>> result =
  59. action->scope()->Get(value_node);
  60. if (result.has_value()) {
  61. return *result;
  62. }
  63. }
  64. }
  65. if (globals_.has_value()) {
  66. std::optional<Nonnull<const Value*>> result = globals_->Get(value_node);
  67. if (result.has_value()) {
  68. return *result;
  69. }
  70. }
  71. // TODO: Move these errors to compile time and explain them more clearly.
  72. return RuntimeError(source_loc)
  73. << "could not find `" << value_node.base() << "`";
  74. }
  75. void ActionStack::MergeScope(RuntimeScope scope) {
  76. for (const std::unique_ptr<Action>& action : todo_) {
  77. if (action->scope().has_value()) {
  78. action->scope()->Merge(std::move(scope));
  79. return;
  80. }
  81. }
  82. if (globals_.has_value()) {
  83. globals_->Merge(std::move(scope));
  84. return;
  85. }
  86. FATAL() << "No current scope";
  87. }
  88. void ActionStack::InitializeFragment(ContinuationValue::StackFragment& fragment,
  89. Nonnull<const Statement*> body) {
  90. std::vector<Nonnull<const RuntimeScope*>> scopes;
  91. for (const std::unique_ptr<Action>& action : todo_) {
  92. if (action->scope().has_value()) {
  93. scopes.push_back(&*action->scope());
  94. }
  95. }
  96. // We don't capture globals_ or constants_ because they're global.
  97. std::vector<std::unique_ptr<Action>> reversed_todo;
  98. reversed_todo.push_back(std::make_unique<StatementAction>(body));
  99. reversed_todo.push_back(
  100. std::make_unique<ScopeAction>(RuntimeScope::Capture(scopes)));
  101. fragment.StoreReversed(std::move(reversed_todo));
  102. }
  103. auto ActionStack::FinishAction() -> ErrorOr<Success> {
  104. std::unique_ptr<Action> act = todo_.Pop();
  105. switch (act->kind()) {
  106. case Action::Kind::ExpressionAction:
  107. case Action::Kind::LValAction:
  108. case Action::Kind::PatternAction:
  109. FATAL() << "This kind of action must produce a result: " << *act;
  110. case Action::Kind::ScopeAction:
  111. FATAL() << "ScopeAction at top of stack";
  112. case Action::Kind::StatementAction:
  113. case Action::Kind::DeclarationAction:
  114. PopScopes();
  115. }
  116. return Success();
  117. }
  118. auto ActionStack::FinishAction(Nonnull<const Value*> result)
  119. -> ErrorOr<Success> {
  120. std::unique_ptr<Action> act = todo_.Pop();
  121. switch (act->kind()) {
  122. case Action::Kind::StatementAction:
  123. case Action::Kind::DeclarationAction:
  124. FATAL() << "This kind of Action cannot produce results: " << *act;
  125. case Action::Kind::ScopeAction:
  126. FATAL() << "ScopeAction at top of stack";
  127. case Action::Kind::ExpressionAction:
  128. case Action::Kind::LValAction:
  129. case Action::Kind::PatternAction:
  130. PopScopes();
  131. SetResult(result);
  132. }
  133. return Success();
  134. }
  135. auto ActionStack::Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success> {
  136. Action& action = *todo_.Top();
  137. action.set_pos(action.pos() + 1);
  138. todo_.Push(std::move(child));
  139. return Success();
  140. }
  141. auto ActionStack::Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
  142. -> ErrorOr<Success> {
  143. Action& action = *todo_.Top();
  144. action.set_pos(action.pos() + 1);
  145. todo_.Push(std::make_unique<ScopeAction>(std::move(scope)));
  146. todo_.Push(std::move(child));
  147. return Success();
  148. }
  149. auto ActionStack::RunAgain() -> ErrorOr<Success> {
  150. Action& action = *todo_.Top();
  151. action.set_pos(action.pos() + 1);
  152. return Success();
  153. }
  154. auto ActionStack::UnwindTo(Nonnull<const Statement*> ast_node)
  155. -> ErrorOr<Success> {
  156. while (true) {
  157. if (const auto* statement_action =
  158. llvm::dyn_cast<StatementAction>(todo_.Top().get());
  159. statement_action != nullptr &&
  160. &statement_action->statement() == ast_node) {
  161. break;
  162. }
  163. todo_.Pop();
  164. }
  165. return Success();
  166. }
  167. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node)
  168. -> ErrorOr<Success> {
  169. RETURN_IF_ERROR(UnwindTo(ast_node));
  170. todo_.Pop();
  171. PopScopes();
  172. return Success();
  173. }
  174. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node,
  175. Nonnull<const Value*> result) -> ErrorOr<Success> {
  176. RETURN_IF_ERROR(UnwindPast(ast_node));
  177. SetResult(result);
  178. return Success();
  179. }
  180. auto ActionStack::Resume(Nonnull<const ContinuationValue*> continuation)
  181. -> ErrorOr<Success> {
  182. Action& action = *todo_.Top();
  183. action.set_pos(action.pos() + 1);
  184. continuation->stack().RestoreTo(todo_);
  185. return Success();
  186. }
  187. static auto IsRunAction(const Action& action) -> bool {
  188. const auto* statement = llvm::dyn_cast<StatementAction>(&action);
  189. return statement != nullptr && llvm::isa<Run>(statement->statement());
  190. }
  191. auto ActionStack::Suspend() -> ErrorOr<Success> {
  192. // Pause the current continuation
  193. todo_.Pop();
  194. std::vector<std::unique_ptr<Action>> paused;
  195. while (!IsRunAction(*todo_.Top())) {
  196. paused.push_back(todo_.Pop());
  197. }
  198. const auto& continuation =
  199. llvm::cast<const ContinuationValue>(*todo_.Top()->results()[0]);
  200. // Update the continuation with the paused stack.
  201. continuation.stack().StoreReversed(std::move(paused));
  202. return Success();
  203. }
  204. void ActionStack::PopScopes() {
  205. while (!todo_.IsEmpty() && llvm::isa<ScopeAction>(*todo_.Top())) {
  206. todo_.Pop();
  207. }
  208. }
  209. void ActionStack::SetResult(Nonnull<const Value*> result) {
  210. if (todo_.IsEmpty()) {
  211. result_ = result;
  212. } else {
  213. todo_.Top()->AddResult(result);
  214. }
  215. }
  216. } // namespace Carbon