furc #24
@@ -4,8 +4,10 @@
|
||||
#include "furc/ast/node.hpp"
|
||||
#include "furc/ast/statement.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace furc {
|
||||
namespace ast {
|
||||
@@ -69,6 +71,20 @@ protected:
|
||||
bool equal(const node& rhs) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parameter of function declaration AST node.
|
||||
*/
|
||||
struct function_declaration_param {
|
||||
std::string name;
|
||||
type type;
|
||||
};
|
||||
|
||||
enum class function_declaration_node_t {
|
||||
Normal = 0,
|
||||
Import,
|
||||
Native,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function declaration AST node.
|
||||
*/
|
||||
@@ -79,10 +95,19 @@ public:
|
||||
*
|
||||
* @param location Node location.
|
||||
* @param name Name of the function.
|
||||
* @param type Return type of the function.
|
||||
*/
|
||||
template <typename T>
|
||||
function_declaration_node(struct location location, T&& name)
|
||||
: declaration_node(location), p_name(std::forward<T>(name)) {}
|
||||
template <typename T, typename ParamsFwd>
|
||||
function_declaration_node(struct location location,
|
||||
T&& name,
|
||||
std::optional<type>&& returnType,
|
||||
ParamsFwd&& params,
|
||||
function_declaration_node_t type = function_declaration_node_t::Normal)
|
||||
: declaration_node(location),
|
||||
p_name(std::forward<T>(name)),
|
||||
p_returnType(std::move(returnType)),
|
||||
p_params(std::forward<ParamsFwd>(params)),
|
||||
p_type(type) {}
|
||||
public:
|
||||
/**
|
||||
* @brief Returns this node's declaration type.
|
||||
@@ -97,6 +122,27 @@ public:
|
||||
* @return Name of the function.
|
||||
*/
|
||||
std::string name() const { return p_name; }
|
||||
|
||||
/**
|
||||
* @brief Returns function's return type.
|
||||
*
|
||||
* @return Function's return type.
|
||||
*/
|
||||
const std::optional<type>& return_type() const { return p_returnType; }
|
||||
|
||||
/**
|
||||
* @brief Returns function's parameters.
|
||||
*
|
||||
* @return Function's parameters.
|
||||
*/
|
||||
const std::vector<function_declaration_param>& params() const { return p_params; }
|
||||
|
||||
/**
|
||||
* @brief Returns function's type.
|
||||
*
|
||||
* @return Function's type.
|
||||
*/
|
||||
function_declaration_node_t type() const { return p_type; }
|
||||
public:
|
||||
void accept(visitor& visitor) const override;
|
||||
|
||||
@@ -108,6 +154,21 @@ protected:
|
||||
* @brief Name of the function.
|
||||
*/
|
||||
std::string p_name;
|
||||
|
||||
/**
|
||||
* @brief Return type of the function.
|
||||
*/
|
||||
std::optional<class type> p_returnType;
|
||||
|
||||
/**
|
||||
* @brief Parameters of the function.
|
||||
*/
|
||||
std::vector<function_declaration_param> p_params;
|
||||
|
||||
/**
|
||||
* @brief Type of the function declaration.
|
||||
*/
|
||||
function_declaration_node_t p_type;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -120,11 +181,17 @@ public:
|
||||
*
|
||||
* @param location Node location.
|
||||
* @param name Name of the function.
|
||||
* @param type Return type of the function.
|
||||
* @param body Body of the function.
|
||||
*/
|
||||
template <typename T>
|
||||
function_definition_node(struct location location, T&& name, body&& body)
|
||||
: function_declaration_node(location, std::forward<T>(name)), m_body(std::move(body)) {}
|
||||
template <typename T, typename ParamsFwd>
|
||||
function_definition_node(struct location location,
|
||||
T&& name,
|
||||
std::optional<class type>&& type,
|
||||
ParamsFwd&& params,
|
||||
body&& body)
|
||||
: function_declaration_node(location, std::forward<T>(name), std::move(type), std::forward<ParamsFwd>(params)),
|
||||
m_body(std::move(body)) {}
|
||||
public:
|
||||
/**
|
||||
* @brief Returns this node's declaration type.
|
||||
|
||||
@@ -54,6 +54,9 @@ enum class token_t {
|
||||
GreaterThan, /**< `>` */
|
||||
LessEq, /**< `<=` */
|
||||
GreaterEq, /**< `>=` */
|
||||
|
||||
SlimArrow, /**< `->` */
|
||||
FatArrow, /**< `=>` */
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
||||
@@ -92,6 +95,8 @@ static inline std::ostream& operator<<(std::ostream& os, token_t type) {
|
||||
case token_t::GreaterThan: return os << ">";
|
||||
case token_t::LessEq: return os << "<=";
|
||||
case token_t::GreaterEq: return os << ">=";
|
||||
case token_t::SlimArrow: return os << "->";
|
||||
case token_t::FatArrow: return os << "=>";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
@@ -132,6 +137,8 @@ static inline std::string operator+(const std::string& str, token_t type) {
|
||||
case token_t::GreaterThan: return str + ">";
|
||||
case token_t::LessEq: return str + "<=";
|
||||
case token_t::GreaterEq: return str + ">=";
|
||||
case token_t::SlimArrow: return str + "->";
|
||||
case token_t::FatArrow: return str + "=>";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -146,6 +153,8 @@ enum class keyword_token {
|
||||
If, /**< `if` */
|
||||
Else, /**< `else` */
|
||||
While, /**< `while` */
|
||||
Import, /**< `import` */
|
||||
Native, /**< `native` */
|
||||
|
||||
Int32, /**< `int32` */
|
||||
};
|
||||
@@ -158,6 +167,8 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword)
|
||||
case keyword_token::If: return os << "if";
|
||||
case keyword_token::Else: return os << "else";
|
||||
case keyword_token::While: return os << "while";
|
||||
case keyword_token::Import: return os << "import";
|
||||
case keyword_token::Native: return os << "native";
|
||||
case keyword_token::Int32: return os << "int32";
|
||||
}
|
||||
return os;
|
||||
@@ -171,6 +182,8 @@ static inline std::string operator+(const std::string& str, keyword_token keywor
|
||||
case keyword_token::If: return str + "if";
|
||||
case keyword_token::Else: return str + "else";
|
||||
case keyword_token::While: return str + "while";
|
||||
case keyword_token::Import: return str + "import";
|
||||
case keyword_token::Native: return str + "native";
|
||||
case keyword_token::Int32: return str + "int32";
|
||||
}
|
||||
return str;
|
||||
|
||||
@@ -100,6 +100,8 @@ token_r lexer::next_token() {
|
||||
{ "if", keyword_token::If },
|
||||
{ "else", keyword_token::Else },
|
||||
{ "while", keyword_token::While },
|
||||
{ "import", keyword_token::Import },
|
||||
{ "native", keyword_token::Native },
|
||||
{ "int32", keyword_token::Int32 },
|
||||
};
|
||||
|
||||
@@ -144,6 +146,8 @@ token_r lexer::next_token() {
|
||||
{ ">", token_t::GreaterThan },
|
||||
{ "<=", token_t::LessEq },
|
||||
{ ">=", token_t::GreaterEq },
|
||||
{ "->", token_t::SlimArrow },
|
||||
{ "=>", token_t::FatArrow },
|
||||
};
|
||||
|
||||
token_t type = token_t::None;
|
||||
|
||||
+55
-11
@@ -12,6 +12,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace furc::front {
|
||||
|
||||
@@ -37,14 +38,11 @@ ast::program_node_r parser::parse() & {
|
||||
|
||||
while (peek_token().has_value()) {
|
||||
auto decl = parse_declaration();
|
||||
if (decl.has_error()) {
|
||||
program = nullptr;
|
||||
} else if (program != nullptr) {
|
||||
program->push(std::move(decl.value()));
|
||||
}
|
||||
if (decl.has_error()) return ast::program_node_r(ast::error{ decl.error().location });
|
||||
program->push(std::move(decl.value()));
|
||||
}
|
||||
|
||||
return program != nullptr ? std::move(program) : ast::program_node_r(ast::error{ location{ m_filename } });
|
||||
return program;
|
||||
}
|
||||
|
||||
ast::type_r parser::parse_type() {
|
||||
@@ -58,30 +56,77 @@ ast::declaration_node_r parser::parse_declaration() {
|
||||
const auto& first = peek_token();
|
||||
switch (first->type) {
|
||||
case token_t::Keyword: {
|
||||
ast::function_declaration_node_t funcDeclType{};
|
||||
|
||||
auto first = next_token();
|
||||
switch ((*first)->keyword) {
|
||||
case keyword_token::Import:
|
||||
case keyword_token::Native: {
|
||||
funcDeclType = ((*first)->keyword == keyword_token::Import) ? ast::function_declaration_node_t::Import
|
||||
: ast::function_declaration_node_t::Native;
|
||||
|
||||
first = eat_token(token_t::Keyword);
|
||||
if (first.has_error()) return ast::declaration_node_r(ast::error{ first.error().location });
|
||||
if (first->value.keyword != keyword_token::Func)
|
||||
return ast::declaration_node_r(ast::error{ first->location });
|
||||
}
|
||||
case keyword_token::Func: {
|
||||
auto name = eat_token(token_t::Identifier);
|
||||
if (name.has_error()) return ast::declaration_node_r(ast::error{ name.error().location });
|
||||
|
||||
auto tok = eat_token(token_t::LParen);
|
||||
if (tok.has_error()) return ast::declaration_node_r(ast::error{ tok.error().location });
|
||||
|
||||
std::vector<ast::function_declaration_param> params;
|
||||
if (peek_token().has_value() && peek_token()->type != token_t::RParen) {
|
||||
while (true) {
|
||||
auto name = eat_token(token_t::Identifier);
|
||||
if (name.has_error()) return ast::declaration_node_r(ast::error{ name.error().location });
|
||||
auto colon = eat_token(token_t::Colon);
|
||||
if (colon.has_error()) return ast::declaration_node_r(ast::error{ colon.error().location });
|
||||
auto type = parse_type();
|
||||
if (type.has_error()) return ast::declaration_node_r(ast::error{ type.error().location });
|
||||
|
||||
params.push_back(
|
||||
ast::function_declaration_param{ std::string(name->value.string), std::move(*type) });
|
||||
|
||||
auto comma = eat_token(token_t::Comma);
|
||||
if (comma.has_error()) break;
|
||||
}
|
||||
}
|
||||
|
||||
tok = eat_token(token_t::RParen);
|
||||
if (tok.has_error()) return ast::declaration_node_r(ast::error{ tok.error().location });
|
||||
|
||||
std::optional<ast::type> returnType;
|
||||
if (peek_token().has_value() && peek_token()->type == token_t::SlimArrow) {
|
||||
auto tok = next_token();
|
||||
auto type = parse_type();
|
||||
if (type.has_error()) return ast::declaration_node_r(ast::error{ tok->location });
|
||||
returnType = *type;
|
||||
}
|
||||
|
||||
const auto& peek = peek_token();
|
||||
if (peek.has_error()) return ast::declaration_node_r(ast::error{ peek.error().location });
|
||||
switch (peek->type) {
|
||||
case token_t::LBrace: {
|
||||
ast::body_r body = parse_body();
|
||||
if (body.has_error()) return ast::declaration_node_r(ast::error{ body.error().location });
|
||||
if (funcDeclType != ast::function_declaration_node_t::Normal)
|
||||
return ast::declaration_node_r(ast::error{ body->begin });
|
||||
return m_arena->allocate_shared<ast::function_definition_node>(first->location,
|
||||
name->value.string,
|
||||
std::move(returnType),
|
||||
std::move(params),
|
||||
std::move(body.value()));
|
||||
}
|
||||
case token_t::Semicolon: {
|
||||
m_peekBuffer.clear();
|
||||
return m_arena->allocate_shared<ast::function_declaration_node>(first->location, name->value.string);
|
||||
return m_arena->allocate_shared<ast::function_declaration_node>(first->location,
|
||||
name->value.string,
|
||||
std::move(returnType),
|
||||
std::move(params),
|
||||
funcDeclType);
|
||||
}
|
||||
default: return ast::declaration_node_r(ast::error{ tok->location });
|
||||
}
|
||||
@@ -454,15 +499,14 @@ const token_r& parser::peek_token() {
|
||||
}
|
||||
|
||||
token_r parser::eat_token(token_t type) {
|
||||
auto token = next_token();
|
||||
if (token.has_error()) return token;
|
||||
if (token->type != type) {
|
||||
if (const auto& token = peek_token(); token.has_error() || peek_token()->type != type) {
|
||||
if (token.has_error()) return token;
|
||||
if (token->type == token_t::None)
|
||||
return token_r(token_error{ token->location, token_error_t::UnexpectedToken, ", expected " + type });
|
||||
return token_r(
|
||||
token_error{ token->location, token_error_t::UnexpectedToken, ""s + token->type + ", expected " + type });
|
||||
}
|
||||
return token;
|
||||
return next_token();
|
||||
}
|
||||
|
||||
} // namespace furc::front
|
||||
|
||||
+3
-1
@@ -13,7 +13,9 @@
|
||||
int main(void) {
|
||||
try {
|
||||
std::string programStr = R"(
|
||||
func main() {
|
||||
native func print(value: int32);
|
||||
|
||||
func main() -> int32 {
|
||||
x = 0;
|
||||
y = 10;
|
||||
z = 1;
|
||||
|
||||
Reference in New Issue
Block a user