action_stack.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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. void ActionStack::InitializeFragment(ContinuationValue::StackFragment& fragment,
  90. Nonnull<const Statement*> body) {
  91. std::vector<Nonnull<const RuntimeScope*>> scopes;
  92. for (const std::unique_ptr<Action>& action : todo_) {
  93. if (action->scope().has_value()) {
  94. scopes.push_back(&*action->scope());
  95. }
  96. }
  97. // We don't capture globals_ or constants_ because they're global.
  98. std::vector<std::unique_ptr<Action>> reversed_todo;
  99. reversed_todo.push_back(std::make_unique<StatementAction>(body));
  100. reversed_todo.push_back(
  101. std::make_unique<ScopeAction>(RuntimeScope::Capture(scopes)));
  102. fragment.StoreReversed(std::move(reversed_todo));
  103. }
  104. namespace {
  105. // The way in which FinishAction should be called for a particular kind of
  106. // action.
  107. enum class FinishActionKind {
  108. // FinishAction should not be passed a value.
  109. NoValue,
  110. // FinishAction should be passed a value.
  111. Value,
  112. // FinishAction should not be called. The Action needs custom handling.
  113. NeverCalled,
  114. };
  115. } // namespace
  116. static auto FinishActionKindFor(Action::Kind kind) -> FinishActionKind {
  117. switch (kind) {
  118. case Action::Kind::ExpressionAction:
  119. case Action::Kind::WitnessAction:
  120. case Action::Kind::LValAction:
  121. return FinishActionKind::Value;
  122. case Action::Kind::StatementAction:
  123. case Action::Kind::DeclarationAction:
  124. case Action::Kind::RecursiveAction:
  125. return FinishActionKind::NoValue;
  126. case Action::Kind::ScopeAction:
  127. case Action::Kind::CleanUpAction:
  128. case Action::Kind::DestroyAction:
  129. return FinishActionKind::NeverCalled;
  130. }
  131. }
  132. auto ActionStack::FinishAction() -> ErrorOr<Success> {
  133. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  134. std::unique_ptr<Action> act = todo_.Pop();
  135. switch (FinishActionKindFor(act->kind())) {
  136. case FinishActionKind::Value:
  137. CARBON_FATAL() << "This kind of action must produce a result: " << *act;
  138. case FinishActionKind::NeverCalled:
  139. CARBON_FATAL() << "Should not call FinishAction for: " << *act;
  140. case FinishActionKind::NoValue:
  141. PopScopes(scopes_to_destroy);
  142. break;
  143. }
  144. PushCleanUpAction(std::move(act));
  145. PushCleanUpActions(std::move(scopes_to_destroy));
  146. return Success();
  147. }
  148. auto ActionStack::FinishAction(Nonnull<const Value*> result)
  149. -> ErrorOr<Success> {
  150. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  151. std::unique_ptr<Action> act = todo_.Pop();
  152. switch (FinishActionKindFor(act->kind())) {
  153. case FinishActionKind::NoValue:
  154. CARBON_FATAL() << "This kind of action cannot produce results: " << *act;
  155. case FinishActionKind::NeverCalled:
  156. CARBON_FATAL() << "Should not call FinishAction for: " << *act;
  157. case FinishActionKind::Value:
  158. PopScopes(scopes_to_destroy);
  159. SetResult(result);
  160. break;
  161. }
  162. PushCleanUpAction(std::move(act));
  163. PushCleanUpActions(std::move(scopes_to_destroy));
  164. return Success();
  165. }
  166. auto ActionStack::Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success> {
  167. Action& action = *todo_.Top();
  168. action.set_pos(action.pos() + 1);
  169. todo_.Push(std::move(child));
  170. return Success();
  171. }
  172. auto ActionStack::Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
  173. -> ErrorOr<Success> {
  174. Action& action = *todo_.Top();
  175. action.set_pos(action.pos() + 1);
  176. todo_.Push(std::make_unique<ScopeAction>(std::move(scope)));
  177. todo_.Push(std::move(child));
  178. return Success();
  179. }
  180. auto ActionStack::ReplaceWith(std::unique_ptr<Action> replacement)
  181. -> ErrorOr<Success> {
  182. std::unique_ptr<Action> old = todo_.Pop();
  183. CARBON_CHECK(FinishActionKindFor(old->kind()) ==
  184. FinishActionKindFor(replacement->kind()))
  185. << "Can't replace action " << *old << " with " << *replacement;
  186. todo_.Push(std::move(replacement));
  187. return Success();
  188. }
  189. auto ActionStack::RunAgain() -> ErrorOr<Success> {
  190. Action& action = *todo_.Top();
  191. action.set_pos(action.pos() + 1);
  192. return Success();
  193. }
  194. auto ActionStack::UnwindToWithCaptureScopesToDestroy(
  195. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  196. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  197. while (true) {
  198. if (const auto* statement_action =
  199. llvm::dyn_cast<StatementAction>(todo_.Top().get());
  200. statement_action != nullptr &&
  201. &statement_action->statement() == ast_node) {
  202. break;
  203. }
  204. auto item = todo_.Pop();
  205. auto& scope = item->scope();
  206. if (scope && item->kind() != Action::Kind::CleanUpAction) {
  207. std::unique_ptr<Action> cleanup_action =
  208. std::make_unique<CleanUpAction>(std::move(*scope));
  209. scopes_to_destroy.push(std::move(cleanup_action));
  210. }
  211. }
  212. return scopes_to_destroy;
  213. }
  214. auto ActionStack::UnwindTo(Nonnull<const Statement*> ast_node)
  215. -> ErrorOr<Success> {
  216. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  217. UnwindToWithCaptureScopesToDestroy(ast_node);
  218. PushCleanUpActions(std::move(scopes_to_destroy));
  219. return Success();
  220. }
  221. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node)
  222. -> ErrorOr<Success> {
  223. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  224. UnwindPastWithCaptureScopesToDestroy(ast_node);
  225. PushCleanUpActions(std::move(scopes_to_destroy));
  226. return Success();
  227. }
  228. auto ActionStack::UnwindPastWithCaptureScopesToDestroy(
  229. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  230. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  231. UnwindToWithCaptureScopesToDestroy(ast_node);
  232. auto item = todo_.Pop();
  233. scopes_to_destroy.push(std::move(item));
  234. PopScopes(scopes_to_destroy);
  235. return scopes_to_destroy;
  236. }
  237. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node,
  238. Nonnull<const Value*> result) -> ErrorOr<Success> {
  239. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  240. UnwindPastWithCaptureScopesToDestroy(ast_node);
  241. SetResult(result);
  242. PushCleanUpActions(std::move(scopes_to_destroy));
  243. return Success();
  244. }
  245. auto ActionStack::Resume(Nonnull<const ContinuationValue*> continuation)
  246. -> ErrorOr<Success> {
  247. Action& action = *todo_.Top();
  248. action.set_pos(action.pos() + 1);
  249. continuation->stack().RestoreTo(todo_);
  250. return Success();
  251. }
  252. static auto IsRunAction(const Action& action) -> bool {
  253. const auto* statement = llvm::dyn_cast<StatementAction>(&action);
  254. return statement != nullptr && llvm::isa<Run>(statement->statement());
  255. }
  256. auto ActionStack::Suspend() -> ErrorOr<Success> {
  257. // Pause the current continuation
  258. todo_.Pop();
  259. std::vector<std::unique_ptr<Action>> paused;
  260. while (!IsRunAction(*todo_.Top())) {
  261. paused.push_back(todo_.Pop());
  262. }
  263. const auto& continuation =
  264. llvm::cast<const ContinuationValue>(*todo_.Top()->results()[0]);
  265. // Update the continuation with the paused stack.
  266. continuation.stack().StoreReversed(std::move(paused));
  267. return Success();
  268. }
  269. void ActionStack::PopScopes(
  270. std::stack<std::unique_ptr<Action>>& cleanup_stack) {
  271. while (!todo_.IsEmpty() && llvm::isa<ScopeAction>(*todo_.Top())) {
  272. auto act = todo_.Pop();
  273. if (act->scope()) {
  274. cleanup_stack.push(std::move(act));
  275. }
  276. }
  277. }
  278. void ActionStack::SetResult(Nonnull<const Value*> result) {
  279. if (todo_.IsEmpty()) {
  280. result_ = result;
  281. } else {
  282. todo_.Top()->AddResult(result);
  283. }
  284. }
  285. void ActionStack::PushCleanUpActions(
  286. std::stack<std::unique_ptr<Action>> actions) {
  287. while (!actions.empty()) {
  288. auto& act = actions.top();
  289. if (act->scope()) {
  290. std::unique_ptr<Action> cleanup_action =
  291. std::make_unique<CleanUpAction>(std::move(*act->scope()));
  292. todo_.Push(std::move(cleanup_action));
  293. }
  294. actions.pop();
  295. }
  296. }
  297. void ActionStack::PushCleanUpAction(std::unique_ptr<Action> act) {
  298. auto& scope = act->scope();
  299. if (scope && act->kind() != Action::Kind::CleanUpAction) {
  300. std::unique_ptr<Action> cleanup_action =
  301. std::make_unique<CleanUpAction>(std::move(*scope));
  302. todo_.Push(std::move(cleanup_action));
  303. }
  304. }
  305. } // namespace Carbon