@@ -2,9 +2,12 @@ export module CppUtils.Language.MetaCircularVirtualMachine;
22
33import std;
44import CppUtils.Container.MeshNetwork;
5+ import CppUtils.Container.SafeShared;
6+ import CppUtils.Execution.Event;
57import CppUtils.Execution.ScopeGuard;
68import CppUtils.Language.AST;
79import CppUtils.String;
10+ import CppUtils.Thread.SharedLocker;
811import CppUtils.Thread.ThreadPool;
912import CppUtils.Type.Specialization;
1013
@@ -88,6 +91,21 @@ export namespace CppUtils::Language
8891 std::expected<MeshNodePtr, std::string_view> value;
8992 };
9093
94+ struct Environment final
95+ {
96+ Thread::SharedLocker<std::unordered_map<Type::Token, std::function<StepResult(MetaCircularVirtualMachine&, MeshNodePtr)>>> functions;
97+ Thread::ThreadPool threadPool;
98+ Thread::SharedLocker<std::unordered_map<std::size_t, std::shared_ptr<std::future<void>>>> threads;
99+ Thread::SharedLocker<std::unordered_map<std::size_t, std::shared_ptr<Execution::Event>>> events;
100+ std::atomic<std::size_t> nextThreadId{0};
101+ std::atomic<std::size_t> nextEventId{0};
102+ Thread::SharedLocker<std::string> firstErrorMessage;
103+ std::atomic<bool> stopRequested{false};
104+ };
105+
106+ MeshNodePtr context = MeshNodePtr::makeRoot(0uz);
107+ std::shared_ptr<Environment> environment;
108+
91109 [[nodiscard]] static inline auto next(MeshNodePtr instruction) noexcept -> MeshNodePtr
92110 {
93111 using namespace String::Literals;
@@ -96,18 +114,15 @@ export namespace CppUtils::Language
96114 .value_or(MeshNodePtr{});
97115 }
98116
99- MeshNodePtr context = MeshNodePtr::makeRoot(0uz);
100- std::unordered_map<Type::Token, std::function<StepResult(MetaCircularVirtualMachine&, MeshNodePtr)>> functions;
101- Thread::ThreadPool threadPool;
102-
103117 template<class T = MetaCircularVirtualMachine>
104118 inline auto addFunction(Type::Token token, auto&& function) -> void
105119 {
106120 using namespace String::Literals;
107121
108- if (not functions.contains(token))
122+ auto functions = environment->functions.uniqueAccess();
123+ if (not functions.value().contains(token))
109124 {
110- functions[token] = [function = std::forward<decltype(function)>(function)](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> StepResult {
125+ functions.value() [token] = [function = std::forward<decltype(function)>(function)](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> StepResult {
111126 return StepResult{function(static_cast<T&>(interpreter), instruction)};
112127 };
113128 if (not context.contains(token))
@@ -145,11 +160,35 @@ export namespace CppUtils::Language
145160 };
146161 }
147162
148- inline MetaCircularVirtualMachine()
163+ inline explicit MetaCircularVirtualMachine(std::shared_ptr<Environment> environment):
164+ environment{std::move(environment)}
165+ {}
166+
167+ inline MetaCircularVirtualMachine():
168+ environment{std::make_shared<Environment>()}
149169 {
150170 using namespace std::literals;
151171 using namespace String::Literals;
152172
173+ environment->threadPool.setOnError([environment = environment](std::exception_ptr exceptionPointer) {
174+ if (environment->stopRequested.exchange(true))
175+ return;
176+
177+ try
178+ {
179+ if (exceptionPointer)
180+ std::rethrow_exception(exceptionPointer);
181+ }
182+ catch (const std::exception& exception)
183+ {
184+ environment->firstErrorMessage.uniqueAccess().value() = exception.what();
185+ }
186+ catch (...)
187+ {
188+ environment->firstErrorMessage.uniqueAccess().value() = "Unknown background error";
189+ }
190+ });
191+
153192 addFunction("define"_token, [](MetaCircularVirtualMachine&, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
154193 return instruction.at("value"_token)
155194 .and_then([](auto valueBranch) { return valueBranch.back(); })
@@ -238,10 +277,146 @@ export namespace CppUtils::Language
238277 addFunction("/"_token, arithmeticOperation<"/">(std::divides<>{}));
239278 addFunction("%"_token, arithmeticOperation<"%">(std::modulus<>{}));
240279 addFunction("<"_token, arithmeticOperation<"<">(std::less<>{}));
280+
281+ addFunction("thread"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
282+ auto targetInstruction = instruction.at("target"_token).and_then([](auto branch) { return branch.front(); });
283+ if (not targetInstruction)
284+ return std::unexpected{"thread: Missing target"sv};
285+
286+ auto threadContext = MeshNodePtr::makeRoot("threadContext"_token);
287+ threadContext["scope"_token] >> interpreter.context;
288+
289+ auto task = [target = targetInstruction.value(),
290+ threadContext = std::move(threadContext),
291+ environment = interpreter.environment]() mutable {
292+ auto threadInterpreter = MetaCircularVirtualMachine{std::move(environment)};
293+ threadInterpreter.context = std::move(threadContext);
294+
295+ if (auto result = threadInterpreter(target); not result)
296+ throw std::runtime_error{std::string{result.error()}};
297+ };
298+
299+ auto id = interpreter.environment->nextThreadId++;
300+ interpreter.environment->threads.uniqueAccess().value()[id] = std::make_shared<std::future<void>>(interpreter.environment->threadPool.call(task));
301+
302+ auto resultNode = instruction.at("result"_token).and_then([](auto branch) { return branch.front(); });
303+ if (not resultNode)
304+ return std::unexpected{"thread: Missing result node"sv};
305+
306+ resultNode->setValue(id);
307+
308+ return next(instruction);
309+ });
310+
311+ addFunction("join"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
312+ auto idNode = instruction.at("thread"_token).and_then([](auto branch) { return branch.front(); });
313+ if (not idNode)
314+ return std::unexpected{"join: Missing thread id"sv};
315+
316+ auto id = idNode->getValue().value();
317+ auto future = [&]() -> std::shared_ptr<std::future<void>> {
318+ auto threads = interpreter.environment->threads.sharedAccess();
319+ if (auto it = threads.value().find(id); it != std::end(threads.value()))
320+ return it->second;
321+ return nullptr;
322+ }();
323+
324+ if (future and future->valid())
325+ future->wait();
326+
327+ {
328+ auto threads = interpreter.environment->threads.uniqueAccess();
329+ threads.value().erase(id);
330+ }
331+
332+ return next(instruction);
333+ });
334+
335+ addFunction("detach"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
336+ auto idNode = instruction.at("thread"_token).and_then([](auto branch) { return branch.front(); });
337+ if (not idNode)
338+ return std::unexpected{"detach: Missing thread id"sv};
339+
340+ auto id = idNode->getValue().value();
341+ auto threads = interpreter.environment->threads.uniqueAccess();
342+ threads.value().erase(id);
343+
344+ return next(instruction);
345+ });
346+
347+ addFunction("event"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
348+ auto resultNode = instruction.at("result"_token).and_then([](auto branch) { return branch.front(); });
349+ if (not resultNode)
350+ return std::unexpected{"event: Missing result node"sv};
351+
352+ auto id = interpreter.environment->nextEventId++;
353+ interpreter.environment->events.uniqueAccess().value()[id] = std::make_shared<Execution::Event>();
354+
355+ resultNode->setValue(id);
356+
357+ return next(instruction);
358+ });
359+
360+ addFunction("wait"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
361+ auto idNode = instruction.at("event"_token).and_then([](auto branch) { return branch.front(); });
362+ if (not idNode)
363+ return std::unexpected{"wait: Missing event id"sv};
364+
365+ auto id = idNode->getValue().value();
366+ auto event = [&]() -> std::shared_ptr<Execution::Event> {
367+ auto events = interpreter.environment->events.sharedAccess();
368+ if (auto it = events.value().find(id); it != std::end(events.value()))
369+ return it->second;
370+ return nullptr;
371+ }();
372+
373+ if (event)
374+ event->wait();
375+
376+ return next(instruction);
377+ });
378+
379+ addFunction("notify"_token, [](MetaCircularVirtualMachine& interpreter, MeshNodePtr instruction) -> std::expected<MeshNodePtr, std::string_view> {
380+ auto idNode = instruction.at("event"_token).and_then([](auto branch) { return branch.front(); });
381+ if (not idNode)
382+ return std::unexpected{"notify: Missing event id"sv};
383+
384+ auto id = idNode->getValue().value();
385+ auto event = [&]() -> std::shared_ptr<Execution::Event> {
386+ auto events = interpreter.environment->events.sharedAccess();
387+ if (auto it = events.value().find(id); it != std::end(events.value()))
388+ return it->second;
389+ return nullptr;
390+ }();
391+
392+ if (event)
393+ event->notify();
394+
395+ return next(instruction);
396+ });
241397 }
242398
243399 virtual ~MetaCircularVirtualMachine() = default;
244400
401+ [[nodiscard]] inline auto reportError(std::string_view message) const -> std::expected<void, std::string_view>
402+ {
403+ if (not environment->stopRequested.exchange(true))
404+ environment->firstErrorMessage.uniqueAccess().value() = message;
405+
406+ return resultWithBackgroundErrors(std::unexpected{message});
407+ }
408+
409+ [[nodiscard]] inline auto resultWithBackgroundErrors(std::expected<void, std::string_view> result) const -> std::expected<void, std::string_view>
410+ {
411+ if (not environment->stopRequested.load())
412+ return result;
413+
414+ if (auto firstError = environment->firstErrorMessage.sharedAccess(); not std::empty(firstError.value()))
415+ return std::unexpected{std::string_view{firstError.value()}};
416+
417+ return result;
418+ }
419+
245420 [[nodiscard]] inline auto get(Type::Token token) -> std::expected<MeshNodePtr, std::string_view>
246421 {
247422 using namespace std::literals;
@@ -260,7 +435,7 @@ export namespace CppUtils::Language
260435 {
261436 using namespace String::Literals;
262437
263- while (instruction)
438+ while (instruction and not environment->stopRequested.load() )
264439 {
265440 auto definition = instruction;
266441 while (true)
@@ -276,18 +451,24 @@ export namespace CppUtils::Language
276451 }
277452
278453 auto definitionToken = definition.getValue().value();
279- if (auto functionIt = functions.find(definitionToken); functionIt != std::cend(functions))
280- if (auto result = functionIt->second(*this, instruction).value)
454+
455+ if (auto function = [&]() -> std::function<StepResult(MetaCircularVirtualMachine&, MeshNodePtr)> {
456+ auto functions = environment->functions.sharedAccess();
457+ if (auto functionIt = functions.value().find(definitionToken); functionIt != std::cend(functions.value()))
458+ return functionIt->second;
459+ return nullptr;
460+ }())
461+ if (auto result = function(*this, instruction).value)
281462 instruction = result.value();
282463 else
283- return std::unexpected{ result.error()} ;
464+ return reportError( result.error()) ;
284465 else if (auto branch = definition.at("next"_token))
285466 instruction = branch.value().front().value_or(MeshNodePtr{});
286467 else
287468 break;
288469 }
289470
290- return {} ;
471+ return resultWithBackgroundErrors({}) ;
291472 }
292473
293474 [[nodiscard]] inline auto operator()(Type::Token token) -> std::expected<void, std::string_view>
@@ -297,15 +478,20 @@ export namespace CppUtils::Language
297478 if (auto instruction = get(token))
298479 return (*this)(instruction.value());
299480
300- if (auto functionIt = functions.find(token); functionIt != std::cend(functions))
481+ if (auto function = [&]() -> std::function<StepResult(MetaCircularVirtualMachine&, MeshNodePtr)> {
482+ auto functions = environment->functions.sharedAccess();
483+ if (auto functionIt = functions.value().find(token); functionIt != std::cend(functions.value()))
484+ return functionIt->second;
485+ return nullptr;
486+ }())
301487 {
302- if (auto result = functionIt->second (*this, MeshNodePtr::make(token)).value)
303- return ( *this)(result.value());
488+ if (auto result = function (*this, MeshNodePtr::make(token)).value)
489+ return resultWithBackgroundErrors(( *this)(result.value() ));
304490 else
305- return std::unexpected{ result.error()} ;
491+ return reportError( result.error()) ;
306492 }
307493
308- return std::unexpected{ "Unknown function"sv} ;
494+ return reportError( "Unknown function"sv) ;
309495 }
310496 };
311497 }
0 commit comments