Better operator resolution mechanism

This commit is contained in:
Robert Bendun 2022-05-16 15:51:38 +02:00
parent ccd2166231
commit 0b9e7e8f4a
4 changed files with 43 additions and 20 deletions

View File

@ -71,6 +71,7 @@ std::ostream& operator<<(std::ostream& os, Error const& err)
case errors::Function_Not_Defined:
case errors::Unexpected_Token_Type:
case errors::Unresolved_Operator:
return os << err.message << '\n';
case errors::Unexpected_Empty_Source:
@ -153,6 +154,15 @@ Error errors::function_not_defined(Value const& value)
return err;
}
Error errors::unresolved_operator(Token const& op)
{
Error err;
err.type = errors::Unresolved_Operator;
err.location = op.location;
err.message = format("Unresolved operator '", op.source, "'");
return err;
}
void errors::all_tokens_were_not_parsed(std::span<Token> tokens)
{
error_heading(std::cerr, std::nullopt, Error_Level::Bug);

View File

@ -2,6 +2,19 @@
#include <iostream>
static auto numeric_binary_operator(auto binop)
{
return [binop = std::move(binop)](std::vector<Value> args) {
auto result = std::move(args.front());
for (auto &v : std::span(args).subspan(1)) {
assert(result.type == Value::Type::Number, "LHS should be a number");
assert(v.type == Value::Type::Number, "RHS should be a number");
result.n = binop(std::move(result.n), v.n);
}
return result;
};
}
Interpreter::Interpreter()
: Interpreter(std::cout)
{
@ -20,7 +33,7 @@ Interpreter::Interpreter(std::ostream& out)
unreachable();
};
functions["say"] = [&](std::vector<Value> args) -> Value {
functions["say"] = [&out](std::vector<Value> args) -> Value {
for (auto it = args.begin(); it != args.end(); ++it) {
out << *it;
if (std::next(it) != args.end())
@ -29,6 +42,11 @@ Interpreter::Interpreter(std::ostream& out)
out << '\n';
return {};
};
operators["+"] = numeric_binary_operator(std::plus<>{});
operators["-"] = numeric_binary_operator(std::minus<>{});
operators["*"] = numeric_binary_operator(std::multiplies<>{});
operators["/"] = numeric_binary_operator(std::divides<>{});
}
Result<Value> Interpreter::eval(Ast &&ast)
@ -41,28 +59,18 @@ Result<Value> Interpreter::eval(Ast &&ast)
{
std::vector<Value> values;
values.reserve(ast.arguments.size());
auto op = operators.find(std::string(ast.token.source));
if (op == operators.end()) {
return errors::unresolved_operator(ast.token);
}
for (auto& a : ast.arguments) {
values.push_back(Try(eval(std::move(a))));
}
Value result = values.front();
if (ast.token.source == "+") {
for (auto &v : std::span(values).subspan(1)) {
assert(result.type == Value::Type::Number, "LHS of + should be a number");
assert(v.type == Value::Type::Number, "RHS of + should be a number");
result.n += v.n;
}
return result;
} else if (ast.token.source == "*") {
for (auto &v : std::span(values).subspan(1)) {
assert(result.type == Value::Type::Number, "LHS of * should be a number");
assert(v.type == Value::Type::Number, "RHS of * should be a number");
result.n *= v.n;
}
return result;
}
unimplemented();
return op->second(std::move(values));
}
break;

View File

@ -45,7 +45,8 @@ namespace errors
Unexpected_Empty_Source,
Failed_Numeric_Parsing,
Function_Not_Defined
Function_Not_Defined,
Unresolved_Operator
};
}
@ -416,6 +417,7 @@ struct Interpreter
{
std::ostream &out;
std::unordered_map<std::string, Function> functions;
std::unordered_map<std::string, Function> operators;
Interpreter();
Interpreter(std::ostream& out);
@ -437,6 +439,7 @@ namespace errors
Error failed_numeric_parsing(Location location, std::errc errc, std::string_view source);
Error function_not_defined(Value const& v);
Error unresolved_operator(Token const& op);
[[noreturn]]
void all_tokens_were_not_parsed(std::span<Token>);

View File

@ -46,6 +46,8 @@ suite intepreter_test = [] {
should("evaluate arithmetic") = [] {
evaluates_to(Value::number(Number(10)), "5 + 3 + 2");
evaluates_to(Value::number(Number(25)), "5 * (3 + 2)");
evaluates_to(Value::number(Number(1, 2)), "1 / 2");
evaluates_to(Value::number(Number(-10)), "10 - 20");
};
should("call builtin functions") = [] {