|
| 1 | +export module CppUtils.Language.HomoiconicVirtualMachine; |
| 2 | + |
| 3 | +import std; |
| 4 | +import CppUtils.String; |
| 5 | +import CppUtils.Type; |
| 6 | +import CppUtils.Language.GenericVirtualMachine; |
| 7 | + |
| 8 | +export namespace CppUtils::Language::Homoiconic |
| 9 | +{ |
| 10 | + inline constexpr auto interpreter = []<auto... functions>(Type::Specializes<Cursor> auto& cursor, const ASTNode& instruction, auto& virtualMachine) constexpr -> std::expected<void, std::string> { |
| 11 | + using namespace std::literals; |
| 12 | + using namespace String::Literals; |
| 13 | + auto& context = virtualMachine.context; |
| 14 | + auto& [rootAst, hashTable, scopes] = context; |
| 15 | + const auto instructionToken = instruction.value; |
| 16 | + auto grammar = [instructionToken, &scopes]() -> std::reference_wrapper<ASTNode> { |
| 17 | + const auto range = scopes | std::views::reverse; |
| 18 | + auto it = std::ranges::find_if(range, [instructionToken](const auto scope) -> bool { return scope.get().exists(instructionToken); }); |
| 19 | + return it != std::ranges::end(range) ? *it : scopes.front(); |
| 20 | + }(); |
| 21 | + if (grammar.get().exists(instructionToken)) |
| 22 | + { |
| 23 | + auto lexemes = std::ref(grammar.get()[instructionToken].nodes); |
| 24 | + for (auto instructionPosition = 0uz; instructionPosition < std::size(lexemes.get()); ++instructionPosition) |
| 25 | + { |
| 26 | + const auto& lexeme = lexemes.get()[instructionPosition]; |
| 27 | + if (auto result = virtualMachine.template execute<functions...>(cursor, lexeme); not result) [[unlikely]] |
| 28 | + return result; |
| 29 | + lexemes = std::ref(grammar.get()[instructionToken].nodes); |
| 30 | + } |
| 31 | + } |
| 32 | + else |
| 33 | + switch (instructionToken) |
| 34 | + { |
| 35 | + case "call"_token: |
| 36 | + if constexpr (sizeof...(functions) > 0) |
| 37 | + { |
| 38 | + if (std::empty(instruction.nodes)) [[unlikely]] |
| 39 | + return std::unexpected{R"(Instruction "call": Missing parameter)"}; |
| 40 | + else if (auto result = Type::Tuple::visitAt(std::make_tuple(functions...), instruction.nodes[0].value, [&cursor, &virtualMachine](auto&& function) -> decltype(auto) { return function(cursor, virtualMachine); }); not result) |
| 41 | + return std::unexpected{std::string{result.error()}}; |
| 42 | + } |
| 43 | + break; |
| 44 | + default: |
| 45 | + return std::unexpected{std::format(R"(Unknown instruction "{}")", String::getNameOrValue(instructionToken, hashTable))}; |
| 46 | + } |
| 47 | + return {}; |
| 48 | + }; |
| 49 | + |
| 50 | + struct Context final |
| 51 | + { |
| 52 | + // clang-format off |
| 53 | + ASTNode rootAst = {0uz, { |
| 54 | + ASTNode{String::hash("main"), { |
| 55 | + ASTNode{String::hash("executeInstruction")}, |
| 56 | + ASTNode{String::hash("advanceCursor")} |
| 57 | + }}, |
| 58 | + ASTNode{String::hash("executeInstruction"), { |
| 59 | + ASTNode{String::hash("call"), {ASTNode{0}}} |
| 60 | + }}, |
| 61 | + ASTNode{String::hash("advanceCursor"), { |
| 62 | + ASTNode{String::hash("call"), {ASTNode{1}}} |
| 63 | + }} |
| 64 | + }}; |
| 65 | + // clang-format on |
| 66 | + String::HashTable<char> hashTable = String::makeHashTable<char>( |
| 67 | + "main", |
| 68 | + "executeInstruction", |
| 69 | + "advanceCursor", |
| 70 | + "call"); |
| 71 | + std::vector<std::reference_wrapper<ASTNode>> scopes = {std::ref(rootAst)}; |
| 72 | + }; |
| 73 | + |
| 74 | + template<auto inspector = nullptr> |
| 75 | + using VirtualMachine = GenericVirtualMachine<Context, interpreter, inspector>; |
| 76 | + |
| 77 | + constexpr auto printInstruction = [](const Type::Specializes<Cursor> auto&, const ASTNode& instruction, Context& context) -> std::expected<void, std::string> { |
| 78 | + std::println("{}", String::getNameOrValue(instruction.value, context.hashTable)); |
| 79 | + return {}; |
| 80 | + }; |
| 81 | + |
| 82 | + constexpr auto executeInstruction = [](Type::Specializes<Cursor> auto& cursor, auto& virtualMachine) -> std::expected<void, std::string> { |
| 83 | + virtualMachine.template execute<>(cursor, ASTNode{static_cast<Symbol>(cursor.getCurrent())}); |
| 84 | + return {}; |
| 85 | + }; |
| 86 | + |
| 87 | + constexpr auto advanceCursor = [](Type::Specializes<Cursor> auto& cursor, [[maybe_unused]] auto& virtualMachine) -> std::expected<void, std::string> { |
| 88 | + ++cursor.position; |
| 89 | + return {}; |
| 90 | + }; |
| 91 | +} |
0 commit comments