feat: add function parsing
This commit is contained in:
parent
17e5021fd8
commit
d7ee0e3bb2
@ -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;
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ namespace ppc::data {
|
||||
|
||||
};
|
||||
|
||||
static const value_t null{};
|
||||
|
||||
class map_t {
|
||||
private:
|
||||
|
@ -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'...
|
||||
|
@ -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<token_t> &tokens) {
|
||||
ast_ctx_t ctx(messages, tokens);
|
||||
|
@ -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");
|
||||
};
|
||||
|
@ -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;
|
||||
|
101
src/compiler/treeifier/ast/parsers/func.cc
Normal file
101
src/compiler/treeifier/ast/parsers/func.cc
Normal file
@ -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());
|
||||
};
|
@ -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());
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user