From bc5fe2be794f08ec622d3de14bc5ddca38dfa4c3 Mon Sep 17 00:00:00 2001 From: "Mr.UNIX" Date: Sat, 6 Jul 2024 18:03:33 +0100 Subject: [PATCH] VM: Code refactor --- include/utils.h | 83 +++++++++++++++++++++++++++ src/ast.cpp | 145 ++++++------------------------------------------ 2 files changed, 99 insertions(+), 129 deletions(-) create mode 100644 include/utils.h diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..4d9856c --- /dev/null +++ b/include/utils.h @@ -0,0 +1,83 @@ +#pragma once + +#include "vm.h" + +#define GENERATE_EMIT_FUNCTION(OPERATION) \ + static inline void emit##OPERATION(Program &program, Segment &segment, const std::string &identifier) { \ + size_t id; \ + bool isLocal; \ + Instruction instruction; \ + Variable::Type type; \ + if (segment.find_local(identifier) != -1) { \ + isLocal = true; \ + id = segment.find_local(identifier); \ + type = segment.locals[identifier].type; \ + } else if (program.find_global(identifier) != -1) { \ + isLocal = false; \ + id = program.find_global(identifier); \ + type = program.segments[0].locals[identifier].type; \ + } else { \ + throw std::runtime_error("[Node::compile] Identifier not found: " + identifier); \ + } \ + switch (type) { \ + case Variable::Type::I32: \ + instruction.type = isLocal ? Instruction::InstructionType::OPERATION##LocalI32 \ + : Instruction::InstructionType::OPERATION##GlobalI32; \ + instruction.params.index = id; \ + break; \ + case Variable::Type::I64: \ + instruction.type = isLocal ? Instruction::InstructionType::OPERATION##LocalI64 \ + : Instruction::InstructionType::OPERATION##GlobalI64; \ + instruction.params.index = id; \ + break; \ + default: \ + throw std::runtime_error("[Node::compile] Invalid variable type!"); \ + } \ + segment.instructions.push_back(instruction); \ + } +GENERATE_EMIT_FUNCTION(Load) +GENERATE_EMIT_FUNCTION(Store) + +static inline Variable::Type varTypeConvert(AbstractSyntaxTree *ast) { + if (ast->nodeType != AbstractSyntaxTree::Type::Node) + throw std::runtime_error("[Declaration::compile] Invalid type: " + ast->typeStr); + auto token = dynamic_cast(ast)->token; + switch (token.type) { + case I32: + return Variable::Type::I32; + case I64: + return Variable::Type::I64; + default: + throw std::runtime_error("[Declaration::compile] Invalid type: " + token.value); + } +} + +#define DECLARE_NUMBER_VAR(TYPE, PARAM) \ + case TYPE: { \ + segment.instructions.push_back({.type = Instruction::InstructionType::Load##TYPE, \ + .params = {.PARAM = std::stoi(initNode->token.value)}}); \ + segment.instructions.push_back({ \ + .type = segment.id == 0 \ + ? Instruction::InstructionType::StoreGlobal##TYPE \ + : Instruction::InstructionType::StoreLocal##TYPE, \ + .params = {.index = segment.locals.size()}, \ + }); \ + segment.declare_variable(identifier.token.value, Variable::Type::TYPE); \ + } break; + +#define DECLARE_OTHER_VAR(TYPE) \ + case TYPE: { \ + initNode->compile(program, segment); \ + segment.instructions.push_back({ \ + .type = segment.id == 0 \ + ? Instruction::InstructionType::StoreGlobal##TYPE \ + : Instruction::InstructionType::StoreLocal##TYPE, \ + .params = {.index = segment.locals.size()}, \ + }); \ + segment.declare_variable(identifier.token.value, Variable::Type::TYPE); \ + } break; + +#define VAR_CASE(OP, TYPE) \ + case Variable::Type::TYPE: \ + segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::OP##TYPE}); \ + break; \ No newline at end of file diff --git a/src/ast.cpp b/src/ast.cpp index e2743c4..df85ac2 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -1,4 +1,5 @@ #include "ast.h" +#include "utils.h" #include #include @@ -8,42 +9,6 @@ static inline void assert(bool condition, const char *message) { throw std::runtime_error("Assertion failed: " + std::string(message)); } -#define GENERATE_EMIT_FUNCTION(OPERATION) \ - static inline void emit##OPERATION(Program &program, Segment &segment, const std::string &identifier) { \ - size_t id; \ - bool isLocal; \ - Instruction instruction; \ - Variable::Type type; \ - if (segment.find_local(identifier) != -1) { \ - isLocal = true; \ - id = segment.find_local(identifier); \ - type = segment.locals[identifier].type; \ - } else if (program.find_global(identifier) != -1) { \ - isLocal = false; \ - id = program.find_global(identifier); \ - type = program.segments[0].locals[identifier].type; \ - } else { \ - throw std::runtime_error("[Node::compile] Identifier not found: " + identifier); \ - } \ - switch (type) { \ - case Variable::Type::I32: \ - instruction.type = isLocal ? Instruction::InstructionType::OPERATION##LocalI32 \ - : Instruction::InstructionType::OPERATION##GlobalI32; \ - instruction.params.index = id; \ - break; \ - case Variable::Type::I64: \ - instruction.type = isLocal ? Instruction::InstructionType::OPERATION##LocalI64 \ - : Instruction::InstructionType::OPERATION##GlobalI64; \ - instruction.params.index = id; \ - break; \ - default: \ - throw std::runtime_error("[Node::compile] Invalid variable type!"); \ - } \ - segment.instructions.push_back(instruction); \ - } -GENERATE_EMIT_FUNCTION(Load) -GENERATE_EMIT_FUNCTION(Store) - Node::Node(Token token) : token(std::move(token)) { nodeType = Type::Node; typeStr = "Node"; @@ -103,23 +68,6 @@ void BinaryExpression::compile(Program &program, Segment &segment) const { } left->compile(program, segment); - if (right->nodeType == AbstractSyntaxTree::Type::Node && - ((Node *) right)->token.value == "1" && - left->nodeType == AbstractSyntaxTree::Type::Node && - ((Node *) left)->token.type == Identifier) { - switch (op.type) { - case Plus: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::IncrementI32}); - return; - case Minus: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::DecrementI32}); - return; - case Multiply: - case Divide: - return; - } - } - right->compile(program, segment); switch (op.type) { case Plus: @@ -193,19 +141,6 @@ bool Declaration::operator==(const AbstractSyntaxTree &other) const { value.has_value() == otherDeclaration.value.has_value(); } -static inline Variable::Type varTypeConvert(AbstractSyntaxTree *ast) { - if (ast->nodeType != AbstractSyntaxTree::Type::Node) - throw std::runtime_error("[Declaration::compile] Invalid type: " + ast->typeStr); - auto token = dynamic_cast(ast)->token; - switch (token.type) { - case I32: - return Variable::Type::I32; - case I64: - return Variable::Type::I64; - default: - throw std::runtime_error("[Declaration::compile] Invalid type: " + token.value); - } -} void Declaration::compile(Program &program, Segment &segment) const { if (!type.has_value()) throw std::runtime_error("[Declaration::compile] Type deduction is not implemented!"); @@ -215,58 +150,18 @@ void Declaration::compile(Program &program, Segment &segment) const { Node *typeNode = (Node *) type.value(); if (initNode->token.type == Number) { switch (typeNode->token.type) { - case I32: { - segment.instructions.push_back({ - .type = Instruction::InstructionType::LoadI32, - .params = {.i32 = std::stoi(initNode->token.value)} - }); - segment.instructions.push_back({ - .type = segment.id == 0 - ? Instruction::InstructionType::StoreGlobalI32 - : Instruction::InstructionType::StoreLocalI32, - .params = {.index = segment.locals.size()}, - }); - segment.declare_variable(identifier.token.value, Variable::Type::I32); - } break; - case I64: { - segment.instructions.push_back({ - .type = Instruction::InstructionType::LoadI64, - .params = {.i64 = std::stol(initNode->token.value)} - }); - segment.instructions.push_back({ - .type = segment.id == 0 - ? Instruction::InstructionType::StoreGlobalI64 - : Instruction::InstructionType::StoreLocalI64, - .params = {.index = segment.locals.size()}, - }); - segment.declare_variable(identifier.token.value, Variable::Type::I64); - } break; + DECLARE_NUMBER_VAR(I32, i32) + DECLARE_NUMBER_VAR(I64, i64) + default: + throw std::runtime_error("[Declaration::compile] Unimplemented type handler!"); + } + } else { + switch (typeNode->token.type) { + DECLARE_OTHER_VAR(I32) + DECLARE_OTHER_VAR(I64) + default: + throw std::runtime_error("[Declaration::compile] Unimplemented type handler!"); } - return; - } - switch (typeNode->token.type) { - case I32: { - initNode->compile(program, segment); - segment.instructions.push_back({ - .type = segment.id == 0 - ? Instruction::InstructionType::StoreGlobalI32 - : Instruction::InstructionType::StoreLocalI32, - .params = {.index = segment.locals.size()}, - }); - segment.declare_variable(identifier.token.value, Variable::Type::I32); - } break; - case I64: { - initNode->compile(program, segment); - segment.instructions.push_back({ - .type = segment.id == 0 - ? Instruction::InstructionType::StoreGlobalI64 - : Instruction::InstructionType::StoreLocalI64, - .params = {.index = segment.locals.size()}, - }); - segment.declare_variable(identifier.token.value, Variable::Type::I64); - } break; - default: - throw std::runtime_error("[Declaration::compile] Unimplemented type handler!"); } } break; case AbstractSyntaxTree::Type::FunctionDeclaration: { @@ -514,24 +409,16 @@ void UnaryExpression::compile(Program &program, Segment &segment) const { switch (op.type) { case Increment: switch (varType) { - case Variable::Type::I32: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::IncrementI32}); - break; - case Variable::Type::I64: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::IncrementI64}); - break; + VAR_CASE(Increment, I32) + VAR_CASE(Increment, I64) default: throw std::runtime_error("[UnaryExpression::compile] Invalid varType!"); } break; case Decrement: switch (varType) { - case Variable::Type::I32: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::DecrementI32}); - break; - case Variable::Type::I64: - segment.instructions.push_back(Instruction{.type = Instruction::InstructionType::DecrementI64}); - break; + VAR_CASE(Decrement, I32) + VAR_CASE(Decrement, I64) default: throw std::runtime_error("[UnaryExpression::compile] Invalid varType!"); }