Add var assign expression
Signed-off-by: CHatingPython <chatingpython@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@ namespace ast {
|
||||
enum class expression_node_t {
|
||||
Literal,
|
||||
VarRead,
|
||||
VarAssign,
|
||||
Unaryop,
|
||||
Binop,
|
||||
Paren,
|
||||
@@ -81,6 +82,7 @@ private:
|
||||
using unaryop_expression_node_h = node_handle<unaryop_expression_node>;
|
||||
|
||||
enum class binop_expression_node_t {
|
||||
None = 0,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
@@ -114,6 +116,31 @@ private:
|
||||
|
||||
using binop_expression_node_h = node_handle<binop_expression_node>;
|
||||
|
||||
class var_assign_expression_node : public expression_node {
|
||||
public:
|
||||
var_assign_expression_node(expression_node_h&& lhs, expression_node_h&& rhs)
|
||||
: m_compound(binop_expression_node_t::None), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
|
||||
|
||||
var_assign_expression_node(binop_expression_node_t compound, expression_node_h&& lhs, expression_node_h&& rhs)
|
||||
: m_compound(compound), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
|
||||
|
||||
binop_expression_node_t compound() const { return m_compound; }
|
||||
const expression_node_h& lhs() const { return m_lhs; }
|
||||
const expression_node_h& rhs() const { return m_rhs; }
|
||||
public:
|
||||
expression_node_t expression_type() const override { return expression_node_t::VarAssign; }
|
||||
|
||||
std::ostream& print(std::ostream& os) const override;
|
||||
protected:
|
||||
bool equal(const node& rhs) const override;
|
||||
private:
|
||||
binop_expression_node_t m_compound;
|
||||
expression_node_h m_lhs;
|
||||
expression_node_h m_rhs;
|
||||
};
|
||||
|
||||
using var_assign_expression_node_h = node_handle<var_assign_expression_node>;
|
||||
|
||||
} // namespace ast
|
||||
} // namespace furc
|
||||
|
||||
|
||||
@@ -34,6 +34,13 @@ enum class token_t {
|
||||
Percent,
|
||||
DPlus,
|
||||
DMinus,
|
||||
|
||||
Eq,
|
||||
PlusEq,
|
||||
MinusEq,
|
||||
StarEq,
|
||||
SlashEq,
|
||||
PercentEq,
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
||||
@@ -60,6 +67,12 @@ static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
||||
case token_t::Percent: return os << "'%'";
|
||||
case token_t::DPlus: return os << "++";
|
||||
case token_t::DMinus: return os << "--";
|
||||
case token_t::Eq: return os << "=";
|
||||
case token_t::PlusEq: return os << "+=";
|
||||
case token_t::MinusEq: return os << "-=";
|
||||
case token_t::StarEq: return os << "*=";
|
||||
case token_t::SlashEq: return os << "/=";
|
||||
case token_t::PercentEq: return os << "%=";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
@@ -88,6 +101,12 @@ static inline std::string operator+(const std::string& str, token_t type) {
|
||||
case token_t::Percent: return str + "'%'";
|
||||
case token_t::DPlus: return str + "++";
|
||||
case token_t::DMinus: return str + "--";
|
||||
case token_t::Eq: return str + "=";
|
||||
case token_t::PlusEq: return str + "+=";
|
||||
case token_t::MinusEq: return str + "-=";
|
||||
case token_t::StarEq: return str + "*=";
|
||||
case token_t::SlashEq: return str + "/=";
|
||||
case token_t::PercentEq: return str + "%=";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -158,24 +177,7 @@ struct token {
|
||||
case token_t::String: return value.string == rhs.value.string;
|
||||
case token_t::Keyword: return value.keyword == rhs.value.keyword;
|
||||
case token_t::Integer: return value.integer == rhs.value.integer;
|
||||
case token_t::None:
|
||||
case token_t::Lparen:
|
||||
case token_t::Rparen:
|
||||
case token_t::Lbrace:
|
||||
case token_t::Rbrace:
|
||||
case token_t::Lbracket:
|
||||
case token_t::Rbracket:
|
||||
case token_t::Semicolon:
|
||||
case token_t::Colon:
|
||||
case token_t::Comma:
|
||||
case token_t::Dot:
|
||||
case token_t::Plus:
|
||||
case token_t::Minus:
|
||||
case token_t::Star:
|
||||
case token_t::Slash:
|
||||
case token_t::Percent:
|
||||
case token_t::DPlus:
|
||||
case token_t::DMinus: return true;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,6 +75,8 @@ bool unaryop_expression_node::equal(const node& rhsNode) const {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case binop_expression_node_t::None: return os;
|
||||
case binop_expression_node_t::Add: return os << '+';
|
||||
case binop_expression_node_t::Sub: return os << '-';
|
||||
case binop_expression_node_t::Mul: return os << '*';
|
||||
@@ -84,6 +86,7 @@ std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) {
|
||||
}
|
||||
|
||||
std::ostream& binop_expression_node::print(std::ostream& os) const {
|
||||
if (m_type == binop_expression_node_t::None) return os;
|
||||
return os << '(' << *m_lhs << ' ' << m_type << ' ' << *m_rhs << ')';
|
||||
}
|
||||
|
||||
@@ -92,6 +95,15 @@ bool binop_expression_node::equal(const node& rhsNode) const {
|
||||
return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_lhs == rhs.m_lhs && m_rhs == rhs.m_rhs;
|
||||
}
|
||||
|
||||
std::ostream& var_assign_expression_node::print(std::ostream& os) const {
|
||||
return os << *m_lhs << " = " << *m_rhs;
|
||||
}
|
||||
|
||||
bool var_assign_expression_node::equal(const node& rhsNode) const {
|
||||
const auto& rhs = reinterpret_cast<const var_assign_expression_node&>(rhsNode);
|
||||
return expression_node::equal(rhsNode) && m_compound == rhs.m_compound && m_lhs == rhs.m_lhs && m_rhs == rhs.m_rhs;
|
||||
}
|
||||
|
||||
bool declaration_node::equal(const node& rhs) const {
|
||||
return declaration_type() == reinterpret_cast<const declaration_node&>(rhs).declaration_type();
|
||||
}
|
||||
|
||||
@@ -121,6 +121,12 @@ token_handle<> lexer::next_token() {
|
||||
{ "%", token_t::Percent },
|
||||
{ "++", token_t::DPlus },
|
||||
{ "--", token_t::DMinus },
|
||||
{ "=", token_t::Eq },
|
||||
{ "+=", token_t::PlusEq },
|
||||
{ "-=", token_t::MinusEq },
|
||||
{ "*=", token_t::StarEq },
|
||||
{ "/=", token_t::SlashEq },
|
||||
{ "%=", token_t::PercentEq },
|
||||
};
|
||||
|
||||
token_t type = token_t::None;
|
||||
|
||||
+39
-10
@@ -212,6 +212,7 @@ enum class associativity {
|
||||
enum class rhsop_info_t {
|
||||
Unaryop,
|
||||
Binop,
|
||||
Assignment,
|
||||
};
|
||||
|
||||
struct rhsop_info {
|
||||
@@ -221,6 +222,7 @@ struct rhsop_info {
|
||||
union {
|
||||
ast::unaryop_expression_node_t unary;
|
||||
ast::binop_expression_node_t binary;
|
||||
ast::binop_expression_node_t assignment;
|
||||
};
|
||||
|
||||
static rhsop_info create(ast::unaryop_expression_node_t type, std::uint32_t precedence) {
|
||||
@@ -242,6 +244,15 @@ struct rhsop_info {
|
||||
info.binary = type;
|
||||
return info;
|
||||
}
|
||||
|
||||
static rhsop_info create(ast::binop_expression_node_t compound = ast::binop_expression_node_t::None) {
|
||||
rhsop_info info{};
|
||||
info.type = rhsop_info_t::Assignment;
|
||||
info.precedence = 14;
|
||||
info.associativity = associativity::Right;
|
||||
info.assignment = compound;
|
||||
return info;
|
||||
}
|
||||
};
|
||||
|
||||
ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& init, std::uint32_t precedence) {
|
||||
@@ -253,6 +264,13 @@ ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& ini
|
||||
{ token_t::Percent, rhsop_info::create(ast::binop_expression_node_t::Mod, 5, associativity::Left) },
|
||||
{ token_t::DPlus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixIncrement, 1) },
|
||||
{ token_t::DMinus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixDecrement, 1) },
|
||||
{ token_t::DMinus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixDecrement, 1) },
|
||||
{ token_t::Eq, rhsop_info::create() },
|
||||
{ token_t::PlusEq, rhsop_info::create(ast::binop_expression_node_t::Add) },
|
||||
{ token_t::MinusEq, rhsop_info::create(ast::binop_expression_node_t::Sub) },
|
||||
{ token_t::StarEq, rhsop_info::create(ast::binop_expression_node_t::Mul) },
|
||||
{ token_t::SlashEq, rhsop_info::create(ast::binop_expression_node_t::Div) },
|
||||
{ token_t::PercentEq, rhsop_info::create(ast::binop_expression_node_t::Mod) },
|
||||
};
|
||||
|
||||
ast::expression_node_h lhs = std::move(init);
|
||||
@@ -265,7 +283,7 @@ ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& ini
|
||||
auto opToken = next_token();
|
||||
|
||||
ast::expression_node_h rhs;
|
||||
if (current.type == rhsop_info_t::Binop) {
|
||||
if (current.type != rhsop_info_t::Unaryop) {
|
||||
rhs = parse_expression_unary(current.precedence + 1); // unary prefix is always right-associative
|
||||
}
|
||||
|
||||
@@ -273,7 +291,7 @@ ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& ini
|
||||
if (nextIt != s_rhsops.end()) {
|
||||
rhsop_info next = nextIt->second;
|
||||
|
||||
if (current.type == rhsop_info_t::Binop) {
|
||||
if (current.type != rhsop_info_t::Unaryop) {
|
||||
rhs = std::move(parse_expression_rhs(std::move(rhs),
|
||||
current.precedence + static_cast<std::uint32_t>(current.associativity == associativity::Right)));
|
||||
} else {
|
||||
@@ -281,14 +299,25 @@ ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& ini
|
||||
}
|
||||
}
|
||||
|
||||
lhs = current.type == rhsop_info_t::Binop
|
||||
? ast::expression_node_h(ast::binop_expression_node_h{ opToken.location(),
|
||||
m_arena,
|
||||
current.binary,
|
||||
std::move(lhs),
|
||||
std::move(rhs) })
|
||||
: ast::expression_node_h(
|
||||
ast::unaryop_expression_node_h{ opToken.location(), m_arena, current.unary, std::move(lhs) });
|
||||
switch (current.type) {
|
||||
case rhsop_info_t::Unaryop:
|
||||
lhs = ast::unaryop_expression_node_h{ opToken.location(), m_arena, current.unary, std::move(lhs) };
|
||||
break;
|
||||
case rhsop_info_t::Binop:
|
||||
lhs = ast::binop_expression_node_h{ opToken.location(),
|
||||
m_arena,
|
||||
current.binary,
|
||||
std::move(lhs),
|
||||
std::move(rhs) };
|
||||
break;
|
||||
case rhsop_info_t::Assignment:
|
||||
lhs = ast::var_assign_expression_node_h{ opToken.location(),
|
||||
m_arena,
|
||||
current.assignment,
|
||||
std::move(lhs),
|
||||
std::move(rhs) };
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
@@ -213,4 +213,62 @@ TEST(Parser, Paren) {
|
||||
EXPECT_VARREAD(inc->get_node(), "x");
|
||||
}
|
||||
|
||||
TEST(Parser, Assignment) {
|
||||
parser parser("<TEMP>", "func main() { x = 10; }");
|
||||
auto program = parser.parse();
|
||||
EXPECT_TRUE(program.present());
|
||||
EXPECT_EQ(program->declarations().size(), 1);
|
||||
auto func = program->declarations()[0];
|
||||
EXPECT_TRUE(func.present());
|
||||
EXPECT_EQ(func->declaration_type(), declaration_node_t::FunctionDefinition);
|
||||
function_definition_node_h funcDef = func;
|
||||
EXPECT_EQ(funcDef->name()->string, "main");
|
||||
EXPECT_EQ(funcDef->body()->statements.size(), 1);
|
||||
|
||||
EXPECT_EQ(funcDef->body()->statements[0]->statement_type(), statement_node_t::Expression);
|
||||
expression_node_h expr = funcDef->body()->statements[0];
|
||||
|
||||
EXPECT_EQ(expr->expression_type(), expression_node_t::VarAssign);
|
||||
var_assign_expression_node_h assign = expr;
|
||||
EXPECT_EQ(assign->compound(), binop_expression_node_t::None);
|
||||
|
||||
expression_node_h lhs = assign->lhs();
|
||||
EXPECT_EQ(lhs->expression_type(), expression_node_t::VarRead);
|
||||
var_read_expression_node_h varRead = lhs;
|
||||
EXPECT_EQ(varRead->get_name(), "x");
|
||||
|
||||
expression_node_h rhs = assign->rhs();
|
||||
EXPECT_EQ(rhs->expression_type(), expression_node_t::Literal);
|
||||
EXPECT_INTLIT(rhs, 10);
|
||||
}
|
||||
|
||||
TEST(Parser, CompoundAssignment) {
|
||||
parser parser("<TEMP>", "func main() { x += 10; }");
|
||||
auto program = parser.parse();
|
||||
EXPECT_TRUE(program.present());
|
||||
EXPECT_EQ(program->declarations().size(), 1);
|
||||
auto func = program->declarations()[0];
|
||||
EXPECT_TRUE(func.present());
|
||||
EXPECT_EQ(func->declaration_type(), declaration_node_t::FunctionDefinition);
|
||||
function_definition_node_h funcDef = func;
|
||||
EXPECT_EQ(funcDef->name()->string, "main");
|
||||
EXPECT_EQ(funcDef->body()->statements.size(), 1);
|
||||
|
||||
EXPECT_EQ(funcDef->body()->statements[0]->statement_type(), statement_node_t::Expression);
|
||||
expression_node_h expr = funcDef->body()->statements[0];
|
||||
|
||||
EXPECT_EQ(expr->expression_type(), expression_node_t::VarAssign);
|
||||
var_assign_expression_node_h assign = expr;
|
||||
EXPECT_EQ(assign->compound(), binop_expression_node_t::Add);
|
||||
|
||||
expression_node_h lhs = assign->lhs();
|
||||
EXPECT_EQ(lhs->expression_type(), expression_node_t::VarRead);
|
||||
var_read_expression_node_h varRead = lhs;
|
||||
EXPECT_EQ(varRead->get_name(), "x");
|
||||
|
||||
expression_node_h rhs = assign->rhs();
|
||||
EXPECT_EQ(rhs->expression_type(), expression_node_t::Literal);
|
||||
EXPECT_INTLIT(rhs, 10);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user