forked from carbon-language/carbon-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
action.h
276 lines (224 loc) · 9.18 KB
/
action.h
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// 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_H_
#define CARBON_EXPLORER_INTERPRETER_ACTION_H_
#include <map>
#include <vector>
#include "common/ostream.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/pattern.h"
#include "explorer/ast/statement.h"
#include "explorer/interpreter/dictionary.h"
#include "explorer/interpreter/heap_allocation_interface.h"
#include "explorer/interpreter/stack.h"
#include "explorer/interpreter/value.h"
#include "llvm/Support/Compiler.h"
namespace Carbon {
// A RuntimeScope manages and provides access to the storage for names that are
// not compile-time constants.
class RuntimeScope {
public:
// Returns a RuntimeScope whose Get() operation for a given name returns the
// storage owned by the first entry in `scopes` that defines that name. This
// behavior is closely analogous to a `[&]` capture in C++, hence the name.
// `scopes` must contain at least one entry, and all entries must be backed
// by the same Heap.
static auto Capture(const std::vector<Nonnull<const RuntimeScope*>>& scopes)
-> RuntimeScope;
// Constructs a RuntimeScope that allocates storage in `heap`.
explicit RuntimeScope(Nonnull<HeapAllocationInterface*> heap) : heap_(heap) {}
// Moving a RuntimeScope transfers ownership of its allocations.
RuntimeScope(RuntimeScope&&) noexcept;
auto operator=(RuntimeScope&&) noexcept -> RuntimeScope&;
// Deallocates any allocations in this scope from `heap`.
~RuntimeScope();
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// Allocates storage for `value_node` in `heap`, and initializes it with
// `value`.
void Initialize(ValueNodeView value_node, Nonnull<const Value*> value);
// Transfers the names and allocations from `other` into *this. The two
// scopes must not define the same name, and must be backed by the same Heap.
void Merge(RuntimeScope other);
// Returns the local storage for value_node, if it has storage local to
// this scope.
auto Get(ValueNodeView value_node) const
-> std::optional<Nonnull<const LValue*>>;
private:
std::map<ValueNodeView, Nonnull<const LValue*>> locals_;
std::vector<AllocationId> allocations_;
Nonnull<HeapAllocationInterface*> heap_;
};
// An Action represents the current state of a self-contained computation,
// usually associated with some AST node, such as evaluation of an expression or
// execution of a statement. Execution of an action is divided into a series of
// steps, and the `pos` field typically counts the number of steps executed.
//
// They should be destroyed as soon as they are done executing, in order to
// clean up the associated Carbon scope, and consequently they should not be
// allocated on an Arena. Actions are typically owned by the ActionStack.
//
// The actual behavior of an Action step is defined by Interpreter::Step, not by
// Action or its subclasses.
// TODO: consider moving this logic to a virtual method `Step`.
class Action {
public:
enum class Kind {
LValAction,
ExpressionAction,
PatternAction,
StatementAction,
DeclarationAction,
ScopeAction,
RecursiveAction,
};
Action(const Value&) = delete;
auto operator=(const Value&) -> Action& = delete;
virtual ~Action() = default;
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// Resets this Action to its initial state.
void Clear() {
CARBON_CHECK(!scope_.has_value());
pos_ = 0;
results_.clear();
}
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> Kind { return kind_; }
// The position or state of the action. Starts at 0 and is typically
// incremented after each step.
auto pos() const -> int { return pos_; }
void set_pos(int pos) { this->pos_ = pos; }
// The results of any Actions spawned by this Action.
auto results() const -> const std::vector<Nonnull<const Value*>>& {
return results_;
}
void ReplaceResult(std::size_t index, Nonnull<const Value*> value) {
CARBON_CHECK(index < results_.size());
results_[index] = value;
}
// Appends `result` to `results`.
void AddResult(Nonnull<const Value*> result) { results_.push_back(result); }
// Returns the scope associated with this Action, if any.
auto scope() -> std::optional<RuntimeScope>& { return scope_; }
auto scope() const -> const std::optional<RuntimeScope>& { return scope_; }
// Associates this action with a new scope, with initial state `scope`.
// Values that are local to this scope will be deallocated when this
// Action is completed or unwound. Can only be called once on a given
// Action.
void StartScope(RuntimeScope scope) {
CARBON_CHECK(!scope_.has_value());
scope_ = std::move(scope);
}
protected:
// Constructs an Action. `kind` must be the enumerator corresponding to the
// most-derived type being constructed.
explicit Action(Kind kind) : kind_(kind) {}
private:
int pos_ = 0;
std::vector<Nonnull<const Value*>> results_;
std::optional<RuntimeScope> scope_;
const Kind kind_;
};
// An Action which implements evaluation of an Expression to produce an
// LValue.
class LValAction : public Action {
public:
explicit LValAction(Nonnull<const Expression*> expression)
: Action(Kind::LValAction), expression_(expression) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::LValAction;
}
// The Expression this Action evaluates.
auto expression() const -> const Expression& { return *expression_; }
private:
Nonnull<const Expression*> expression_;
};
// An Action which implements evaluation of an Expression to produce an
// rvalue. The result is expressed as a Value.
class ExpressionAction : public Action {
public:
explicit ExpressionAction(Nonnull<const Expression*> expression)
: Action(Kind::ExpressionAction), expression_(expression) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::ExpressionAction;
}
// The Expression this Action evaluates.
auto expression() const -> const Expression& { return *expression_; }
private:
Nonnull<const Expression*> expression_;
};
// An Action which implements evaluation of a Pattern. The result is expressed
// as a Value.
class PatternAction : public Action {
public:
explicit PatternAction(Nonnull<const Pattern*> pattern)
: Action(Kind::PatternAction), pattern_(pattern) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::PatternAction;
}
// The Pattern this Action evaluates.
auto pattern() const -> const Pattern& { return *pattern_; }
private:
Nonnull<const Pattern*> pattern_;
};
// An Action which implements execution of a Statement. Does not produce a
// result.
class StatementAction : public Action {
public:
explicit StatementAction(Nonnull<const Statement*> statement)
: Action(Kind::StatementAction), statement_(statement) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::StatementAction;
}
// The Statement this Action executes.
auto statement() const -> const Statement& { return *statement_; }
private:
Nonnull<const Statement*> statement_;
};
// Action which implements the run-time effects of executing a Declaration.
// Does not produce a result.
class DeclarationAction : public Action {
public:
explicit DeclarationAction(Nonnull<const Declaration*> declaration)
: Action(Kind::DeclarationAction), declaration_(declaration) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::DeclarationAction;
}
// The Declaration this Action executes.
auto declaration() const -> const Declaration& { return *declaration_; }
private:
Nonnull<const Declaration*> declaration_;
};
// Action which does nothing except introduce a new scope into the action
// stack. This is useful when a distinct scope doesn't otherwise have an
// Action it can naturally be associated with. ScopeActions are not associated
// with AST nodes.
class ScopeAction : public Action {
public:
explicit ScopeAction(RuntimeScope scope) : Action(Kind::ScopeAction) {
StartScope(std::move(scope));
}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::ScopeAction;
}
};
// Action which contains another action and does nothing further once that
// action completes. This action therefore acts as a marker on the action stack
// that indicates that the interpreter should stop when the inner action has
// finished, and holds the result of that inner action. This is useful to allow
// a sequence of steps for an action to be run immediately rather than as part
// of the normal step queue.
//
// Should be avoided where possible.
class RecursiveAction : public Action {
public:
explicit RecursiveAction() : Action(Kind::RecursiveAction) {}
static auto classof(const Action* action) -> bool {
return action->kind() == Kind::RecursiveAction;
}
};
} // namespace Carbon
#endif // CARBON_EXPLORER_INTERPRETER_ACTION_H_