ScummVM API documentation
coroutines.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef MTROPOLIS_COROUTINES_H
23#define MTROPOLIS_COROUTINES_H
24
25#include "mtropolis/coroutine_protos.h"
26#include "mtropolis/miniscript_protos.h"
27#include "mtropolis/vthread.h"
28
29namespace MTropolis {
30
31struct CoroExecInstr;
32struct CoroutineRuntimeState;
33
34typedef VThreadState (*CoroutineFragmentFunction_t)(CoroutineRuntimeState &coroState);
35
38
39 VThread *_vthread;
41 bool _condition;
42 MiniscriptInstructionOutcome _miniscriptOutcome;
43
44private:
45 CoroutineRuntimeState() = delete;
47 CoroutineRuntimeState &operator=(const CoroutineRuntimeState&) = delete;
48};
49
53
54 CoroutineFrameConstructor_t _frameConstructor;
55 CoroutineGetFrameParametersFunction_t _getFrameParameters;
56 bool _isVoidReturn;
57
58 CoroExecInstr *_instructions;
59 uint _numInstructions;
60
61private:
62 CompiledCoroutine(const CompiledCoroutine &) = delete;
63 CompiledCoroutine &operator =(const CompiledCoroutine &) = delete;
64};
65
67 explicit CoroutineStackFrame2(const CompiledCoroutine *compiledCoro);
68 virtual ~CoroutineStackFrame2();
69
70 VThreadState execute(VThread *thread) override;
71
72 const CompiledCoroutine *getCompiledCoroutine() const;
73
74private:
75 CoroutineStackFrame2() = delete;
77
78 const CompiledCoroutine *_compiledCoro;
79 uint _nextInstr;
80};
81
82enum class CoroOps {
83 Invalid = 0,
84
85 BeginFunction,
86 EndFunction,
87
88 IfCond,
89 IfBody,
90 Else,
91 ElseIfCond,
92 ElseIfBody,
93 EndIf,
94
95 WhileCond,
96 WhileBody,
97 EndWhile,
98
99 ForNext,
100 ForCond,
101 ForBody,
102 EndFor,
103
104 Do,
105 DoWhile,
106 DoWhileCond,
107
108 Return,
109
110 Error,
111
112 YieldToFunction,
113
114 CheckMiniscript,
115
116 Code,
117};
118
120 virtual ~ICoroutineCompiler();
121
122 virtual void defineFunction(CoroutineFrameConstructor_t frameConstructor, CoroutineGetFrameParametersFunction_t frameGetParams) = 0;
123 virtual void addOp(CoroOps op, CoroutineFragmentFunction_t fragmentFunc) = 0;
124};
125
126#define CORO_START_CODE_BLOCK(op) \
127 compiler->addOp(op, [](CoroutineRuntimeState &coroRuntime) -> VThreadState { \
128 Params *params = &static_cast<CoroStackFrame *>(coroRuntime._frame)->_params; \
129 Locals *locals = &static_cast<CoroStackFrame *>(coroRuntime._frame)->_locals; \
130 CoroutineReturnValueRef<ReturnValue_t> coroReturnValueRef = (static_cast<CoroStackFrame *>(coroRuntime._frame)->_rvRef);
131
132#define CORO_AWAIT_PUSHED_TASK \
133 return kVThreadReturn
134
135#define CORO_DISUSE_CODE_BLOCK_VARS \
136 (void)params; \
137 (void)locals; \
138 (void)coroReturnValueRef;
139
140#define CORO_END_CODE_BLOCK \
141 CORO_DISUSE_CODE_BLOCK_VARS \
142 return kVThreadReturn; \
143 });
144
145#define CORO_BEGIN_DEFINITION(type) \
146CompiledCoroutine *type::ms_compiledCoro = nullptr;\
147void type::compileCoroutine(ICoroutineCompiler *compiler) {
148
149#define CORO_END_DEFINITION \
150 }
151
152#define CORO_BEGIN_FUNCTION \
153 struct CoroStackFrame : public CoroutineStackFrame2 {\
154 Params _params;\
155 Locals _locals;\
156 CoroutineReturnValueRef<ReturnValue_t> _rvRef;\
157 explicit CoroStackFrame(const CompiledCoroutine *compiledCoro, const Params &params, const CoroutineReturnValueRef<ReturnValue_t> &rvRef)\
158 : CoroutineStackFrame2(compiledCoro), _params(params), _rvRef(rvRef) {\
159 }\
160 static CoroutineStackFrame2 *constructFrame(void *ptr, const CompiledCoroutine *compiledCoro, const CoroutineParamsBase &params, const CoroutineReturnValueRefBase &returnValueRef) {\
161 return new (ptr) CoroStackFrame(compiledCoro, static_cast<const Params &>(params), static_cast<const CoroutineReturnValueRef<ReturnValue_t>&>(returnValueRef));\
162 }\
163 static void getFrameParameters(size_t &outSize, size_t &outAlignment) { \
164 outSize = sizeof(CoroStackFrame); \
165 outAlignment = alignof(CoroStackFrame); \
166 }\
167 };\
168 compiler->defineFunction(CoroStackFrame::constructFrame, CoroStackFrame::getFrameParameters); \
169 CORO_START_CODE_BLOCK(CoroOps::BeginFunction)
170
171#define CORO_END_FUNCTION \
172 CORO_END_CODE_BLOCK \
173 CORO_START_CODE_BLOCK(CoroOps::EndFunction) \
174 CORO_END_CODE_BLOCK
175
176#define CORO_AWAIT(expr) \
177 (expr); \
178 CORO_END_CODE_BLOCK \
179 CORO_START_CODE_BLOCK(CoroOps::YieldToFunction) \
180 CORO_END_CODE_BLOCK \
181 CORO_START_CODE_BLOCK(CoroOps::Code)
182
183#define CORO_AWAIT_MINISCRIPT(expr) \
184 coroRuntime._miniscriptOutcome = ((expr)); \
185 CORO_END_CODE_BLOCK \
186 CORO_START_CODE_BLOCK(CoroOps::CheckMiniscript) \
187 CORO_END_CODE_BLOCK \
188 CORO_START_CODE_BLOCK(CoroOps::Code)
189
190#define CORO_IF(expr) \
191 CORO_END_CODE_BLOCK \
192 CORO_START_CODE_BLOCK(CoroOps::IfCond) \
193 coroRuntime._condition = !!(expr); \
194 CORO_END_CODE_BLOCK \
195 CORO_START_CODE_BLOCK(CoroOps::IfBody)
196
197#define CORO_ELSE \
198 CORO_END_CODE_BLOCK \
199 CORO_START_CODE_BLOCK(CoroOps::Else)
200
201#define CORO_ELSE_IF(expr) \
202 CORO_END_CODE_BLOCK \
203 CORO_START_CODE_BLOCK(CoroOps::ElseIfCond) \
204 coroRuntime._condition = !!(expr); \
205 CORO_END_CODE_BLOCK \
206 CORO_START_CODE_BLOCK(CoroOps::ElseIfBody)
207
208#define CORO_END_IF \
209 CORO_END_CODE_BLOCK \
210 CORO_START_CODE_BLOCK(CoroOps::EndIf)
211
212#define CORO_WHILE(expr) \
213 CORO_END_CODE_BLOCK \
214 CORO_START_CODE_BLOCK(CoroOps::WhileCond) \
215 coroRuntime._condition = !!(expr); \
216 CORO_END_CODE_BLOCK \
217 CORO_START_CODE_BLOCK(CoroOps::WhileBody)
218
219#define CORO_END_WHILE \
220 CORO_END_CODE_BLOCK \
221 CORO_START_CODE_BLOCK(CoroOps::EndWhile)
222
223#define CORO_DO \
224 CORO_END_CODE_BLOCK \
225 CORO_START_CODE_BLOCK(CoroOps::Do)
226
227#define CORO_DO_WHILE(expr) \
228 CORO_END_CODE_BLOCK \
229 CORO_START_CODE_BLOCK(CoroOps::DoWhileCond) \
230 coroCondition = !(expr); \
231 CORO_END_CODE_BLOCK \
232 CORO_START_CODE_BLOCK(CoroOps::DoWhile)
233
234#define CORO_FOR(initExpr, condExpr, nextExpr) \
235 (initExpr); \
236 CORO_END_CODE_BLOCK \
237 CORO_START_CODE_BLOCK(CoroOps::ForNext) \
238 (nextExpr); \
239 CORO_END_CODE_BLOCK \
240 CORO_START_CODE_BLOCK(CoroOps::ForCond) \
241 coroRuntime._condition = !!(condExpr); \
242 CORO_END_CODE_BLOCK \
243 CORO_START_CODE_BLOCK(CoroOps::ForBody)
244
245#define CORO_END_FOR \
246 CORO_END_CODE_BLOCK \
247 CORO_START_CODE_BLOCK(CoroOps::EndFor)
248
249#define CORO_RETURN_VALUE(expr) \
250 coroReturnValueRef.set((expr)); \
251 CORO_END_CODE_BLOCK \
252 CORO_START_CODE_BLOCK(CoroOps::Return)
253
254#define CORO_ERROR \
255 CORO_END_CODE_BLOCK \
256 CORO_START_CODE_BLOCK(CoroOps::Error)
257
258
259#define CORO_RETURN \
260 coroReturnValueRef.voidSet(); \
261 CORO_END_CODE_BLOCK \
262 CORO_START_CODE_BLOCK(CoroOps::Return)
263
264#define CORO_RETURN_CALL(func, ...) \
265 coroFrame->pushFrame<CoroAutoFrame<func> >(coroReturnValueRef._returnValue, __VA_ARGS__); \
266 CORO_END_CODE_BLOCK \
267 CORO_START_CODE_BLOCK(CoroOps::YieldToFunction) \
268 CORO_END_CODE_BLOCK \
269 CORO_START_CODE_BLOCK(CoroOps::Return)
270
271#define CORO_SET_CALL(dest, func, ...) \
272 CORO_AWAIT(coroRuntime._vthread->pushCoroutineWithReturn<func>(&(dest), __VA_ARGS__))
273
274#define CORO_CALL(func, ...) \
275 CORO_AWAIT(coroRuntime._vthread->pushCoroutine<func>(__VA_ARGS__))
276
277} // Namespace MTropolis
278
279#endif
Definition: vthread.h:133
Definition: vthread.h:52
Definition: actions.h:25
Definition: coroutines.h:50
Definition: coroutine_exec.h:42
Definition: coroutines.h:36
Definition: coroutines.h:66
Definition: coroutines.h:119