Skip to content

Commit

Permalink
refactor: sequence multiplication to own function
Browse files Browse the repository at this point in the history
  • Loading branch information
hrzlgnm committed Dec 16, 2024
1 parent 0b79ed0 commit 04475bc
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 75 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ target_sources(monkey_lib
source/eval/ast_eval.cpp
source/eval/environment.cpp
source/eval/object.cpp
source/eval/util.cpp
source/lexer/lexer.cpp
source/lexer/token.cpp
source/lexer/token_type.cpp
Expand Down
44 changes: 7 additions & 37 deletions source/eval/ast_eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@
#include <overloaded.hpp>
#include <parser/parser.hpp>

#include "code/code.hpp"
#include "environment.hpp"
#include "lexer/token.hpp"
#include "object.hpp"
#include "util.hpp"

auto array_expression::eval(environment* env) const -> const object*
{
Expand Down Expand Up @@ -95,16 +98,6 @@ auto apply_string_binary_operator(token_type oper, const std::string& left, cons
return {};
}
}

template<typename O>
auto multiply_sequence(const typename O::value_type& values, int64_t count) -> object*
{
typename O::value_type target;
for (int64_t i = 0; i < count; i++) {
std::copy(values.cbegin(), values.cend(), std::back_inserter(target));
}
return make<O>(std::move(target));
}
} // namespace

auto binary_expression::eval(environment* env) const -> const object*
Expand All @@ -118,35 +111,12 @@ auto binary_expression::eval(environment* env) const -> const object*
if (evaluated_right->is_error()) {
return evaluated_right;
}
using enum object::object_type;
if ((evaluated_left->is(integer) && evaluated_right->is(array))
|| (evaluated_left->is(array) && evaluated_right->is(integer)) && op == token_type::asterisk)
{
const array_object* arr {};
const integer_object* integer {};
if (evaluated_left->is(array)) {
arr = evaluated_left->as<array_object>();
integer = evaluated_right->as<integer_object>();
} else {
arr = evaluated_right->as<array_object>();
integer = evaluated_left->as<integer_object>();
}
return multiply_sequence<array_object>(arr->value, integer->value);
}
if ((evaluated_left->is(integer) && evaluated_right->is(string))
|| (evaluated_left->is(string) && evaluated_right->is(integer)) && op == token_type::asterisk)
{
const string_object* str {};
const integer_object* integer {};
if (evaluated_left->is(string)) {
str = evaluated_left->as<string_object>();
integer = evaluated_right->as<integer_object>();
} else {
str = evaluated_right->as<string_object>();
integer = evaluated_left->as<integer_object>();
if (op == token_type::asterisk) {
if (const auto* multiplied = evaluate_sequence_mul(evaluated_left, evaluated_right); multiplied != nullptr) {
return multiplied;
}
return multiply_sequence<string_object>(str->value, integer->value);
}
using enum object::object_type;
if (evaluated_left->type() != evaluated_right->type()) {
return make_error("type mismatch: {} {} {}", evaluated_left->type(), op, evaluated_right->type());
}
Expand Down
4 changes: 4 additions & 0 deletions source/eval/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ struct string_object : hashable_object
{
using value_type = std::string;

string_object() = default;

explicit string_object(std::string val)
: value {std::move(val)}
{
Expand Down Expand Up @@ -192,6 +194,8 @@ struct array_object : object
{
using value_type = std::vector<const object*>;

array_object() = default;

explicit array_object(value_type&& arr)
: value {std::move(arr)}
{
Expand Down
48 changes: 48 additions & 0 deletions source/eval/util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

#include "util.hpp"

#include <gc.hpp>

#include "object.hpp"

namespace
{
template<class T, class U>
concept Derived = std::is_base_of_v<U, T>;

template<Derived<object> SequenceObject>
auto multiply_sequence(const SequenceObject* source, integer_object::value_type count) -> SequenceObject*
{
typename SequenceObject::value_type target;
for (integer_object::value_type i = 0; i < count; i++) {
std::copy(source->value.cbegin(), source->value.cend(), std::back_inserter(target));
}
return make<SequenceObject>(std::move(target));
}

template<typename T>
auto handle_mul(const object* lhs, const object* rhs) -> const object*
{
using enum object::object_type;
auto seq_type = T {}.type();
if (lhs->is(integer) && rhs->is(seq_type)) {
return multiply_sequence(rhs->as<T>(), lhs->as<integer_object>()->value);
}
if (lhs->is(seq_type) && rhs->is(integer)) {
return multiply_sequence(lhs->as<T>(), rhs->as<integer_object>()->value);
}
return nullptr;
}

} // namespace

auto evaluate_sequence_mul(const object* lhs, const object* rhs) -> const object*
{
if (const auto* result = handle_mul<array_object>(lhs, rhs)) {
return result;
}
if (const auto* result = handle_mul<string_object>(lhs, rhs)) {
return result;
}
return nullptr;
}
3 changes: 3 additions & 0 deletions source/eval/util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "object.hpp"

auto evaluate_sequence_mul(const object* lhs, const object* rhs) -> const object*;
43 changes: 5 additions & 38 deletions source/vm/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <compiler/compiler.hpp>
#include <doctest/doctest.h>
#include <eval/object.hpp>
#include <eval/util.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <gc.hpp>
Expand Down Expand Up @@ -193,50 +194,16 @@ auto vm::last_popped() const -> const object*
return m_stack[m_sp];
}

namespace
{
template<typename O>
auto multiply_sequence(const typename O::value_type& values, int64_t count) -> object*
{
typename O::value_type target;
for (int64_t i = 0; i < count; i++) {
std::copy(values.cbegin(), values.cend(), std::back_inserter(target));
}
return make<O>(std::move(target));
}
} // namespace

auto vm::exec_binary_op(opcodes opcode) -> void
{
const auto* right = pop();
const auto* left = pop();
using enum object::object_type;
if ((left->is(integer) && right->is(array)) || (left->is(array) && right->is(integer)) && opcode == opcodes::mul) {
const array_object* arr {};
const integer_object* integer {};
if (left->is(array)) {
arr = left->as<array_object>();
integer = right->as<integer_object>();
} else {
arr = right->as<array_object>();
integer = left->as<integer_object>();
}
push(multiply_sequence<array_object>(arr->value, integer->value));
return;
}
if ((left->is(integer) && right->is(string)) || (left->is(string) && right->is(integer)) && opcode == opcodes::mul)
{
const string_object* str {};
const integer_object* integer {};
if (left->is(string)) {
str = left->as<string_object>();
integer = right->as<integer_object>();
} else {
str = right->as<string_object>();
integer = left->as<integer_object>();
if (opcode == opcodes::mul) {
if (const auto* multiplied = evaluate_sequence_mul(left, right); multiplied) {
push(multiplied);
return;
}
push(multiply_sequence<string_object>(str->value, integer->value));
return;
}
if (left->is(integer) && right->is(integer)) {
auto left_value = left->as<integer_object>()->value;
Expand Down

0 comments on commit 04475bc

Please sign in to comment.