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 type_adder;
|
||||||
extern const parser_adder_t exp_adder;
|
extern const parser_adder_t exp_adder;
|
||||||
extern const parser_adder_t field_adder;
|
extern const parser_adder_t field_adder;
|
||||||
|
extern const parser_adder_t func_adder;
|
||||||
extern const parser_adder_t var_adder;
|
extern const parser_adder_t var_adder;
|
||||||
|
|
||||||
struct ast_ctx_t {
|
struct ast_ctx_t {
|
||||||
@ -43,6 +44,7 @@ namespace ppc::comp::tree::ast {
|
|||||||
private:
|
private:
|
||||||
ast_ctx_t *parent;
|
ast_ctx_t *parent;
|
||||||
public:
|
public:
|
||||||
|
group_parser_t &operator[](const std::string &name);
|
||||||
group_parser_t &operator[](const std::string &name) const;
|
group_parser_t &operator[](const std::string &name) const;
|
||||||
group_proxy_t(ast_ctx_t *parent): parent(parent) { }
|
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);
|
||||||
void add_parser(const parser_t *parser, const std::string &group);
|
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_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); }
|
void add_parser(parser_adder_t factory) { factory(*this); }
|
||||||
|
|
||||||
@ -75,6 +76,7 @@ namespace ppc::comp::tree::ast {
|
|||||||
add_parser(exp_adder);
|
add_parser(exp_adder);
|
||||||
add_parser(var_adder);
|
add_parser(var_adder);
|
||||||
add_parser(field_adder);
|
add_parser(field_adder);
|
||||||
|
add_parser(func_adder);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ namespace ppc::data {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const value_t null{};
|
||||||
|
|
||||||
class map_t {
|
class map_t {
|
||||||
private:
|
private:
|
||||||
|
@ -43,16 +43,16 @@ build: $(binary)
|
|||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
$(binary): $$(call frdeps,$(mainmodule)) $$(call binaries,$(mainmodule))
|
$(binary): $$(call frdeps,$(mainmodule)) $$(call binaries,$(mainmodule))
|
||||||
$(call mkdir,$(dir $@))
|
$(call mkdir,$(dir $@))
|
||||||
echo Compiling executable '$(notdir $(binary))'...
|
|
||||||
$(CXX) $(flags) $(call binaries,$(mainmodule)) -o $@ $(ldflags) $(call ldeps,$(mainmodule)) -L$(bin) "-I$(inc)"
|
$(CXX) $(flags) $(call binaries,$(mainmodule)) -o $@ $(ldflags) $(call ldeps,$(mainmodule)) -L$(bin) "-I$(inc)"
|
||||||
|
echo Compiling executable '$(notdir $(binary))'...
|
||||||
|
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
$(bin)/lib$(lib)%$(so): $$(call frdeps,$$*) $$(call binaries,$$*)
|
$(bin)/lib$(lib)%$(so): $$(call frdeps,$$*) $$(call binaries,$$*)
|
||||||
$(call mkdir,$(bin))
|
$(call mkdir,$(bin))
|
||||||
echo Compiling library '$(notdir $@)'...
|
|
||||||
$(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)"
|
$(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)"
|
||||||
|
echo Compiling library '$(notdir $@)'...
|
||||||
|
|
||||||
$(bin)/tmp/%.o: $(src)/%.cc $(headers)
|
$(bin)/tmp/%.o: $(src)/%.cc $(headers)
|
||||||
echo - Compiling '$*.cc'...
|
|
||||||
$(call mkdir,$(dir $@))
|
$(call mkdir,$(dir $@))
|
||||||
$(CXX) -fPIC -c $(flags) $< -o $@
|
$(CXX) -fPIC -c $(flags) $< -o $@
|
||||||
|
echo - Compiling '$*.cc'...
|
||||||
|
@ -9,9 +9,19 @@ namespace ppc::comp::tree::ast {
|
|||||||
return *it->second;
|
return *it->second;
|
||||||
}
|
}
|
||||||
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
||||||
auto p = (group_parser_t*)&parent->parser[name];
|
auto it = parent->parsers.find(name);
|
||||||
if (parent->groups.find(p) == parent->groups.end()) throw "A parser '" + name + "' exists, but isn't a group.";
|
if (it == parent->parsers.end()) {
|
||||||
return *p;
|
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() {
|
ast_ctx_t::~ast_ctx_t() {
|
||||||
@ -32,12 +42,6 @@ namespace ppc::comp::tree::ast {
|
|||||||
add_parser(parser);
|
add_parser(parser);
|
||||||
this->group[group].add(*parser, name);
|
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) {
|
data::map_t ast_ctx_t::parse(msg_stack_t &messages, std::vector<token_t> &tokens) {
|
||||||
ast_ctx_t ctx(messages, 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") { }
|
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;
|
type = true;
|
||||||
}
|
}
|
||||||
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
||||||
h.i++;
|
|
||||||
h.err("Default values are not yet supported.", 1);
|
|
||||||
h.advance();
|
h.advance();
|
||||||
h.force_parse("$_exp", "Expected an expression.", out["value"].map({}));
|
h.force_parse("$_exp", "Expected an expression.", out["value"].map({}));
|
||||||
type = true;
|
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);
|
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 {
|
class import_parser_t : public parser_t {
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
|
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 {
|
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const {
|
||||||
tree_helper_t h(ctx, res_i);
|
tree_helper_t h(ctx, res_i);
|
||||||
|
|
||||||
return h.parse("$_exp", out);
|
|
||||||
|
|
||||||
if (h.ended()) return true;
|
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());
|
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
out["namespace"] = data::null;
|
||||||
|
}
|
||||||
|
|
||||||
auto &imports = (out["imports"] = array_t()).array();
|
auto &imports = out["imports"].array({});
|
||||||
auto &contents = (out["content"] = array_t()).array();
|
auto &contents = out["content"].array({});
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
map_t map;
|
map_t map;
|
||||||
@ -83,7 +84,5 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
const parser_adder_t ppc::comp::tree::ast::glob_adder = [](ast_ctx_t &ctx) {
|
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());
|
ctx.add_parser(new glob_parser_t());
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user