chore: Rework AST innerworkings

This commit is contained in:
TopchetoEU 2022-10-04 16:00:18 +03:00
parent 7a4d81f5f8
commit 90461448f0
9 changed files with 237 additions and 82 deletions

View File

@ -1,43 +1,84 @@
#pragma once
#include <string>
#include <list>
#include <set>
#include <unordered_map>
#include <memory>
#include "compiler/treeifier/tokenizer.hh"
#include "utils/data.hh"
#include "utils/slice.hh"
#include "lang/common.hh"
using namespace std::string_literals;
using namespace ppc;
using namespace ppc::messages;
namespace ppc::comp::tree::ast {
class constr_parser_t {
class parser_t;
class group_parser_t;
struct ast_ctx_t {
private:
std::string name;
public:
const std::string &name() { return name; }
virtual bool parse(messages::msg_stack_t &messages, vec_slice_t<tok::token_t> &tokens, data::map_t &out) = 0;
};
using named_parser_t = std::pair<std::string, parser_t*>;
class group_parser_t : constr_parser_t {
struct parser_proxy_t {
private:
struct named_parser {
constr_parser_t *parser;
std::string name;
};
std::list<constr_parser_t*> parsers;
std::unordered_map<std::string, constr_parser_t*> insertion_points;
ast_ctx_t &parent;
public:
void add_insertion_point(constr_parser_t &parser, const std::string &name);
void add(constr_parser_t &parser);
void add(const std::string &ins_point, constr_parser_t &parser);
bool parse(messages::msg_stack_t &messages, data::map_t &out);
group_parser_t();
parser_t &operator[](const std::string &name) const;
parser_proxy_t(ast_ctx_t &parent): parent(parent) { }
};
extern const constr_parser_t &glob_parser;
struct group_proxy_t {
private:
ast_ctx_t &parent;
public:
group_parser_t &operator[](const std::string &name) const;
group_proxy_t(ast_ctx_t &parent): parent(parent) { }
};
std::unordered_map<std::string, parser_t*> parsers;
std::set<parser_t*> groups;
public:
msg_stack_t &messages;
std::vector<tok::token_t> &tokens;
void add_parser(std::string name, parser_t &parser);
void add_parser(std::string name, group_parser_t &parser);
const parser_proxy_t parser;
const group_proxy_t group;
ast_ctx_t(msg_stack_t &messages, std::vector<tok::token_t> tokens):
messages(messages),
tokens(tokens),
parser(*this),
group(*this) { }
};
class parser_t {
private:
std::string _name;
public:
const std::string &name() { return _name; }
virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0;
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
return parse(ctx, i, out);
}
};
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;
public:
group_parser_t &add(parser_t &parser);
group_parser_t &add(parser_t &parser, const lang::namespace_name_t &name);
bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
};
extern const parser_t &glob_parser;
const group_parser_t &get_group(std::string name);
}

View File

@ -0,0 +1,75 @@
#include "compiler/treeifier/ast.hh"
namespace ppc::comp::tree::ast {
struct tree_helper_t {
private:
ast_ctx_t &ctx;
size_t &res_i;
size_t i;
public:
void submit() {
res_i = i;
}
bool ended() {
return i == ctx.tokens.size();
}
tok::token_t &curr() { return ctx.tokens[i]; }
location_t next_loc(size_t n = 1) {
location_t res = loc();
res.start += res.length;
res.code_start += res.length;
res.length = n;
return res;
}
location_t loc() {
if (ended()) {
if (i == 0) return location_t::NONE;
location_t loc = ctx.tokens[i - 1].location;
loc.start += loc.length;
loc.code_start += loc.length;
loc.length = 1;
return loc;
}
else return curr().location;
}
bool try_parse(const parser_t &parser, data::map_t &out, messages::msg_stack_t &messages) {
try {
return parser(ctx, i, out);
}
catch (messages::message_t msg) {
messages.push(msg);
return false;
}
}
bool try_parse(const parser_t &parser, data::map_t &out) {
try {
return parser(ctx, i, out);
}
catch (messages::message_t msg) {
return false;
}
}
bool try_advance() {
if (ended()) return false;
i++;
return !ended();
}
bool advance() {
if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc());
i++;
if (ended()) throw messages::message_t(message_t::ERROR, "Unexpected end.", loc());
}
tree_helper_t(ast_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) {
this->i = i;
}
};
}

View File

