Skip to content

Commit

Permalink
VM: Code refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
mrunix00 committed Jul 6, 2024
1 parent 3a0ffd1 commit bc5fe2b
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 129 deletions.
83 changes: 83 additions & 0 deletions include/utils.h
Original file line number Diff line number Diff line change
@@ -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<Node *>(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;
145 changes: 16 additions & 129 deletions src/ast.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "ast.h"
#include "utils.h"

#include <stdexcept>
#include <utility>
Expand All @@ -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";
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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<Node *>(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!");
Expand All @@ -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: {
Expand Down Expand Up @@ -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!");
}
Expand Down

0 comments on commit bc5fe2b

Please sign in to comment.