Overloaded operators
This commit is contained in:
parent
5b3cfca2a8
commit
de1ed62f6b
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
static auto binary_operator(auto binop)
|
constexpr auto binary_operator(auto binop)
|
||||||
{
|
{
|
||||||
return [binop = std::move(binop)](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
return [binop = std::move(binop)](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||||
auto result = std::move(args.front());
|
auto result = std::move(args.front());
|
||||||
@ -20,6 +20,34 @@ static auto binary_operator(auto binop)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr auto equality_operator(auto binop)
|
||||||
|
{
|
||||||
|
return [binop = std::move(binop)](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||||
|
assert(args.size() == 2, "(in)Equality only allows for 2 operands"); // TODO(assert)
|
||||||
|
return Value::boolean(binop(std::move(args.front()), std::move(args.back())));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto comparison_operator(auto binop)
|
||||||
|
{
|
||||||
|
return [binop = std::move(binop)](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
||||||
|
assert(args.size() == 2, "(in)Equality only allows for 2 operands"); // TODO(assert)
|
||||||
|
assert(args.front().type == args.back().type, "Only values of the same type can be ordered"); // TODO(assert)
|
||||||
|
|
||||||
|
switch (args.front().type) {
|
||||||
|
case Value::Type::Number:
|
||||||
|
return Value::boolean(binop(std::move(args.front()).n, std::move(args.back()).n));
|
||||||
|
|
||||||
|
case Value::Type::Bool:
|
||||||
|
return Value::boolean(binop(std::move(args.front()).b, std::move(args.back()).b));
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false, "Cannot compare value of given types"); // TODO(assert)
|
||||||
|
}
|
||||||
|
unreachable();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Interpreter::Interpreter()
|
Interpreter::Interpreter()
|
||||||
: Interpreter(std::cout)
|
: Interpreter(std::cout)
|
||||||
{
|
{
|
||||||
@ -69,12 +97,13 @@ Interpreter::Interpreter(std::ostream& out)
|
|||||||
operators["*"] = binary_operator(std::multiplies<>{});
|
operators["*"] = binary_operator(std::multiplies<>{});
|
||||||
operators["/"] = binary_operator(std::divides<>{});
|
operators["/"] = binary_operator(std::divides<>{});
|
||||||
|
|
||||||
operators["<"] = binary_operator(std::less<>{});
|
operators["<"] = comparison_operator(std::less<>{});
|
||||||
operators[">"] = binary_operator(std::greater<>{});
|
operators[">"] = comparison_operator(std::greater<>{});
|
||||||
operators["<="] = binary_operator(std::less_equal<>{});
|
operators["<="] = comparison_operator(std::less_equal<>{});
|
||||||
operators[">="] = binary_operator(std::greater_equal<>{});
|
operators[">="] = comparison_operator(std::greater_equal<>{});
|
||||||
operators["=="] = binary_operator(std::equal_to<>{});
|
|
||||||
operators["!="] = binary_operator(std::not_equal_to<>{});
|
operators["=="] = equality_operator(std::equal_to<>{});
|
||||||
|
operators["!="] = equality_operator(std::not_equal_to<>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Value> Interpreter::eval(Ast &&ast)
|
Result<Value> Interpreter::eval(Ast &&ast)
|
||||||
@ -161,6 +190,7 @@ Result<Value> Interpreter::eval(Ast &&ast)
|
|||||||
unimplemented();
|
unimplemented();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::enter_scope()
|
void Interpreter::enter_scope()
|
||||||
{
|
{
|
||||||
env = env->enter();
|
env = env->enter();
|
||||||
|
@ -19,7 +19,7 @@ void evaluates_to(Value value, std::string_view source_code, reflection::source_
|
|||||||
capture_errors([=]() -> Result<void> {
|
capture_errors([=]() -> Result<void> {
|
||||||
Interpreter interpreter;
|
Interpreter interpreter;
|
||||||
auto result = Try(interpreter.eval(Try(Parser::parse(source_code, "test"))));
|
auto result = Try(interpreter.eval(Try(Parser::parse(source_code, "test"))));
|
||||||
expect(eq(result, value));
|
expect(eq(result, value), sl);
|
||||||
return {};
|
return {};
|
||||||
}, sl)();
|
}, sl)();
|
||||||
}
|
}
|
||||||
@ -38,9 +38,10 @@ void produces_output(std::string_view source_code, std::string_view expected_out
|
|||||||
suite intepreter_test = [] {
|
suite intepreter_test = [] {
|
||||||
"Interpreter"_test = [] {
|
"Interpreter"_test = [] {
|
||||||
should("evaluate literals") = [] {
|
should("evaluate literals") = [] {
|
||||||
evaluates_to(Value{}, "nil");
|
evaluates_to(Value::boolean(false), "false");
|
||||||
|
evaluates_to(Value::boolean(true), "true");
|
||||||
evaluates_to(Value::number(Number(10)), "10");
|
evaluates_to(Value::number(Number(10)), "10");
|
||||||
// evaluates_to(Value::symbol("notexistingsymbol"), "notexistingsymbol");
|
evaluates_to(Value{}, "nil");
|
||||||
};
|
};
|
||||||
|
|
||||||
should("evaluate arithmetic") = [] {
|
should("evaluate arithmetic") = [] {
|
||||||
@ -60,6 +61,8 @@ suite intepreter_test = [] {
|
|||||||
};
|
};
|
||||||
|
|
||||||
should("allows only for calling which is callable") = [] {
|
should("allows only for calling which is callable") = [] {
|
||||||
|
evaluates_to(Value::number(Number(0)), "[i|i] 0");
|
||||||
|
{
|
||||||
Interpreter i;
|
Interpreter i;
|
||||||
{
|
{
|
||||||
auto result = Parser::parse("10 20", "test").and_then([&](Ast &&ast) { return i.eval(std::move(ast)); });
|
auto result = Parser::parse("10 20", "test").and_then([&](Ast &&ast) { return i.eval(std::move(ast)); });
|
||||||
@ -72,6 +75,34 @@ suite intepreter_test = [] {
|
|||||||
expect(!result.has_value()) << "Expected code to have failed";
|
expect(!result.has_value()) << "Expected code to have failed";
|
||||||
expect(eq(result.error().type, errors::Not_Callable));
|
expect(eq(result.error().type, errors::Not_Callable));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
should("allow for value (in)equality comparisons") = [] {
|
||||||
|
evaluates_to(Value::boolean(true), "nil == nil");
|
||||||
|
evaluates_to(Value::boolean(false), "nil != nil");
|
||||||
|
|
||||||
|
evaluates_to(Value::boolean(true), "true == true");
|
||||||
|
evaluates_to(Value::boolean(false), "true != true");
|
||||||
|
evaluates_to(Value::boolean(false), "true == false");
|
||||||
|
evaluates_to(Value::boolean(true), "true != false");
|
||||||
|
|
||||||
|
evaluates_to(Value::boolean(true), "0 == 0");
|
||||||
|
evaluates_to(Value::boolean(false), "0 != 0");
|
||||||
|
evaluates_to(Value::boolean(true), "1 != 0");
|
||||||
|
evaluates_to(Value::boolean(false), "1 == 0");
|
||||||
|
};
|
||||||
|
|
||||||
|
should("allow for value ordering comparisons") = [] {
|
||||||
|
evaluates_to(Value::boolean(false), "true < true");
|
||||||
|
evaluates_to(Value::boolean(true), "true <= true");
|
||||||
|
evaluates_to(Value::boolean(true), "false < true");
|
||||||
|
evaluates_to(Value::boolean(false), "false > true");
|
||||||
|
|
||||||
|
evaluates_to(Value::boolean(false), "0 < 0");
|
||||||
|
evaluates_to(Value::boolean(true), "0 <= 0");
|
||||||
|
evaluates_to(Value::boolean(true), "1 < 2");
|
||||||
|
evaluates_to(Value::boolean(false), "1 > 2");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Added to explicitly test against bug that was in old implementation of enviroments.
|
// Added to explicitly test against bug that was in old implementation of enviroments.
|
||||||
|
Loading…
Reference in New Issue
Block a user