@ -4,11 +4,31 @@
#include "utils/location.hh"
namespace ppc::lang {
template <class T>
struct located_t : T {
location_t location;
template <class ...Args>
located_t(location_t loc, Args ...args): T(args...), location(loc) { }
template <class ...Args>
located_t(Args ...args): T(args...), location(location_t::NONE) { }
};
struct namespace_name_t {
std::vector<std::string> segments;
ppc::location_t location;
bool operator ==(const namespace_name_t &other);
bool is_empty() const { return segments.empty(); }
auto begin() { return segments.begin(); }
auto end() { return segments.end(); }
bool operator ==(const namespace_name_t &other) const;
const std::string &operator[](size_t i) const { return segments[i]; }
std::string to_string() const;
namespace_name_t() { }
namespace_name_t(std::initializer_list<std::string> segments): segments(segments.begin(), segments.end()) { }
};
bool is_identifier_valid(messages::msg_stack_t &msg_stack, ppc::location_t location, const std::string &name);

View File

@ -14,8 +14,8 @@ namespace ppc::messages {
WARNING,
ERROR,
} level;
location_t location;
std::string content;
location_t location;
message_t(level_t level, std::string content, location_t loc = location_t::NONE) :
level(level),

View File

@ -1,54 +0,0 @@
#include <vector>
namespace ppc {
template <class T>
class slice_t {
private:
T *iterable;
std::size_t start;
std::size_t n;
public:
auto begin() const { return iterable->begin() + start; }
auto end() const { return iterable->end() + start + n; }
auto size() const { return n; }
auto &operator[](std::size_t i) const { return (iterable*)[start + i]; }
slice_t(T &iterable, std::size_t start, std::size_t n) {
this->iterable = &iterable;
this->start = start;
this->n = n;
if (n == -1u) this->n = iterable.size() - start;
}
};
template <class T>
using vec_slice_t = slice_t<std::vector<T>>;
template <class T>
inline slice_t<T> slice(slice_t<T> &sl) {
return slice_t<T>(sl.iterable, sl.start, sl.n);
}
template <class T>
inline slice_t<T> slice(slice_t<T> &sl, std::size_t start) {
return slice_t<T>(sl.iterable, sl.start + start, sl.n);
}
template <class T>
inline slice_t<T> slice(slice_t<T> &sl, std::size_t start, std::size_t n) {
return slice_t<T>(sl.iterable, sl.start + start, n);
}
template <class T>
inline slice_t<T> slice(T &vec) {
return slice_t<T>(vec, 0, vec.size());
}
template <class T>
inline slice_t<T> slice(T &vec, std::size_t start) {
return slice_t<T>(vec, start, vec.size());
}
template <class T>
inline slice_t<T> slice(T &vec, std::size_t start, std::size_t n) {
return slice_t<T>(vec, start, n);
}
}

View File

@ -1 +1,27 @@
#include "compiler/treeifier/ast.hh"
namespace ppc::comp::tree::ast {
std::unordered_map<std::string, group_parser_t> parsers;
parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
auto it = parent.parsers.find(name);
if (it == parent.parsers.end()) throw "The parser '" + name + "' doesn't exist.";
return *it->second;
}
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
parser_t *p = &parent.parser[name];
if (parent.groups.find(p) == parent.groups.end()) throw "A parser '" + name + "' exists, but isn't a group.";
return *(group_parser_t*)p;
}
void ast_ctx_t::add_parser(std::string name, parser_t &parser) {
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
parsers[name] = &parser;
}
void ast_ctx_t::add_parser(std::string name, group_parser_t &parser) {
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
parsers[name] = &parser;
groups.emplace(&parser);
}
}

View File

@ -1,11 +1,11 @@
#include "compiler/treeifier/ast.hh"
namespace ppc::comp::tree::ast {
class glob_parser_t : public constr_parser_t {
bool parse(messages::msg_stack_t &messages, vec_slice_t<tok::token_t> &tokens, data::map_t &out) {
class glob_parser_t : public parser_t {
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const {
return false;
}
};
const constr_parser_t &glob_parser = glob_parser_t();
const parser_t &glob_parser = glob_parser_t();
}

View File

@ -0,0 +1,20 @@
#include "compiler/treeifier/ast.hh"
#include <algorithm>
using namespace ppc::comp::tree::ast;
using namespace std::string_literals;
group_parser_t &group_parser_t::add(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) {
if (name.is_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.";
}
named_parsers.push_back({ name, &parser });
return *this;
}

27
src/lang/common.cc Normal file
View File

@ -0,0 +1,27 @@
#include <sstream>
#include "lang/common.hh"
namespace ppc::lang {
std::string namespace_name_t::to_string() const {
std::stringstream res;
for (size_t i = 0; i < segments.size(); i++) {
if (i != 0) res << "::";
res << segments[i];
}
return res.str();
}
bool namespace_name_t::operator==(const namespace_name_t &other) const {
if (other.segments.size() != segments.size()) return false;
for (size_t i = 0; i < segments.size(); i++) {
if (other[i] != segments[i]) return false;
}
return true;
}
}