diff --git a/include/utils.h b/include/utils.h index 2f29002..e30d19f 100644 --- a/include/utils.h +++ b/include/utils.h @@ -22,6 +22,7 @@ throw std::runtime_error("[Node::compile] Identifier not found: " + identifier); \ } \ switch (type->type) { \ + case VariableType::Type::Array: \ case VariableType::Type::Object: \ instruction.type = isLocal ? Instruction::InstructionType::OPERATION##LocalObject \ : Instruction::InstructionType::OPERATION##GlobalObject; \ diff --git a/include/vm.h b/include/vm.h index a573170..932ac06 100644 --- a/include/vm.h +++ b/include/vm.h @@ -37,6 +37,7 @@ struct Instruction { MakeArray, LoadFromLocalArray, LoadFromGlobalArray, + AppendToArray, Return, Call, JumpIfFalse, @@ -69,7 +70,7 @@ struct FunctionType : public VariableType { }; struct ArrayObjectType : public VariableType { VariableType *elementType; - explicit ArrayObjectType(VariableType *elementType) : VariableType(Object), elementType(elementType){}; + explicit ArrayObjectType(VariableType *elementType) : VariableType(Array), elementType(elementType){}; }; struct Object { diff --git a/src/ast.cpp b/src/ast.cpp index 9291c35..392f4ec 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -61,23 +61,28 @@ void BinaryExpression::compile(Program &program, Segment &segment) const { emitStore(program, segment, dynamic_cast(*left).token.value); return; } - if (op.type == IncrementAssign || op.type == DecrementAssign) { + if ((op.type == IncrementAssign || op.type == DecrementAssign) && + left->nodeType == AbstractSyntaxTree::Type::Node) { auto node = dynamic_cast(left); if (node->token.type != Identifier) throw std::runtime_error("[BinaryExpression::compile] Invalid expression varType!"); - auto varType = segment.find_local(node->token.value) != -1 ? segment.locals[node->token.value].type : program.segments[0].locals[node->token.value].type; + auto varType = segment.find_local(node->token.value) != -1 ? segment.locals[node->token.value] : program.segments[0].locals[node->token.value]; emitLoad(program, segment, node->token.value); right->compile(program, segment); switch (op.type) { case IncrementAssign: - switch (varType->type) { + switch (varType.type->type) { VAR_CASE(Add, I64) + case VariableType::Array: { + left->compile(program, segment); + segment.instructions.push_back({.type = Instruction::AppendToArray}); + } break; default: throw std::runtime_error("[BinaryExpression::compile] Invalid varType!"); } break; case DecrementAssign: - switch (varType->type) { + switch (varType.type->type) { VAR_CASE(Sub, I64) default: throw std::runtime_error("[BinaryExpression::compile] Invalid varType!"); diff --git a/src/vm.cpp b/src/vm.cpp index 7fb2b6f..d332b45 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -232,7 +232,10 @@ void VM::run(const Program &program) { pushStack(std::bit_cast(instruction.params.ptr)); } break; case Instruction::MakeArray: { - auto data = new uint64_t[instruction.params.index]; + auto data = (uint64_t *) malloc(instruction.params.index * sizeof(uint64_t)); + if (data == nullptr) { + throw std::runtime_error("Memory allocation failure!"); + } for (size_t i = instruction.params.index - 1; i != -1; i--) { auto val = popStack(); data[i] = val; @@ -256,6 +259,17 @@ void VM::run(const Program &program) { } pushStack(array->data[index]); } break; + case Instruction::AppendToArray: { + auto array = std::bit_cast(popStack()); + auto val = popStack(); + auto data = (uint64_t*) realloc(array->data, (array->size + 1) * sizeof(uint64_t)); + if (data == nullptr) { + throw std::runtime_error("Memory allocation failure!"); + } + array->data = data; + array->data[array->size++] = val; + pushStack(std::bit_cast(array)); + } break; case Instruction::Exit: return; } diff --git a/tests/vm_tests.cpp b/tests/vm_tests.cpp index e64181a..0732736 100644 --- a/tests/vm_tests.cpp +++ b/tests/vm_tests.cpp @@ -243,3 +243,14 @@ TEST(VM, ArrayAccess) { vm.run(program); ASSERT_EQ(vm.topStack(), 3); } + +TEST(VM, AppendToArray){ + const char *input = "define x : int[] = [1, 2, 3, 4];" + "x += 5;" + "x;"; + VM vm; + auto program = compile(input); + vm.run(program); + auto obj = reinterpret_cast(vm.topStack()); + ASSERT_EQ(*obj, std::vector({1, 2, 3, 4, 5})); +}