forked from carbon-language/carbon-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaction_stack.h
More file actions
139 lines (108 loc) · 5.62 KB
/
Copy pathaction_stack.h
File metadata and controls
139 lines (108 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_EXPLORER_INTERPRETER_ACTION_STACK_H_
#define CARBON_EXPLORER_INTERPRETER_ACTION_STACK_H_
#include <memory>
#include <optional>
#include "common/ostream.h"
#include "explorer/ast/statement.h"
#include "explorer/interpreter/action.h"
#include "explorer/interpreter/value.h"
namespace Carbon {
// Selects between compile-time and run-time behavior.
enum class Phase { CompileTime, RunTime };
// The stack of Actions currently being executed by the interpreter.
class ActionStack {
public:
// Constructs an empty compile-time ActionStack.
ActionStack() : phase_(Phase::CompileTime) {}
// Constructs an empty run-time ActionStack that allocates global variables
// on `heap`.
explicit ActionStack(Nonnull<HeapAllocationInterface*> heap)
: globals_(RuntimeScope(heap)), phase_(Phase::RunTime) {}
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// TODO: consider unifying with Print.
void PrintScopes(llvm::raw_ostream& out) const;
// Starts execution with `action` at the top of the stack. Cannot be called
// when IsEmpty() is false.
void Start(std::unique_ptr<Action> action);
// True if the stack is empty.
auto IsEmpty() const -> bool { return todo_.IsEmpty(); }
// The Action currently at the top of the stack. This will never be a
// ScopeAction.
auto CurrentAction() -> Action& { return *todo_.Top(); }
// Allocates storage for `value_node`, and initializes it to `value`.
void Initialize(ValueNodeView value_node, Nonnull<const Value*> value);
// Returns the value bound to `value_node`. If `value_node` is a local
// variable, this will be an LValue.
auto ValueOfNode(ValueNodeView value_node, SourceLocation source_loc) const
-> ErrorOr<Nonnull<const Value*>>;
// Merges `scope` into the innermost scope currently on the stack.
void MergeScope(RuntimeScope scope);
// Initializes `fragment` so that, when resumed, it begins execution of
// `body`.
void InitializeFragment(ContinuationValue::StackFragment& fragment,
Nonnull<const Statement*> body);
// The result produced by the `action` argument of the most recent
// Start call. Cannot be called if IsEmpty() is false, or if `action`
// was an action that doesn't produce results.
auto result() const -> Nonnull<const Value*> { return *result_; }
// The following methods, called "transition methods", update the state of
// the ActionStack and/or the current Action to reflect the effects of
// executing a step of that Action. Execution of an Action step should always
// invoke exactly one transition method, as the very last operation. This is a
// matter of safety as well as convention: most transition methods modify the
// state of the current action, and some of them destroy it. To help enforce
// this requirement, we have a convention of making these methods return an
// ErrorOr<Success> even when a method can't actually fail, and calling the
// methods as part of return statements, e.g. `return todo_.FinishAction()`.
// Finishes execution of the current Action. If `result` is specified, it
// represents the result of that Action.
auto FinishAction() -> ErrorOr<Success>;
auto FinishAction(Nonnull<const Value*> result) -> ErrorOr<Success>;
// Advances the current action one step, and push `child` onto the stack.
// If `scope` is specified, `child` will be executed in that scope.
auto Spawn(std::unique_ptr<Action> child) -> ErrorOr<Success>;
auto Spawn(std::unique_ptr<Action> child, RuntimeScope scope)
-> ErrorOr<Success>;
// Replace the current action with another action of the same kind and run it
// next.
auto ReplaceWith(std::unique_ptr<Action> child) -> ErrorOr<Success>;
// Start a new recursive action.
auto BeginRecursiveAction() {
todo_.Push(std::make_unique<RecursiveAction>());
}
// Advances the current action one step.
auto RunAgain() -> ErrorOr<Success>;
// Unwinds Actions from the stack until the StatementAction associated with
// `ast_node` is at the top of the stack.
auto UnwindTo(Nonnull<const Statement*> ast_node) -> ErrorOr<Success>;
// Unwinds Actions from the stack until the StatementAction associated with
// `ast_node` has been removed from the stack. If `result` is specified,
// it represents the result of that Action (StatementActions normally cannot
// produce results, but the body of a function can).
auto UnwindPast(Nonnull<const Statement*> ast_node) -> ErrorOr<Success>;
auto UnwindPast(Nonnull<const Statement*> ast_node,
Nonnull<const Value*> result) -> ErrorOr<Success>;
// Resumes execution of a suspended continuation.
auto Resume(Nonnull<const ContinuationValue*> continuation)
-> ErrorOr<Success>;
// Suspends execution of the currently-executing continuation.
auto Suspend() -> ErrorOr<Success>;
private:
// Pop any ScopeActions from the top of the stack, propagating results as
// needed, to restore the invariant that todo_.Top() is not a ScopeAction.
void PopScopes();
// Set `result` as the result of the Action most recently removed from the
// stack.
void SetResult(Nonnull<const Value*> result);
// TODO: consider defining a non-nullable unique_ptr-like type to use here.
Stack<std::unique_ptr<Action>> todo_;
std::optional<Nonnull<const Value*>> result_;
std::optional<RuntimeScope> globals_;
Phase phase_;
};
} // namespace Carbon
#endif // CARBON_EXPLORER_INTERPRETER_ACTION_STACK_H_