implemented infix operator parsing
This commit is contained in:
@@ -4,6 +4,13 @@
|
|||||||
|
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
|
infix_expr::infix_expr(
|
||||||
|
token::token token, std::string op, ast::expression* left
|
||||||
|
)
|
||||||
|
: token(std::move(token)),
|
||||||
|
op(op),
|
||||||
|
left(left) {}
|
||||||
|
|
||||||
std::string infix_expr::token_literal() const {
|
std::string infix_expr::token_literal() const {
|
||||||
return token.literal;
|
return token.literal;
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
namespace ast {
|
namespace ast {
|
||||||
struct infix_expr : expression {
|
struct infix_expr : expression {
|
||||||
|
infix_expr(token::token, std::string, ast::expression*);
|
||||||
token::token token;
|
token::token token;
|
||||||
expression* left;
|
expression* left;
|
||||||
std::string op;
|
std::string op;
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "ast/errors/error.hpp"
|
#include "ast/errors/error.hpp"
|
||||||
#include "ast/expressions/identifier.hpp"
|
#include "ast/expressions/identifier.hpp"
|
||||||
|
#include "ast/expressions/infix.hpp"
|
||||||
#include "ast/expressions/integer.hpp"
|
#include "ast/expressions/integer.hpp"
|
||||||
#include "ast/expressions/prefix.hpp"
|
#include "ast/expressions/prefix.hpp"
|
||||||
#include "token/token.hpp"
|
#include "token/token.hpp"
|
||||||
@@ -36,6 +37,40 @@ namespace parser {
|
|||||||
token::type::MINUS,
|
token::type::MINUS,
|
||||||
std::bind(&parser::parse_prefix_expr, this)
|
std::bind(&parser::parse_prefix_expr, this)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
register_infix(
|
||||||
|
token::type::PLUS,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::MINUS,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::ASTERISK,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::SLASH,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::EQ,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::NEQ,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::GT,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
|
register_infix(
|
||||||
|
token::type::LT,
|
||||||
|
std::bind(&parser::parse_infix_expr, this, _1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parser::next_token() {
|
void parser::next_token() {
|
||||||
@@ -72,15 +107,27 @@ namespace parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::expression* parser::parse_expression(precedence) {
|
ast::expression* parser::parse_expression(precedence prec) {
|
||||||
auto it = prefix_parse_fns.find(current.type);
|
auto prefix_it = prefix_parse_fns.find(current.type);
|
||||||
if (it == prefix_parse_fns.end()) {
|
if (prefix_it == prefix_parse_fns.end()) {
|
||||||
unkown_prefix_error(current);
|
unkown_prefix_error(current);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix_parse_fn func = it->second;
|
prefix_parse_fn prefix = prefix_it->second;
|
||||||
return func();
|
ast::expression* left = prefix();
|
||||||
|
|
||||||
|
while (next.type != token::type::SEMICOLON
|
||||||
|
&& prec < precedence_for(next.type)) {
|
||||||
|
auto infix_it = infix_parse_fns.find(next.type);
|
||||||
|
if (infix_it == infix_parse_fns.end())
|
||||||
|
return left;
|
||||||
|
next_token();
|
||||||
|
|
||||||
|
infix_parse_fn infix = infix_it->second;
|
||||||
|
left = infix(left);
|
||||||
|
}
|
||||||
|
return left;
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::return_stmt* parser::parse_return() {
|
ast::return_stmt* parser::parse_return() {
|
||||||
@@ -178,4 +225,13 @@ namespace parser {
|
|||||||
ret->right = parse_expression(precedence::PREFIX);
|
ret->right = parse_expression(precedence::PREFIX);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ast::expression* parser::parse_infix_expr(ast::expression* left) {
|
||||||
|
ast::infix_expr* ret =
|
||||||
|
new ast::infix_expr(current, current.literal, left);
|
||||||
|
precedence prec = precedence_for(current.type);
|
||||||
|
next_token();
|
||||||
|
ret->right = parse_expression(prec);
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
} // namespace parser
|
} // namespace parser
|
||||||
|
@@ -49,5 +49,7 @@ namespace parser {
|
|||||||
ast::expression* parse_identifier();
|
ast::expression* parse_identifier();
|
||||||
ast::expression* parse_integer();
|
ast::expression* parse_integer();
|
||||||
ast::expression* parse_prefix_expr();
|
ast::expression* parse_prefix_expr();
|
||||||
|
|
||||||
|
ast::expression* parse_infix_expr(ast::expression*);
|
||||||
};
|
};
|
||||||
} // namespace parser
|
} // namespace parser
|
||||||
|
22
src/parser/precedence.cpp
Normal file
22
src/parser/precedence.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include "precedence.hpp"
|
||||||
|
|
||||||
|
namespace parser {
|
||||||
|
precedence precedence_for(token::type type) {
|
||||||
|
switch (type) {
|
||||||
|
case token::type::EQ:
|
||||||
|
case token::type::NEQ:
|
||||||
|
return precedence::EQUALS;
|
||||||
|
case token::type::LT:
|
||||||
|
case token::type::GT:
|
||||||
|
return precedence::LESS_GREATER;
|
||||||
|
case token::type::PLUS:
|
||||||
|
case token::type::MINUS:
|
||||||
|
return precedence::SUM;
|
||||||
|
case token::type::ASTERISK:
|
||||||
|
case token::type::SLASH:
|
||||||
|
return precedence::PRODUCT;
|
||||||
|
default:
|
||||||
|
return precedence::LOWEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace parser
|
@@ -1,3 +1,7 @@
|
|||||||
|
#include "token/type.hpp"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace parser {
|
namespace parser {
|
||||||
enum class precedence {
|
enum class precedence {
|
||||||
LOWEST,
|
LOWEST,
|
||||||
@@ -8,4 +12,10 @@ namespace parser {
|
|||||||
PREFIX,
|
PREFIX,
|
||||||
CALL
|
CALL
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
precedence precedence_for(token::type);
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, precedence& p) {
|
||||||
|
return os << static_cast<int>(p);
|
||||||
|
}
|
||||||
|
} // namespace parser
|
||||||
|
51
test/parser/precedence.cpp
Normal file
51
test/parser/precedence.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "parser/parser.hpp"
|
||||||
|
|
||||||
|
#include <doctest.h>
|
||||||
|
|
||||||
|
TEST_SUITE("Precedence") {
|
||||||
|
TEST_CASE("Raw precedence") {
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::EQUALS);
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::LESS_GREATER);
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::SUM);
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::PRODUCT);
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::PREFIX);
|
||||||
|
CHECK(parser::precedence::LOWEST < parser::precedence::CALL);
|
||||||
|
|
||||||
|
CHECK(parser::precedence::EQUALS < parser::precedence::LESS_GREATER);
|
||||||
|
CHECK(parser::precedence::EQUALS < parser::precedence::SUM);
|
||||||
|
CHECK(parser::precedence::EQUALS < parser::precedence::PRODUCT);
|
||||||
|
CHECK(parser::precedence::EQUALS < parser::precedence::PREFIX);
|
||||||
|
CHECK(parser::precedence::EQUALS < parser::precedence::CALL);
|
||||||
|
|
||||||
|
CHECK(parser::precedence::LESS_GREATER < parser::precedence::SUM);
|
||||||
|
CHECK(parser::precedence::LESS_GREATER < parser::precedence::PRODUCT);
|
||||||
|
CHECK(parser::precedence::LESS_GREATER < parser::precedence::PREFIX);
|
||||||
|
CHECK(parser::precedence::LESS_GREATER < parser::precedence::CALL);
|
||||||
|
|
||||||
|
CHECK(parser::precedence::SUM < parser::precedence::PRODUCT);
|
||||||
|
CHECK(parser::precedence::SUM < parser::precedence::PREFIX);
|
||||||
|
CHECK(parser::precedence::SUM < parser::precedence::CALL);
|
||||||
|
|
||||||
|
CHECK(parser::precedence::PRODUCT < parser::precedence::PREFIX);
|
||||||
|
CHECK(parser::precedence::PRODUCT < parser::precedence::CALL);
|
||||||
|
|
||||||
|
CHECK(parser::precedence::PREFIX < parser::precedence::CALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Operator precedence") {
|
||||||
|
auto& prec = parser::precedence_for;
|
||||||
|
CHECK(prec(token::type::EQ) == prec(token::type::NEQ));
|
||||||
|
CHECK(prec(token::type::LT) == prec(token::type::GT));
|
||||||
|
CHECK(prec(token::type::PLUS) == prec(token::type::MINUS));
|
||||||
|
CHECK(prec(token::type::ASTERISK) == prec(token::type::SLASH));
|
||||||
|
|
||||||
|
CHECK(prec(token::type::EQ) < prec(token::type::LT));
|
||||||
|
CHECK(prec(token::type::EQ) < prec(token::type::PLUS));
|
||||||
|
CHECK(prec(token::type::EQ) < prec(token::type::ASTERISK));
|
||||||
|
|
||||||
|
CHECK(prec(token::type::LT) < prec(token::type::PLUS));
|
||||||
|
CHECK(prec(token::type::LT) < prec(token::type::ASTERISK));
|
||||||
|
|
||||||
|
CHECK(prec(token::type::PLUS) < prec(token::type::ASTERISK));
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user