AST building #2

Merged
TopchetoEU merged 74 commits from TopchetoEU/ast-building into master 2022-10-28 11:58:03 +00:00
13 changed files with 186 additions and 100 deletions
Showing only changes of commit e2e180b9a5 - Show all commits

View File

@ -16,15 +16,16 @@ using namespace ppc::messages;
namespace ppc::comp::tree::ast {
class parser_t;
class group_parser_t;
struct ast_ctx_t;
using parser_factory_t = parser_t *(*)();
using group_parser_factory_t = group_parser_t *(*)();
using parser_adder_t = void (*)(ast_ctx_t &ctx);
extern parser_factory_t glob_parser;
extern parser_factory_t identifier_parser;
extern parser_factory_t nmsp_parser;
extern parser_factory_t type_parser;
extern group_parser_factory_t def_parser;
extern const parser_adder_t glob_adder;
extern const parser_adder_t identifier_adder;
extern const parser_adder_t nmsp_adder;
extern const parser_adder_t type_adder;
extern const parser_adder_t exp_adder;
extern const parser_adder_t field_adder;
struct ast_ctx_t {
private:
@ -40,23 +41,23 @@ namespace ppc::comp::tree::ast {
private:
ast_ctx_t *parent;
public:
const 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) { }
};
std::unordered_map<std::string, const parser_t*> parsers;
std::set<const parser_t*> groups;
void add_parser(const parser_t *parser);
void add_parser(const group_parser_t *parser);
std::set<group_parser_t*> groups;
public:
msg_stack_t &messages;
std::vector<token_t> &tokens;
std::set<loc_namespace_name_t> imports;
loc_namespace_name_t nmsp;
void add_parser(parser_factory_t factory) { add_parser(factory()); }
void add_parser(group_parser_factory_t factory) { add_parser(factory()); }
void add_parser(const parser_t *parser);
void add_parser(const parser_t *parser, const std::string &group);
void add_group(const std::string &name);
void add_parser(parser_adder_t factory) { factory(*this); }
ast_ctx_t &operator=(const ast_ctx_t &other) = delete;
@ -64,11 +65,13 @@ namespace ppc::comp::tree::ast {
const group_proxy_t group;
ast_ctx_t &init() {
add_parser(glob_parser);
add_parser(identifier_parser);
add_parser(nmsp_parser);
add_parser(def_parser);
add_parser(type_parser);
add_parser(identifier_adder);
add_parser(nmsp_adder);
add_parser(glob_adder);
add_parser(type_adder);
add_parser(exp_adder);
add_parser(field_adder);
return *this;
}
@ -102,11 +105,11 @@ namespace ppc::comp::tree::ast {
class group_parser_t : public parser_t {
private:
std::vector<std::pair<lang::namespace_name_t, parser_t*>> named_parsers;
std::vector<parser_t*> parsers;
std::vector<std::pair<lang::namespace_name_t, const parser_t*>> named_parsers;
std::vector<const parser_t*> parsers;
public:
group_parser_t &add(parser_t &parser);
group_parser_t &add(parser_t &parser, const lang::namespace_name_t &name);
group_parser_t &add(const parser_t &parser);
group_parser_t &add(const parser_t &parser, const lang::namespace_name_t &name);
bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;

View File

@ -12,14 +12,15 @@ namespace ppc::comp::tree::ast {
ast_ctx_t &ctx;
size_t &res_i;
public:
size_t i;
void throw_ended() {
if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc());
}
void throw_ended(const std::string &reason) {
if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end: " + reason, loc());
}
public:
size_t i;
location_t loc(size_t n) {
location_t res = prev_loc();
@ -62,10 +63,10 @@ namespace ppc::comp::tree::ast {
else return ctx.tokens[res_i].location.intersect(loc());
}
void err(std::string message) {
bool err(std::string message) {
throw message_t::error(message, loc());
}
void err(std::string message, size_t n) {
bool err(std::string message, size_t n) {
throw message_t::error(message, loc(n));
}
@ -78,6 +79,10 @@ namespace ppc::comp::tree::ast {
return i == ctx.tokens.size();
}
token_t &curr(const std::string &reason) {
throw_ended(reason);
return ctx.tokens[i];
}
token_t &curr() {
throw_ended();
return ctx.tokens[i];
@ -113,7 +118,7 @@ namespace ppc::comp::tree::ast {
}
void force_push_parse(const std::string &name, std::string message, data::array_t &out) {
advance(message);
throw_ended(message);
bool success;
try {
@ -127,7 +132,7 @@ namespace ppc::comp::tree::ast {
if (!success) err(message);
}
void force_parse(const std::string &name, std::string message, data::map_t &out) {
advance(message);
throw_ended(message);
bool success;
try {

View File

@ -39,16 +39,22 @@ namespace ppc::data {
bool is_string() const;
bool is_bool() const;
bool array(array_t &out) const;
bool map(map_t &out) const;
bool number(number_t &out) const;
bool string(string_t &out) const;
bool boolean(bool_t &out) const;
array_t &array(const array_t &arr);
map_t &map(const map_t &map);
number_t &number(number_t num);
string_t &string(const string_t &str);
bool_t &boolean(bool_t bl);
array_t &array() const;
map_t &map() const;
array_t &array();
map_t &map();
number_t &number();
string_t &string();
bool_t &boolean();
const array_t &array() const;
const map_t &map() const;
number_t number() const;
string_t &string() const;
const string_t &string() const;
bool_t boolean() const;
value_t &operator=(const value_t &other);
@ -65,8 +71,6 @@ namespace ppc::data {
value_t(bool_t val);
value_t(const value_t &other);
static value_t mk_arr();
static value_t mk_map();
};

View File

@ -38,7 +38,13 @@ namespace ppc::messages {
inline auto begin() { return messages.begin(); }
inline auto end() { return messages.end(); }
inline auto begin() const { return messages.begin(); }
inline auto end() const { return messages.end(); }
void push(const message_t &msg) { messages.push_back(msg); }
void push(const msg_stack_t &other) {
for (const auto &msg : other) push(msg);
}
const message_t &peek() { return messages.back(); }
void clear() { messages.clear(); }

View File

@ -8,10 +8,10 @@ namespace ppc::comp::tree::ast {
if (it == parent->parsers.end()) throw "The parser '" + name + "' doesn't exist.";
return *it->second;
}
const group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
auto p = &parent->parser[name];
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 *(const group_parser_t*)p;
return *p;
}
ast_ctx_t::~ast_ctx_t() {
@ -24,7 +24,12 @@ namespace ppc::comp::tree::ast {
if (parsers.find(parser->name()) != parsers.end()) throw "The parser '" + parser->name() + "' already exists.";
parsers[parser->name()] = parser;
}
void ast_ctx_t::add_parser(const group_parser_t *parser) {
void ast_ctx_t::add_parser(const parser_t *parser, const std::string &group) {
add_parser(parser);
this->group[group].add(*parser);
}
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);

View File

@ -51,7 +51,7 @@ namespace ppc::comp::tree::ast::conv {
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp) {
data::map_t res;
auto arr = (res["content"] = data::array_t()).array();
auto arr = res["content"].array({});
for (const auto &segment : nmsp) {
arr.push({

View File

@ -0,0 +1,44 @@
#include "compiler/treeifier/ast/helper.hh"
class field_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.i++;
h.err("Default values are not yet supported.", 1);
h.advance();
h.force_parse("$_exp", "Expected an expression.", out["value"].map({}));
type = true;
}
if (h.curr().is_operator(operator_t::SEMICOLON)) {
if (type || defval) return h.submit();
else return h.err("A type or a default value must be specified ");
}
else if (type || defval) {
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
return h.submit(false);
}
else return false;
return h.submit(true);
}
public: field_parser_t(): parser_t("$_field") { }
};
parser_adder_t ppc::comp::tree::ast::field_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new field_parser_t(), "$_def"); };

View File

@ -9,6 +9,7 @@ class nmsp_def_parser_t : public parser_t {
if (h.ended()) return false;
if (!h.curr().is_identifier("namespace")) return false;
h.advance("Expected a namespace");
h.force_parse("$_nmsp", "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
@ -25,6 +26,7 @@ class import_parser_t : public parser_t {
if (h.ended()) return false;
if (!h.curr().is_identifier("import")) return false;
h.advance("Expected a namespace");
h.force_parse("$_nmsp", "Expected a namespace.", res);
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
@ -49,7 +51,7 @@ class glob_parser_t : public parser_t {
}
auto &imports = (out["imports"] = array_t()).array();
/* auto &contents = */ (out["content"] = array_t()).array();
auto &contents = (out["content"] = array_t()).array();
while (true) {
map_t map;
@ -60,9 +62,16 @@ class glob_parser_t : public parser_t {
if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported.");
}
while (true) {
if (h.ended()) break;
if (!h.push_parse("$_def", contents)) {
ctx.messages.push(message_t::error("Invalid token.", h.loc()));
h.i++;
}
}
if (!h.ended()) h.err("Invalid token.");
if (ctx.messages.is_failed()) return false;
return h.submit();
}
@ -70,5 +79,8 @@ public:
glob_parser_t(): parser_t("$_glob") { }
};
parser_factory_t ppc::comp::tree::ast::glob_parser = []() { return (parser_t*)new glob_parser_t(); };
group_parser_factory_t ppc::comp::tree::ast::def_parser = []() { return new group_parser_t("$_def"); };
parser_adder_t ppc::comp::tree::ast::glob_adder = [](ast_ctx_t &ctx) {
ctx.add_parser(new group_parser_t("$_def"));
ctx.add_parser(new group_parser_t("$_expr_val"));
ctx.add_parser(new glob_parser_t());
};

View File

@ -2,10 +2,13 @@
#include "compiler/treeifier/tokenizer.hh"
#include "compiler/treeifier/ast/helper.hh"
#include <algorithm>
#include <unordered_map>
#include <sstream>
using namespace ppc::comp::tree;
using namespace ppc::comp::tree::ast;
using namespace std::string_literals;
using namespace std;
static bool read_nmsp(ast_ctx_t &ctx, size_t &i, const lang::namespace_name_t &name) {
tree_helper_t h(ctx, i);
@ -33,29 +36,31 @@ static bool read_nmsp(ast_ctx_t &ctx, size_t &i, const lang::namespace_name_t &n
bool group_parser_t::parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
tree_helper_t h(ctx, i);
if (h.ended()) return false;
for (auto &pair : named_parsers) {
if (!read_nmsp(ctx, i, pair.first)) continue;
auto &parser = *pair.second;
return parser(ctx, i, out);
if (parser(ctx, i, out)) return true;
else throw message_t::error("Unexpected construct specifier.", h.res_loc());
}
unordered_map<string, message_t> errors;
for (auto parser : parsers) {
try {
return (*parser)(ctx, i, out);
}
catch (const message_t &err) {
ctx.messages.push(err);
return false;
}
if ((*parser)(ctx, i, out)) return true;
}
stringstream m;
return false;
}
group_parser_t &group_parser_t::add(parser_t &parser) {
group_parser_t &group_parser_t::add(const parser_t &parser) {
parsers.push_back(&parser);
return *this;
}
group_parser_t &group_parser_t::add(parser_t &parser, const lang::namespace_name_t &name) {
group_parser_t &group_parser_t::add(const parser_t &parser, const lang::namespace_name_t &name) {
if (name.empty()) throw "Name can't be empty."s;
if (std::find(parsers.begin(), parsers.end(), &parser) != parsers.end()) {
throw "Parser '" + name.to_string() + "' already in group.";

View File

@ -18,4 +18,4 @@ class identifier_parser_t : public parser_t {
public: identifier_parser_t(): parser_t("$_identifier") { }
};
parser_factory_t ppc::comp::tree::ast::identifier_parser = []() { return (parser_t*)new identifier_parser_t(); };
parser_adder_t ppc::comp::tree::ast::identifier_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new identifier_parser_t()); };

View File

@ -23,4 +23,4 @@ class nmsp_parser_t : public parser_t {
public: nmsp_parser_t(): parser_t("$_nmsp") { }
};
parser_factory_t ppc::comp::tree::ast::nmsp_parser = []() { return (parser_t*)new nmsp_parser_t(); };
parser_adder_t ppc::comp::tree::ast::nmsp_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new nmsp_parser_t()); };

View File

@ -47,4 +47,4 @@ class type_parser_t : public parser_t {
public: type_parser_t(): parser_t("$_type") { }
};
parser_factory_t ppc::comp::tree::ast::type_parser = []() { return (parser_t*)new type_parser_t(); };
parser_adder_t ppc::comp::tree::ast::type_adder = [](ast_ctx_t &ctx) { ctx.add_parser(new type_parser_t()); };

View File

@ -20,47 +20,55 @@ namespace ppc::data {
return type == type_t::Bool;
}
bool value_t::array(array_t &out) const {
if (is_array()) {
out = *val.arr;
return true;
}
return false;
array_t &value_t::array(const array_t &val) {
*this = val;
return *this->val.arr;
}
bool value_t::map(map_t &out) const {
if (is_map()) {
out = *val.map;
return true;
}
return false;
map_t &value_t::map(const map_t &val) {
*this = val;
return *this->val.map;
}
bool value_t::number(number_t &out) const {
if (is_number()) {
out = val.num;
return true;
}
return false;
number_t &value_t::number(number_t val) {
*this = val;
return this->val.num;
}
bool value_t::string(string_t &out) const {
if (is_string()) {
out = *val.str;
return true;
}
return false;
string_t &value_t::string(const string_t &val) {
*this = val;
return *this->val.str;
}
bool value_t::boolean(bool_t &out) const {
if (is_bool()) {
out = val.bl;
return true;
}
return false;
bool_t &value_t::boolean(bool_t val) {
*this = val;
return this->val.bl;
}
array_t &value_t::array() const {
array_t &value_t::array() {
if (is_array()) return *val.arr;
else throw (std::string)"The value isn't an array.";
}
map_t &value_t::map() const {
map_t &value_t::map() {
if (is_map()) return *val.map;
else throw (std::string)"The value isn't a map.";
}
number_t &value_t::number() {
if (is_number()) return val.num;
else throw (std::string)"The value isn't a number.";
}
string_t &value_t::string() {
if (is_string()) return *val.str;
else throw (std::string)"The value isn't a string.";
}
bool_t &value_t::boolean() {
if (is_bool()) return val.bl;
else throw (std::string)"The value isn't a bool.";
}
const array_t &value_t::array() const {
if (is_array()) return *val.arr;
else throw (std::string)"The value isn't an array.";
}
const map_t &value_t::map() const {
if (is_map()) return *val.map;
else throw (std::string)"The value isn't a map.";
}
@ -68,7 +76,7 @@ namespace ppc::data {
if (is_number()) return val.num;
else throw (std::string)"The value isn't a number.";
}
string_t &value_t::string() const {
const string_t &value_t::string() const {
if (is_string()) return *val.str;
else throw (std::string)"The value isn't a string.";
}
@ -121,12 +129,6 @@ namespace ppc::data {
break;
}
}
value_t value_t::mk_arr() {
return value_t(array_t());
}
value_t value_t::mk_map() {
return value_t(map_t());
}
value_t::~value_t() {
switch (type) {