forked from KPGPMC/furlang
+2
-1
@@ -26,7 +26,8 @@ Checks: >
|
|||||||
-cppcoreguidelines-avoid-c-arrays,
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||||
-cppcoreguidelines-macro-usage,
|
-cppcoreguidelines-macro-usage,
|
||||||
-cppcoreguidelines-owning-memory
|
-cppcoreguidelines-owning-memory,
|
||||||
|
-cppcoreguidelines-non-private-member-variables-in-classes
|
||||||
|
|
||||||
WarningsAsErrors: "*"
|
WarningsAsErrors: "*"
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ namespace furc {
|
|||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
enum class declaration_node_t {
|
enum class declaration_node_t {
|
||||||
Function,
|
FunctionDeclaration,
|
||||||
|
FunctionDefinition,
|
||||||
Variable,
|
Variable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::ostream& operator<<(std::ostream& os, declaration_node_t type) {
|
static inline std::ostream& operator<<(std::ostream& os, declaration_node_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case declaration_node_t::Function: return os << "function";
|
case declaration_node_t::FunctionDeclaration: return os << "function declaration";
|
||||||
|
case declaration_node_t::FunctionDefinition: return os << "function definition";
|
||||||
case declaration_node_t::Variable: return os << "variable";
|
case declaration_node_t::Variable: return os << "variable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +32,7 @@ public:
|
|||||||
virtual std::ostream& print(std::ostream& os) const = 0;
|
virtual std::ostream& print(std::ostream& os) const = 0;
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const declaration_node& node) {
|
friend std::ostream& operator<<(std::ostream& os, const declaration_node& node) {
|
||||||
os << node.type() << " declaration";
|
os << node.type();
|
||||||
return node.print(os);
|
return node.print(os);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -46,15 +48,28 @@ class function_declarartion_node : public declaration_node {
|
|||||||
public:
|
public:
|
||||||
function_declarartion_node(front::token name)
|
function_declarartion_node(front::token name)
|
||||||
: m_name(name) {}
|
: m_name(name) {}
|
||||||
|
|
||||||
function_declarartion_node(front::token name, function_body&& body)
|
|
||||||
: m_name(name), m_body(std::move(body)) {}
|
|
||||||
public:
|
public:
|
||||||
declaration_node_t type() const override { return declaration_node_t::Function; }
|
declaration_node_t type() const override { return declaration_node_t::FunctionDeclaration; }
|
||||||
|
|
||||||
|
front::token name() const { return m_name; }
|
||||||
|
public:
|
||||||
|
std::ostream& print(std::ostream& os) const override { return os << ": " << m_name; }
|
||||||
|
protected:
|
||||||
|
front::token m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class function_definition_node : public function_declarartion_node {
|
||||||
|
public:
|
||||||
|
function_definition_node(front::token name, function_body_handle&& body)
|
||||||
|
: function_declarartion_node(name), m_body(std::move(body)) {}
|
||||||
|
public:
|
||||||
|
declaration_node_t type() const override { return declaration_node_t::FunctionDefinition; }
|
||||||
|
|
||||||
|
const function_body_handle& body() const { return m_body; }
|
||||||
public:
|
public:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
os << ": " << m_name;
|
os << ": " << m_name.value;
|
||||||
if (m_body.has_value()) {
|
if (m_body.present()) {
|
||||||
os << '\n' << m_body->begin << ": begin:";
|
os << '\n' << m_body->begin << ": begin:";
|
||||||
for (const auto& entry : m_body->statements) {
|
for (const auto& entry : m_body->statements) {
|
||||||
os << '\n' << entry;
|
os << '\n' << entry;
|
||||||
@@ -65,7 +80,7 @@ public:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
front::token m_name;
|
front::token m_name;
|
||||||
std::optional<function_body> m_body;
|
function_body_handle m_body;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
|||||||
@@ -115,6 +115,10 @@ public:
|
|||||||
handle(location location, std::shared_ptr<U> value)
|
handle(location location, std::shared_ptr<U> value)
|
||||||
: m_location(location), m_value(value) {}
|
: m_location(location), m_value(value) {}
|
||||||
|
|
||||||
|
template <typename U, typename = std::enable_if_t<std::is_base_of_v<U, value_type>>>
|
||||||
|
handle(const handle<U*, Error>& other)
|
||||||
|
: m_location(other.m_location), m_value(std::dynamic_pointer_cast<value_type>(other.m_value)) {}
|
||||||
|
|
||||||
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<value_type, Args...>>>
|
template <typename... Args, typename = std::enable_if_t<std::is_constructible_v<value_type, Args...>>>
|
||||||
handle(location location, Args&&... args)
|
handle(location location, Args&&... args)
|
||||||
: m_location(location), m_value(std::make_shared<value_type>(std::forward<Args>(args)...)) {}
|
: m_location(location), m_value(std::make_shared<value_type>(std::forward<Args>(args)...)) {}
|
||||||
@@ -133,7 +137,8 @@ public:
|
|||||||
other.m_value = nullptr;
|
other.m_value = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U = value_type, typename = std::enable_if_t<std::is_base_of_v<value_type, U>>>
|
template <typename U = value_type,
|
||||||
|
typename = std::enable_if_t<std::is_base_of_v<value_type, U> || std::is_base_of_v<U, value_type>>>
|
||||||
handle(handle<U*, Error>&& other) noexcept // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
handle(handle<U*, Error>&& other) noexcept // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||||
: m_location(other.m_location), m_value(std::move(other.m_value)), m_error(std::move(other.m_error)) {
|
: m_location(other.m_location), m_value(std::move(other.m_value)), m_error(std::move(other.m_error)) {
|
||||||
other.m_value = nullptr;
|
other.m_value = nullptr;
|
||||||
@@ -172,8 +177,8 @@ public:
|
|||||||
|
|
||||||
reference operator*() { return *m_value; }
|
reference operator*() { return *m_value; }
|
||||||
const_reference operator*() const { return *m_value; }
|
const_reference operator*() const { return *m_value; }
|
||||||
pointer operator->() { return m_value; }
|
pointer operator->() { return m_value.get(); }
|
||||||
const_pointer operator->() const { return m_value; }
|
const_pointer operator->() const { return m_value.get(); }
|
||||||
public:
|
public:
|
||||||
friend std::ostream& operator<<(std::ostream& os, const handle& result) {
|
friend std::ostream& operator<<(std::ostream& os, const handle& result) {
|
||||||
os << result.m_location << ": ";
|
os << result.m_location << ": ";
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ ast::node_handle<ast::declaration_node> parser::parse_declaration() {
|
|||||||
case token_t::Lbrace: {
|
case token_t::Lbrace: {
|
||||||
ast::function_body_handle body = parse_body();
|
ast::function_body_handle body = parse_body();
|
||||||
if (body.error()) return body;
|
if (body.error()) return body;
|
||||||
return ast::node_handle<ast::function_declarartion_node>{ first.location(),
|
return ast::node_handle<ast::function_definition_node>{ first.location(), name, std::move(body) };
|
||||||
name,
|
|
||||||
std::move(body.move()) };
|
|
||||||
}
|
}
|
||||||
case token_t::Semicolon: {
|
case token_t::Semicolon: {
|
||||||
m_peekBuffer.clear();
|
m_peekBuffer.clear();
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#include "furc/front/parser.hpp"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace furc::front;
|
||||||
|
using namespace furc::ast;
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
|
TEST(Parser, EmptyFunctions) {
|
||||||
|
parser parser("<TEMP>", "func main() {}\nfunc foo();");
|
||||||
|
auto program = parser.parse();
|
||||||
|
EXPECT_TRUE(program.present());
|
||||||
|
EXPECT_EQ(program->declarations().size(), 2);
|
||||||
|
{
|
||||||
|
auto first = program->declarations()[0];
|
||||||
|
EXPECT_TRUE(first.present());
|
||||||
|
EXPECT_EQ(first->type(), declaration_node_t::FunctionDefinition);
|
||||||
|
node_handle<function_definition_node> funcDef = first;
|
||||||
|
EXPECT_EQ(funcDef->name().value, "main");
|
||||||
|
EXPECT_EQ(funcDef->body()->statements.size(), 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto second = program->declarations()[1];
|
||||||
|
EXPECT_TRUE(second.present());
|
||||||
|
EXPECT_EQ(second->type(), declaration_node_t::FunctionDeclaration);
|
||||||
|
node_handle<function_declarartion_node> funcDecl = second;
|
||||||
|
EXPECT_EQ(funcDecl->name().value, "foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
Reference in New Issue
Block a user