From d7ee0e3bb2b7ee30d41ba68ea470781dee4d0856 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sat, 22 Oct 2022 15:19:05 +0300 Subject: [PATCH] feat: add function parsing --- include/compiler/treeifier/ast.hh | 4 +- include/utils/data.hh | 1 + scripts/common.mak | 6 +- src/compiler/treeifier/ast.cc | 22 +++-- src/compiler/treeifier/ast/parsers/exp.cc | 18 +++- src/compiler/treeifier/ast/parsers/field.cc | 2 - src/compiler/treeifier/ast/parsers/func.cc | 101 ++++++++++++++++++++ src/compiler/treeifier/ast/parsers/glob.cc | 15 ++- 8 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 src/compiler/treeifier/ast/parsers/func.cc diff --git a/include/compiler/treeifier/ast.hh b/include/compiler/treeifier/ast.hh index 6842d6d..b83f24d 100644 --- a/include/compiler/treeifier/ast.hh +++ b/include/compiler/treeifier/ast.hh @@ -27,6 +27,7 @@ namespace ppc::comp::tree::ast { extern const parser_adder_t type_adder; extern const parser_adder_t exp_adder; extern const parser_adder_t field_adder; + extern const parser_adder_t func_adder; extern const parser_adder_t var_adder; struct ast_ctx_t { @@ -43,6 +44,7 @@ namespace ppc::comp::tree::ast { private: ast_ctx_t *parent; public: + group_parser_t &operator[](const std::string &name); group_parser_t &operator[](const std::string &name) const; group_proxy_t(ast_ctx_t *parent): parent(parent) { } }; @@ -58,7 +60,6 @@ namespace ppc::comp::tree::ast { void add_parser(const parser_t *parser); void add_parser(const parser_t *parser, const std::string &group); void add_parser(const parser_t *parser, const std::string &group, const namespace_name_t &name); - void add_group(const std::string &name); void add_parser(parser_adder_t factory) { factory(*this); } @@ -75,6 +76,7 @@ namespace ppc::comp::tree::ast { add_parser(exp_adder); add_parser(var_adder); add_parser(field_adder); + add_parser(func_adder); return *this; } diff --git a/include/utils/data.hh b/include/utils/data.hh index 9dd385b..0001345 100644 --- a/include/utils/data.hh +++ b/include/utils/data.hh @@ -73,6 +73,7 @@ namespace ppc::data { }; + static const value_t null{}; class map_t { private: diff --git a/scripts/common.mak b/scripts/common.mak index 626748c..c9091f3 100644 --- a/scripts/common.mak +++ b/scripts/common.mak @@ -43,16 +43,16 @@ build: $(binary) .SECONDEXPANSION: $(binary): $$(call frdeps,$(mainmodule)) $$(call binaries,$(mainmodule)) $(call mkdir,$(dir $@)) - echo Compiling executable '$(notdir $(binary))'... $(CXX) $(flags) $(call binaries,$(mainmodule)) -o $@ $(ldflags) $(call ldeps,$(mainmodule)) -L$(bin) "-I$(inc)" + echo Compiling executable '$(notdir $(binary))'... .SECONDEXPANSION: $(bin)/lib$(lib)%$(so): $$(call frdeps,$$*) $$(call binaries,$$*) $(call mkdir,$(bin)) - echo Compiling library '$(notdir $@)'... $(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)" + echo Compiling library '$(notdir $@)'... $(bin)/tmp/%.o: $(src)/%.cc $(headers) - echo - Compiling '$*.cc'... $(call mkdir,$(dir $@)) $(CXX) -fPIC -c $(flags) $< -o $@ + echo - Compiling '$*.cc'... diff --git a/src/compiler/treeifier/ast.cc b/src/compiler/treeifier/ast.cc index e0e66b8..aea1723 100644 --- a/src/compiler/treeifier/ast.cc +++ b/src/compiler/treeifier/ast.cc @@ -9,9 +9,19 @@ namespace ppc::comp::tree::ast { return *it->second; } group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const { - auto p = (group_parser_t*)&parent->parser[name]; - if (parent->groups.find(p) == parent->groups.end()) throw "A parser '" + name + "' exists, but isn't a group."; - return *p; + auto it = parent->parsers.find(name); + if (it == parent->parsers.end()) { + auto p = new group_parser_t(name); + parent->parsers[name] = p; + parent->groups.emplace(p); + return *p; + } + else if (parent->groups.find((group_parser_t*)it->second) == parent->groups.end()) { + throw "A parser '" + name + "' exists, but isn't a group."s; + } + else { + return *(group_parser_t*)it->second; + } } ast_ctx_t::~ast_ctx_t() { @@ -32,12 +42,6 @@ namespace ppc::comp::tree::ast { add_parser(parser); this->group[group].add(*parser, name); } - void ast_ctx_t::add_group(const std::string &name) { - auto parser = new group_parser_t(name); - if (parsers.find(parser->name()) != parsers.end()) throw "The parser '" + parser->name() + "' already exists."; - parsers[parser->name()] = parser; - groups.emplace(parser); - } data::map_t ast_ctx_t::parse(msg_stack_t &messages, std::vector &tokens) { ast_ctx_t ctx(messages, tokens); diff --git a/src/compiler/treeifier/ast/parsers/exp.cc b/src/compiler/treeifier/ast/parsers/exp.cc index d93310b..f4ed46e 100644 --- a/src/compiler/treeifier/ast/parsers/exp.cc +++ b/src/compiler/treeifier/ast/parsers/exp.cc @@ -282,4 +282,20 @@ class exp_parser_t : public parser_t { public: exp_parser_t(): parser_t("$_exp") { } }; -const parser_adder_t ppc::comp::tree::ast::exp_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new exp_parser_t()); }; +class exp_stat_parser_t : public parser_t { + bool parse(ast_ctx_t &ctx, size_t &i, map_t &res) const { + tree_helper_t h(ctx, i); + if (!h.parse("$_exp", res)) return false; + if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); + + ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1))); + return h.submit(false); + } + + public: exp_stat_parser_t() : parser_t("$_exp_stat") { } +}; + +const parser_adder_t ppc::comp::tree::ast::exp_adder = [](ast_ctx_t &ctx) { + ctx.add_parser(new exp_parser_t()); + ctx.add_parser(new exp_stat_parser_t(), "$_stat"); +}; diff --git a/src/compiler/treeifier/ast/parsers/field.cc b/src/compiler/treeifier/ast/parsers/field.cc index 072e186..631faac 100644 --- a/src/compiler/treeifier/ast/parsers/field.cc +++ b/src/compiler/treeifier/ast/parsers/field.cc @@ -18,8 +18,6 @@ class field_parser_t : public parser_t { type = true; } if (h.curr().is_operator(operator_t::ASSIGN)) { - h.i++; - h.err("Default values are not yet supported.", 1); h.advance(); h.force_parse("$_exp", "Expected an expression.", out["value"].map({})); type = true; diff --git a/src/compiler/treeifier/ast/parsers/func.cc b/src/compiler/treeifier/ast/parsers/func.cc new file mode 100644 index 0000000..1380ce3 --- /dev/null +++ b/src/compiler/treeifier/ast/parsers/func.cc @@ -0,0 +1,101 @@ +#include "compiler/treeifier/ast/helper.hh" + +class arg_parser_t : public parser_t { + bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { + tree_helper_t h(ctx, res_i); + + if (h.ended()) return false; + + if (!h.parse("$_identifier", out["name"].map({}))) return false; + + bool type, defval; + + h.throw_ended("Expected a colon or an equals sign."); + + if (h.curr().is_operator(operator_t::COLON)) { + h.advance(); + h.force_parse("$_type", "Expected a type.", out["type"].map({})); + type = true; + } + if (h.curr().is_operator(operator_t::ASSIGN)) { + h.advance(); + h.force_parse("$_exp", "Expected an expression.", out["value"].map({})); + type = true; + } + + if (!type && !defval) { + ctx.messages.push(message_t::error("Expected a type or a default value.", h.loc(1))); + } + + return h.submit(false); + } + + public: arg_parser_t(): parser_t("$_func_arg") {} +}; + +class func_parser_t : public parser_t { + bool parse(ast_ctx_t &ctx, size_t &res_i, map_t &out) const { + tree_helper_t h(ctx, res_i); + + if (h.ended()) return false; + + if (!h.parse("$_identifier", out["name"].map({}))) return false; + if (h.ended()) return false; + if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false; + h.advance("Expected a closing paren or a parameter."); + + auto ¶ms = out["params"].array({}); + auto &content = out["content"].array({}); + + while (true) { + if (h.curr().is_operator(operator_t::PAREN_CLOSE)) { + h.advance("Expected a function body."); + break; + } + h.force_push_parse("$_func_arg", "Expected a parameter.", params); + if (h.curr().is_operator(operator_t::COMMA)) { + h.advance("Expected a parameter."); + } + } + + if (h.curr().is_operator(operator_t::COLON)) { + h.advance("Expected a type."); + h.force_parse("$_type", "Expected a type", out["type"].map({})); + } + + if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true); + else if (h.curr().is_operator(operator_t::LAMBDA)) { + h.advance("Expected an expression."); + map_t exp; + h.force_parse("$_exp", "Expected an expression.", exp); + content.push_back({ + { "$_name", "$_return" }, + { "content", exp }, + }); + return h.submit(false); + } + else if (h.curr().is_operator(operator_t::BRACE_OPEN)) { + h.advance("Expected a statement."); + while (true) { + if (h.curr().is_operator(operator_t::BRACE_CLOSE)) { + return h.submit(true); + } + + h.force_push_parse("$_stat", "Expected an expression.", content); + } + } + else { + ctx.messages.push(message_t::error("Expected a semicolon, brace open or a lambda operator.", h.loc(1))); + return h.submit(false); + } + + return h.submit(true); + } + + public: func_parser_t(): parser_t("$_func") { } +}; + +const parser_adder_t ppc::comp::tree::ast::func_adder = [](ast_ctx_t &ctx) { + ctx.add_parser(new func_parser_t(), "$_def"); + ctx.add_parser(new arg_parser_t()); +}; diff --git a/src/compiler/treeifier/ast/parsers/glob.cc b/src/compiler/treeifier/ast/parsers/glob.cc index ead5048..f8ec95c 100644 --- a/src/compiler/treeifier/ast/parsers/glob.cc +++ b/src/compiler/treeifier/ast/parsers/glob.cc @@ -18,7 +18,7 @@ class nmsp_def_parser_t : public parser_t { return h.submit(true); } - public: nmsp_def_parser_t(): parser_t("$_nmsp_def") { } + public: nmsp_def_parser_t(): parser_t("$_nmsp") { } }; class import_parser_t : public parser_t { bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const { @@ -46,15 +46,16 @@ class glob_parser_t : public parser_t { bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const { tree_helper_t h(ctx, res_i); - return h.parse("$_exp", out); - if (h.ended()) return true; - if (nmsp_def_parser(ctx, h.i, (out["namespace"] = map_t()).map())) { + if (nmsp_def_parser(ctx, h.i, out["namespace"].map({}))) { ctx.nmsp = conv::map_to_nmsp(out["namespace"].map()); } + else { + out["namespace"] = data::null; + } - auto &imports = (out["imports"] = array_t()).array(); - auto &contents = (out["content"] = array_t()).array(); + auto &imports = out["imports"].array({}); + auto &contents = out["content"].array({}); while (true) { map_t map; @@ -83,7 +84,5 @@ public: }; const parser_adder_t ppc::comp::tree::ast::glob_adder = [](ast_ctx_t &ctx) { - ctx.add_group("$_def"); - ctx.add_group("$_exp_val"); ctx.add_parser(new glob_parser_t()); };