action_stack.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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_.empty());
  20. 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. CARBON_ASSIGN_OR_RETURN(auto result,
  46. action->scope()->Get(value_node, source_loc));
  47. if (result.has_value()) {
  48. return *result;
  49. }
  50. }
  51. }
  52. if (globals_.has_value()) {
  53. CARBON_ASSIGN_OR_RETURN(auto result, globals_->Get(value_node, source_loc));
  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::ValueExpressionAction:
  104. case Action::Kind::ExpressionAction:
  105. case Action::Kind::WitnessAction:
  106. case Action::Kind::LocationAction:
  107. case Action::Kind::TypeInstantiationAction:
  108. return FinishActionKind::Value;
  109. case Action::Kind::StatementAction:
  110. case Action::Kind::DeclarationAction:
  111. case Action::Kind::RecursiveAction:
  112. return FinishActionKind::NoValue;
  113. case Action::Kind::ScopeAction:
  114. case Action::Kind::CleanUpAction:
  115. case Action::Kind::DestroyAction:
  116. return FinishActionKind::NeverCalled;
  117. }
  118. }
  119. auto ActionStack::FinishAction() -> ErrorOr<Success> {
  120. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  121. std::unique_ptr<Action> act = Pop();
  122. switch (FinishActionKindFor(act->kind())) {
  123. case FinishActionKind::Value:
  124. CARBON_FATAL("This kind of action must produce a result: {0}", *act);
  125. case FinishActionKind::NeverCalled:
  126. CARBON_FATAL("Should not call FinishAction for: {0}", *act);
  127. case FinishActionKind::NoValue:
  128. PopScopes(scopes_to_destroy);
  129. break;
  130. }
  131. PushCleanUpAction(std::move(act));
  132. PushCleanUpActions(std::move(scopes_to_destroy));
  133. return Success();
  134. }
  135. auto ActionStack::FinishAction(Nonnull<const Value*> result)
  136. -> ErrorOr<Success> {
  137. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  138. std::unique_ptr<Action> act = Pop();
  139. switch (FinishActionKindFor(act->kind())) {
  140. case FinishActionKind::NoValue:
  141. CARBON_FATAL("This kind of action cannot produce results: {0}", *act);
  142. case FinishActionKind::NeverCalled:
  143. CARBON_FATAL("Should not call FinishAction for: {0}", *act);
  144. case FinishActionKind::Value:
  145. PopScopes(scopes_to_destroy);
  146. SetResult(result);
  147. break;
  148. }
  149. PushCleanUpAction(std::move(act));
  150. PushCleanUpActions(std::move(scopes_to_destroy));
  151. return Success();
  152. }
  153. auto ActionStack::Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success> {
  154. Action& action = *todo_.Top();
  155. action.set_pos(action.pos() + 1);
  156. Push(std::move(child));
  157. return Success();
  158. }
  159. auto ActionStack::Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
  160. -> ErrorOr<Success> {
  161. Action& action = *todo_.Top();
  162. action.set_pos(action.pos() + 1);
  163. Push(std::make_unique<ScopeAction>(std::move(scope)));
  164. Push(std::move(child));
  165. return Success();
  166. }
  167. auto ActionStack::ReplaceWith(std::unique_ptr<Action> replacement)
  168. -> ErrorOr<Success> {
  169. std::unique_ptr<Action> old = Pop();
  170. CARBON_CHECK(FinishActionKindFor(old->kind()) ==
  171. FinishActionKindFor(replacement->kind()),
  172. "Can't replace action {0} with {1}", *old, *replacement);
  173. Push(std::move(replacement));
  174. return Success();
  175. }
  176. auto ActionStack::RunAgain() -> ErrorOr<Success> {
  177. Action& action = *todo_.Top();
  178. action.set_pos(action.pos() + 1);
  179. return Success();
  180. }
  181. auto ActionStack::UnwindToWithCaptureScopesToDestroy(
  182. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  183. std::stack<std::unique_ptr<Action>> scopes_to_destroy;
  184. while (true) {
  185. if (const auto* statement_action =
  186. llvm::dyn_cast<StatementAction>(todo_.Top().get());
  187. statement_action != nullptr &&
  188. &statement_action->statement() == ast_node) {
  189. break;
  190. }
  191. auto item = Pop();
  192. auto& scope = item->scope();
  193. if (scope && item->kind() != Action::Kind::CleanUpAction) {
  194. std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
  195. std::move(*scope), ast_node->source_loc());
  196. scopes_to_destroy.push(std::move(cleanup_action));
  197. }
  198. }
  199. return scopes_to_destroy;
  200. }
  201. auto ActionStack::UnwindTo(Nonnull<const Statement*> ast_node)
  202. -> ErrorOr<Success> {
  203. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  204. UnwindToWithCaptureScopesToDestroy(ast_node);
  205. PushCleanUpActions(std::move(scopes_to_destroy));
  206. return Success();
  207. }
  208. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node)
  209. -> ErrorOr<Success> {
  210. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  211. UnwindPastWithCaptureScopesToDestroy(ast_node);
  212. PushCleanUpActions(std::move(scopes_to_destroy));
  213. return Success();
  214. }
  215. auto ActionStack::UnwindPastWithCaptureScopesToDestroy(
  216. Nonnull<const Statement*> ast_node) -> std::stack<std::unique_ptr<Action>> {
  217. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  218. UnwindToWithCaptureScopesToDestroy(ast_node);
  219. auto item = Pop();
  220. scopes_to_destroy.push(std::move(item));
  221. PopScopes(scopes_to_destroy);
  222. return scopes_to_destroy;
  223. }
  224. auto ActionStack::UnwindPast(Nonnull<const Statement*> ast_node,
  225. Nonnull<const Value*> result) -> ErrorOr<Success> {
  226. std::stack<std::unique_ptr<Action>> scopes_to_destroy =
  227. UnwindPastWithCaptureScopesToDestroy(ast_node);
  228. SetResult(result);
  229. PushCleanUpActions(std::move(scopes_to_destroy));
  230. return Success();
  231. }
  232. void ActionStack::PopScopes(
  233. std::stack<std::unique_ptr<Action>>& cleanup_stack) {
  234. while (!todo_.empty() && llvm::isa<ScopeAction>(*todo_.Top())) {
  235. auto act = Pop();
  236. if (act->scope()) {
  237. cleanup_stack.push(std::move(act));
  238. }
  239. }
  240. }
  241. void ActionStack::SetResult(Nonnull<const Value*> result) {
  242. if (todo_.empty()) {
  243. result_ = result;
  244. } else {
  245. todo_.Top()->AddResult(result);
  246. }
  247. }
  248. void ActionStack::PushCleanUpActions(
  249. std::stack<std::unique_ptr<Action>> actions) {
  250. while (!actions.empty()) {
  251. auto& act = actions.top();
  252. if (act->scope()) {
  253. // TODO: Provide a real source location.
  254. std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
  255. std::move(*act->scope()),
  256. SourceLocation("stack cleanup", 1, FileKind::Unknown));
  257. Push(std::move(cleanup_action));
  258. }
  259. actions.pop();
  260. }
  261. }
  262. void ActionStack::PushCleanUpAction(std::unique_ptr<Action> act) {
  263. auto& scope = act->scope();
  264. if (scope && act->kind() != Action::Kind::CleanUpAction) {
  265. // TODO: Provide a real source location.
  266. std::unique_ptr<Action> cleanup_action = std::make_unique<CleanUpAction>(
  267. std::move(*scope),
  268. SourceLocation("stack cleanup", 1, FileKind::Unknown));
  269. Push(std::move(cleanup_action));
  270. }
  271. }
  272. } // namespace Carbon