Skip to content

Commit

Permalink
fix: bang operator in eval and vm (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
hrzlgnm authored Dec 14, 2024
1 parent 3404a25 commit 80d300a
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 34 deletions.
13 changes: 9 additions & 4 deletions source/eval/ast_eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,7 @@ auto unary_expression::eval(environment* env) const -> const object*
}
return make<integer_object>(-evaluated_value->as<integer_object>()->value);
case exclamation:
if (!evaluated_value->is(object::object_type::boolean)) {
return native_bool_to_object(/*val=*/false);
}
return native_bool_to_object(!evaluated_value->as<boolean_object>()->value);
return native_bool_to_object(!evaluated_value->is_truthy());
default:
return make_error("unknown operator: {}{}", op, evaluated_value->type());
}
Expand Down Expand Up @@ -386,6 +383,7 @@ const builtin_function_expression builtin_puts {"puts",
fmt::print("\n");
return native_null();
}};

const builtin_function_expression builtin_first {
"first",
{"arr"},
Expand All @@ -412,6 +410,7 @@ const builtin_function_expression builtin_first {
}
return make_error("argument of type {} to first() is not supported", maybe_string_or_array->type());
}};

const builtin_function_expression builtin_last {
"last",
{"arr"},
Expand All @@ -438,6 +437,7 @@ const builtin_function_expression builtin_last {
}
return make_error("argument of type {} to last() is not supported", maybe_string_or_array->type());
}};

const builtin_function_expression builtin_rest {
"rest",
{"arr"},
Expand Down Expand Up @@ -466,6 +466,7 @@ const builtin_function_expression builtin_rest {
}
return make_error("argument of type {} to rest() is not supported", maybe_string_or_array->type());
}};

const builtin_function_expression builtin_push {
"push",
{"arr", "val"},
Expand Down Expand Up @@ -694,12 +695,16 @@ TEST_CASE("bangOperator")
et {"!true", false},
et {"!false", true},
et {"!false", true},
et {"!0", true},
et {"!5", false},
et {R"(!"a")", false},
et {R"(!"")", true},
et {"!!true", true},
et {"!!false", false},
et {"!!5", true},
et {R"(!!"a")", true},
et {R"(![])", true},
et {R"(!{})", true},
};
for (const auto& [input, expected] : tests) {
const auto evaluated = run(input);
Expand Down
15 changes: 6 additions & 9 deletions source/eval/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@

#include "object.hpp"

environment::environment(environment* parent_env)
: m_parent(parent_env)
environment::environment(environment* outer_env)
: outer(outer_env)
{
if (m_parent == this) {
abort();
}
}

auto environment::get(const std::string& name) const -> const object*
{
for (const auto* ptr = this; ptr != nullptr; ptr = ptr->m_parent) {
if (const auto itr = ptr->m_store.find(name); itr != ptr->m_store.end()) {
for (const auto* ptr = this; ptr != nullptr; ptr = ptr->outer) {
if (const auto itr = ptr->store.find(name); itr != ptr->store.end()) {
return itr->second;
}
}
Expand All @@ -24,12 +21,12 @@ auto environment::get(const std::string& name) const -> const object*

auto environment::set(const std::string& name, const object* val) -> void
{
m_store[name] = val;
store[name] = val;
}

auto environment::debug() const -> void
{
for (const auto& [k, v] : m_store) {
for (const auto& [k, v] : store) {
fmt::print("[{}] = {}\n", k, v->inspect());
}
}
7 changes: 3 additions & 4 deletions source/eval/environment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ struct object;

struct environment
{
explicit environment(environment* parent_env = nullptr);
explicit environment(environment* outer_env = nullptr);

auto debug() const -> void;
auto get(const std::string& name) const -> const object*;
auto set(const std::string& name, const object* val) -> void;

private:
std::unordered_map<std::string, const object*> m_store;
environment* m_parent {};
std::unordered_map<std::string, const object*> store;
environment* outer {};
};
8 changes: 8 additions & 0 deletions source/eval/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ const boolean_object true_obj {/*val=*/true};
const null_object null_obj;
} // namespace

auto native_bool_to_object(bool val) -> const object*
{
if (val) {
return &true_obj;
}
return &false_obj;
}

auto native_true() -> const object*
{
return &true_obj;
Expand Down
17 changes: 9 additions & 8 deletions source/eval/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ struct integer_object : hashable_object
{
}

[[nodiscard]] auto is_truthy() const -> bool override { return value != 0; }

[[nodiscard]] auto type() const -> object_type override { return object_type::integer; }

[[nodiscard]] auto inspect() const -> std::string override { return std::to_string(value); }
Expand Down Expand Up @@ -124,14 +126,7 @@ struct boolean_object : hashable_object

auto native_true() -> const object*;
auto native_false() -> const object*;

inline auto native_bool_to_object(bool val) -> const object*
{
if (val) {
return native_true();
}
return native_false();
}
auto native_bool_to_object(bool val) -> const object*;

struct string_object : hashable_object
{
Expand All @@ -140,6 +135,8 @@ struct string_object : hashable_object
{
}

[[nodiscard]] auto is_truthy() const -> bool override { return !value.empty(); }

[[nodiscard]] auto type() const -> object_type override { return object_type::string; }

[[nodiscard]] auto inspect() const -> std::string override { return fmt::format(R"("{}")", value); }
Expand Down Expand Up @@ -201,6 +198,8 @@ struct array_object : object
{
}

[[nodiscard]] auto is_truthy() const -> bool override { return !elements.empty(); }

[[nodiscard]] auto type() const -> object_type override { return object_type::array; }

[[nodiscard]] auto inspect() const -> std::string override;
Expand Down Expand Up @@ -230,6 +229,8 @@ struct hash_object : object
{
}

[[nodiscard]] auto is_truthy() const -> bool override { return !pairs.empty(); }

[[nodiscard]] auto type() const -> object_type override { return object_type::hash; }

[[nodiscard]] auto inspect() const -> std::string override;
Expand Down
14 changes: 5 additions & 9 deletions source/vm/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,15 +281,7 @@ auto vm::exec_bang() -> void
{
using enum object::object_type;
const auto* operand = pop();
if (operand->is(boolean)) {
push(native_bool_to_object(!operand->as<boolean_object>()->value));
return;
}
if (operand->is(null)) {
push(native_true());
return;
}
push(native_false());
push(native_bool_to_object(!operand->is_truthy()));
}

auto vm::exec_minus() -> void
Expand Down Expand Up @@ -647,8 +639,12 @@ TEST_CASE("booleanExpressions")
vt<bool> {R"(("a" > "b") == false)", true},
vt<bool> {R"(!true)", false},
vt<bool> {R"(!false)", true},
vt<bool> {R"(!!"")", false},
vt<bool> {R"(!"a")", false},
vt<bool> {R"(!!"a")", true},
vt<bool> {R"(!0)", true},
vt<bool> {R"(![])", true},
vt<bool> {R"(!{})", true},
vt<bool> {R"(!5)", false},
vt<bool> {R"(!!true)", true},
vt<bool> {R"(!!false)", false},
Expand Down

0 comments on commit 80d300a

Please sign in to comment.