diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 557b618..09a1c67 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -5,8 +5,6 @@ #include "furc/ast/statement.hpp" #include "furc/front/token.hpp" -#include - namespace furc { namespace ast { @@ -45,27 +43,14 @@ protected: front::token m_name; }; -struct function_body { - location begin, end; - std::vector> statements; - - bool operator==(const function_body& rhs) const { - return begin == rhs.begin && end == rhs.end && statements == rhs.statements; - } - - bool operator!=(const function_body& rhs) const { return !this->operator==(rhs); } -}; - -using function_body_h = handle; - class function_definition_node : public function_declaration_node { public: - function_definition_node(front::token name, function_body_h&& body) + function_definition_node(front::token name, body_h&& body) : function_declaration_node(name), m_body(std::move(body)) {} public: declaration_node_t declaration_type() const override { return declaration_node_t::FunctionDefinition; } - const function_body_h& body() const { return m_body; } + const body_h& body() const { return m_body; } public: void accept(visitor& visitor) const override; @@ -73,7 +58,7 @@ public: protected: bool equal(const node& rhs) const override; private: - function_body_h m_body; + body_h m_body; }; } // namespace ast diff --git a/furc/include/furc/ast/fwd.hpp b/furc/include/furc/ast/fwd.hpp index 81be929..30d767f 100644 --- a/furc/include/furc/ast/fwd.hpp +++ b/furc/include/furc/ast/fwd.hpp @@ -4,6 +4,7 @@ #include "furc/handle.hpp" #include +#include namespace furc { namespace ast { @@ -38,6 +39,21 @@ using binop_expression_node_h = node_handle; class var_assign_expression_node; using var_assign_expression_node_h = node_handle; +struct body { + location begin, end; + std::vector statements; + + bool operator==(const body& rhs) const { + return begin == rhs.begin && end == rhs.end && statements == rhs.statements; + } + + bool operator!=(const body& rhs) const { return !this->operator==(rhs); } + + friend std::ostream& operator<<(std::ostream&, const body&); +}; + +using body_h = handle; + class function_declaration_node; using function_declaration_node_h = node_handle; class function_definition_node; @@ -45,6 +61,8 @@ using function_definition_node_h = node_handle; class return_statement_node; using return_statement_node_h = node_handle; +class if_statement_node; +using if_statement_node_h = node_handle; } // namespace ast } // namespace furc diff --git a/furc/include/furc/ast/statement.hpp b/furc/include/furc/ast/statement.hpp index f9d1092..ebb09ab 100644 --- a/furc/include/furc/ast/statement.hpp +++ b/furc/include/furc/ast/statement.hpp @@ -10,6 +10,7 @@ enum class statement_node_t { Expression, Declaration, Return, + If, }; class statement_node : public node { @@ -25,10 +26,10 @@ class return_statement_node : public statement_node { public: return_statement_node() = default; - return_statement_node(node_handle&& value) + return_statement_node(expression_node_h&& value) : m_value(std::move(value)) {} public: - node_handle value() const { return m_value; } + expression_node_h value() const { return m_value; } public: statement_node_t statement_type() const override { return statement_node_t::Return; } public: @@ -38,7 +39,32 @@ public: protected: bool equal(const node& rhs) const override; private: - node_handle m_value; + expression_node_h m_value; +}; + +class if_statement_node : public statement_node { +public: + if_statement_node(expression_node_h&& cond, statement_node_h&& then) + : m_cond(std::move(cond)), m_then(std::move(then)) {} + + if_statement_node(expression_node_h&& cond, statement_node_h&& then, statement_node_h&& elze) + : m_cond(std::move(cond)), m_then(std::move(then)), m_else(std::move(elze)) {} +public: + expression_node_h cond() const { return m_cond; } + const statement_node_h& then() const { return m_then; } + const statement_node_h& elze() const { return m_else; } +public: + statement_node_t statement_type() const override { return statement_node_t::If; } +public: + void accept(visitor& visitor) const override; + + std::ostream& print(std::ostream& os) const override; +protected: + bool equal(const node& rhs) const override; +private: + expression_node_h m_cond; + statement_node_h m_then; + statement_node_h m_else; }; } // namespace ast diff --git a/furc/include/furc/ast/visitor.hpp b/furc/include/furc/ast/visitor.hpp index 8123c0f..67dbb0d 100644 --- a/furc/include/furc/ast/visitor.hpp +++ b/furc/include/furc/ast/visitor.hpp @@ -25,6 +25,7 @@ public: virtual void visit_function_declaration_node(const function_declaration_node&) {} virtual void visit_function_definition_node(const function_definition_node&) {} virtual void visit_return_statement_node(const return_statement_node&) {} + virtual void visit_if_statement_node(const if_statement_node&) {} virtual void visit_error(const node_handle& handle) {} }; diff --git a/furc/include/furc/front/ir_generator.hpp b/furc/include/furc/front/ir_generator.hpp index ac959c5..472cb08 100644 --- a/furc/include/furc/front/ir_generator.hpp +++ b/furc/include/furc/front/ir_generator.hpp @@ -17,13 +17,14 @@ public: ir_generator(ir_generator&&) = default; ir_generator& operator=(ir_generator&&) = default; - ir_generator(const ir_generator&) = default; - ir_generator& operator=(const ir_generator&) = default; + ir_generator(const ir_generator&) = delete; + ir_generator& operator=(const ir_generator&) = delete; public: furlang::ir::module&& move_module() { return std::move(m_module); } public: void visit_function_definition_node(const ast::function_definition_node& funcDef) override; void visit_return_statement_node(const ast::return_statement_node& returnStmt) override; + void visit_if_statement_node(const ast::if_statement_node& node) override; void visit_string_literal_node(const ast::string_literal_node& node) override; void visit_integer_literal_node(const ast::integer_literal_node& node) override; void visit_var_read_expression_node(const ast::var_read_expression_node& node) override; @@ -31,9 +32,12 @@ public: void visit_binop_expression_node(const ast::binop_expression_node& node) override; void visit_var_assign_expression_node(const ast::var_assign_expression_node& node) override; private: - furlang::ir::module m_module; - std::shared_ptr m_currentBlock; - std::uint32_t m_registerCounter = 0; + furlang::ir::block_index push_block(); +private: + furlang::ir::module m_module; + std::unique_ptr m_currentFunction; + std::shared_ptr m_currentBlock; + std::uint32_t m_registerCounter = 0; std::unordered_map m_variableMap; }; diff --git a/furc/include/furc/front/parser.hpp b/furc/include/furc/front/parser.hpp index 83987a9..0e60a96 100644 --- a/furc/include/furc/front/parser.hpp +++ b/furc/include/furc/front/parser.hpp @@ -36,7 +36,7 @@ private: ast::expression_node_h parse_expression_unary(std::uint32_t precedence); ast::expression_node_h parse_expression_rhs(ast::expression_node_h&& init, std::uint32_t precedence); - ast::function_body_h parse_body(); + ast::body_h parse_body(); private: token_handle<> next_token(); const token_handle<>& peek_token(); diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index 3cf2f8b..b94354d 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -134,6 +134,8 @@ enum class keyword_token { None, Func, Return, + If, + Else, }; static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) { @@ -141,7 +143,10 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) case keyword_token::None: return os << "none"; case keyword_token::Func: return os << "func"; case keyword_token::Return: return os << "return"; + case keyword_token::If: return os << "if"; + case keyword_token::Else: return os << "else"; } + return os; } static inline std::string operator+(const std::string& str, keyword_token keyword) { @@ -149,7 +154,10 @@ static inline std::string operator+(const std::string& str, keyword_token keywor case keyword_token::None: return str + "none"; case keyword_token::Func: return str + "func"; case keyword_token::Return: return str + "return"; + case keyword_token::If: return str + "if"; + case keyword_token::Else: return str + "else"; } + return str; } using integer_token = std::uint64_t; diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index d6a656f..631f4aa 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -188,6 +188,22 @@ bool return_statement_node::equal(const node& rhs) const { return statement_node::equal(rhs) && m_value == reinterpret_cast(rhs).m_value; } +void if_statement_node::accept(visitor& visitor) const { + visitor.visit_if_statement_node(*this); +} + +std::ostream& if_statement_node::print(std::ostream& os) const { + os << "if " << *m_cond << ", then:\n"; + os << m_then; + if (m_else.present()) os << m_else; + return os; +} + +bool if_statement_node::equal(const node& rhsNode) const { + const auto& rhs = reinterpret_cast(rhsNode); + return statement_node::equal(rhs) && m_cond == rhs.m_cond && m_then == rhs.m_then && m_else == rhs.m_else; +} + void program_node::accept(visitor& visitor) const { for (const auto& decl : m_declarations) { if (decl.has_error()) { @@ -210,4 +226,12 @@ bool program_node::equal(const node& rhs) const { return m_declarations == reinterpret_cast(rhs).m_declarations; } +std::ostream& operator<<(std::ostream& os, const body& body) { + os << "body:"; + for (const auto& stmt : body.statements) { + os << '\n' << stmt; + } + return os; +} + } // namespace furc::ast \ No newline at end of file diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp index e470a34..788028b 100644 --- a/furc/src/front/ir_generator.cpp +++ b/furc/src/front/ir_generator.cpp @@ -14,9 +14,9 @@ namespace ir = furlang::ir; } void ir_generator::visit_function_definition_node(const ast::function_definition_node& funcDef) { - auto func = std::make_unique(std::string(funcDef.name()->string)); + m_currentFunction = std::make_unique(std::string(funcDef.name()->string)); - m_currentBlock = func->push(); + push_block(); if (funcDef.body().has_error()) { std::cerr << funcDef.body().error() << '\n'; return; @@ -25,7 +25,7 @@ void ir_generator::visit_function_definition_node(const ast::function_definition stmt->accept(*this); } - m_module.push(std::move(func)); + m_module.push(std::move(m_currentFunction)); } void ir_generator::visit_return_statement_node(const ast::return_statement_node& returnStmt) { @@ -41,6 +41,25 @@ void ir_generator::visit_return_statement_node(const ast::return_statement_node& } } +void ir_generator::visit_if_statement_node(const ast::if_statement_node& node) { + node.cond()->accept(*this); + std::uint32_t cond = m_registerCounter - 1; + m_currentBlock->emplace(ir::operand::new_reg(cond), + m_currentFunction->blocks().size(), + m_currentFunction->blocks().size() + 1); + + push_block(); // then block + node.then()->accept(*this); + if (node.elze().present()) { + m_currentBlock->emplace(m_currentFunction->blocks().size() + 1); + + push_block(); // else block + node.elze()->accept(*this); + } + + push_block(); +} + void ir_generator::visit_string_literal_node(const ast::string_literal_node& node) { m_currentBlock->emplace(ir::operand::new_string(std::string(*node.value())), ir::operand::new_reg(m_registerCounter++)); @@ -93,4 +112,10 @@ void ir_generator::visit_var_assign_expression_node(const ast::var_assign_expres throw std::runtime_error("unimplemented"); } +furlang::ir::block_index ir_generator::push_block() { + ir::block_index index = m_currentFunction->blocks().size(); + m_currentBlock = m_currentFunction->push(); + return index; +} + } // namespace furc::front \ No newline at end of file diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index c09c59a..d6c6f8b 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -90,6 +90,8 @@ token_handle<> lexer::next_token() { static std::unordered_map s_keywords = { { "func", keyword_token::Func }, { "return", keyword_token::Return }, + { "if", keyword_token::If }, + { "else", keyword_token::Else }, }; if (auto it = s_keywords.find(value); it != s_keywords.end()) return { location, it->second, value }; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index cd69149..278b06e 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -1,6 +1,6 @@ #include "furc/front/parser.hpp" -#include "furc/ast/declaration.hpp" +// #include "furc/ast/declaration.hpp" // IWYU pragma: keep #include #include @@ -55,7 +55,7 @@ ast::declaration_node_h parser::parse_declaration() { if (peek.has_error()) return peek; switch (peek->type) { case token_t::Lbrace: { - ast::function_body_h body = parse_body(); + ast::body_h body = parse_body(); if (body.has_error()) return body; return ast::function_definition_node_h{ first.location(), m_arena, *name, std::move(body) }; } @@ -91,16 +91,49 @@ ast::statement_node_h parser::parse_statement() { if (tok.has_error()) return tok; switch (tok->type) { case token_t::Keyword: { - auto tok = next_token(); - if (peek_token()->type == token_t::Semicolon) { - next_token(); - return ast::return_statement_node_h{ tok.location(), m_arena }; - } + switch (tok->value.keyword) { + case keyword_token::Return: { + auto tok = next_token(); + if (peek_token()->type == token_t::Semicolon) { + next_token(); + return ast::return_statement_node_h{ tok.location(), m_arena }; + } - auto value = parse_expression(); - auto err = eat_token(token_t::Semicolon); - if (err.has_error()) return err; - return ast::return_statement_node_h{ tok.location(), m_arena, std::move(value) }; + auto value = parse_expression(); + auto err = eat_token(token_t::Semicolon); + if (err.has_error()) return err; + return ast::return_statement_node_h{ tok.location(), m_arena, std::move(value) }; + } + case keyword_token::If: { + auto tok = next_token(); + auto err = eat_token(token_t::Lparen); + if (err.has_error()) return err; + + auto cond = parse_expression(); + + err = eat_token(token_t::Rparen); + if (err.has_error()) return err; + + auto then = parse_statement(); + if (then.has_error()) return then; + + if (peek_token().present() && peek_token()->type == token_t::Keyword && + peek_token()->value.keyword == keyword_token::Else) { + next_token(); + + return ast::if_statement_node_h{ tok.location(), + m_arena, + std::move(cond), + std::move(then), + std::move(parse_statement()) }; + } + + return ast::if_statement_node_h{ tok.location(), m_arena, std::move(cond), std::move(then) }; + } + case keyword_token::None: + case keyword_token::Func: + default: break; + } } default: break; } @@ -328,8 +361,8 @@ ast::expression_node_h parser::parse_expression_rhs(ast::expression_node_h&& ini return lhs; } -ast::function_body_h parser::parse_body() { - ast::function_body body; +ast::body_h parser::parse_body() { + ast::body body; token_handle<> begin = eat_token(token_t::Lbrace); if (begin.has_error()) return begin; diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 42a9b43..019c904 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -6,7 +6,7 @@ #include int main(void) { - furc::front::parser parser("", "func main() {\n return 7 + 6 * 10;\n}"); + furc::front::parser parser("", "func main() {\n if (1) return 7 + 6 * 10; else return 0;\n}"); furc::front::ir_generator generator; auto program = parser.parse();