action_stack.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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 EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_STACK_H_
  5. #define EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_STACK_H_
  6. #include <memory>
  7. #include <optional>
  8. #include "common/ostream.h"
  9. #include "executable_semantics/ast/statement.h"
  10. #include "executable_semantics/interpreter/action.h"
  11. #include "executable_semantics/interpreter/value.h"
  12. namespace Carbon {
  13. // Selects between compile-time and run-time behavior.
  14. enum class Phase { CompileTime, RunTime };
  15. // The stack of Actions currently being executed by the interpreter.
  16. class ActionStack {
  17. public:
  18. // Constructs an empty compile-time ActionStack.
  19. ActionStack() : phase_(Phase::CompileTime) {}
  20. // Constructs an empty run-time ActionStack that allocates global variables
  21. // on `heap`.
  22. explicit ActionStack(Nonnull<HeapAllocationInterface*> heap)
  23. : globals_(RuntimeScope(heap)), phase_(Phase::RunTime) {}
  24. void Print(llvm::raw_ostream& out) const;
  25. LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
  26. // TODO: consider unifying with Print.
  27. void PrintScopes(llvm::raw_ostream& out) const;
  28. // Starts execution with `action` at the top of the stack. Cannot be called
  29. // when IsEmpty() is false.
  30. void Start(std::unique_ptr<Action> action);
  31. // True if the stack is empty.
  32. auto IsEmpty() const -> bool { return todo_.IsEmpty(); }
  33. // The Action currently at the top of the stack. This will never be a
  34. // ScopeAction.
  35. auto CurrentAction() -> Action& { return *todo_.Top(); }
  36. // Allocates storage for `value_node`, and initializes it to `value`.
  37. void Initialize(ValueNodeView value_node, Nonnull<const Value*> value);
  38. // Returns the value bound to `value_node`. If `value_node` is a local
  39. // variable, this will be an LValue.
  40. auto ValueOfNode(ValueNodeView value_node, SourceLocation source_loc) const
  41. -> ErrorOr<Nonnull<const Value*>>;
  42. // Merges `scope` into the innermost scope currently on the stack.
  43. void MergeScope(RuntimeScope scope);
  44. // Initializes `fragment` so that, when resumed, it begins execution of
  45. // `body`.
  46. void InitializeFragment(ContinuationValue::StackFragment& fragment,
  47. Nonnull<const Statement*> body);
  48. // The result produced by the `action` argument of the most recent
  49. // Start call. Cannot be called if IsEmpty() is false, or if `action`
  50. // was an action that doesn't produce results.
  51. auto result() const -> Nonnull<const Value*> { return *result_; }
  52. // The following methods, called "transition methods", update the state of
  53. // the ActionStack and/or the current Action to reflect the effects of
  54. // executing a step of that Action. Execution of an Action step should always
  55. // invoke exactly one transition method, as the very last operation. This is a
  56. // matter of safety as well as convention: most transition methods modify the
  57. // state of the current action, and some of them destroy it. To help enforce
  58. // this requirement, we have a convention of making these methods return an
  59. // ErrorOr<Success> even when a method can't actually fail, and calling the
  60. // methods as part of return statements, e.g. `return todo_.FinishAction()`.
  61. // Finishes execution of the current Action. If `result` is specified, it
  62. // represents the result of that Action.
  63. auto FinishAction() -> ErrorOr<Success>;
  64. auto FinishAction(Nonnull<const Value*> result) -> ErrorOr<Success>;
  65. // Advances the current action one step, and push `child` onto the stack.
  66. // If `scope` is specified, `child` will be executed in that scope.
  67. auto Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success>;
  68. auto Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
  69. -> ErrorOr<Success>;
  70. // Advances the current action one step.
  71. auto RunAgain() -> ErrorOr<Success>;
  72. // Unwinds Actions from the stack until the StatementAction associated with
  73. // `ast_node` is at the top of the stack.
  74. auto UnwindTo(Nonnull<const Statement*> ast_node) -> ErrorOr<Success>;
  75. // Unwinds Actions from the stack until the StatementAction associated with
  76. // `ast_node` has been removed from the stack. If `result` is specified,
  77. // it represents the result of that Action (StatementActions normally cannot
  78. // produce results, but the body of a function can).
  79. auto UnwindPast(Nonnull<const Statement*> ast_node) -> ErrorOr<Success>;
  80. auto UnwindPast(Nonnull<const Statement*> ast_node,
  81. Nonnull<const Value*> result) -> ErrorOr<Success>;
  82. // Resumes execution of a suspended continuation.
  83. auto Resume(Nonnull<const ContinuationValue*> continuation)
  84. -> ErrorOr<Success>;
  85. // Suspends execution of the currently-executing continuation.
  86. auto Suspend() -> ErrorOr<Success>;
  87. private:
  88. // Pop any ScopeActions from the top of the stack, propagating results as
  89. // needed, to restore the invariant that todo_.Top() is not a ScopeAction.
  90. void PopScopes();
  91. // Set `result` as the result of the Action most recently removed from the
  92. // stack.
  93. void SetResult(Nonnull<const Value*> result);
  94. // TODO: consider defining a non-nullable unique_ptr-like type to use here.
  95. Stack<std::unique_ptr<Action>> todo_;
  96. std::optional<Nonnull<const Value*>> result_;
  97. std::optional<RuntimeScope> globals_;
  98. Phase phase_;
  99. };
  100. } // namespace Carbon
  101. #endif // EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_STACK_H_