chore: Rework AST innerworkings
This commit is contained in:
parent
7a4d81f5f8
commit
90461448f0
@ -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 {
|
||||
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;
|
||||
};
|
||||
class parser_t;
|
||||
class group_parser_t;
|
||||
|
||||
class group_parser_t : constr_parser_t {
|
||||
struct ast_ctx_t {
|
||||
private:
|
||||
struct named_parser {
|
||||
constr_parser_t *parser;
|
||||
std::string name;
|
||||
using named_parser_t = std::pair<std::string, parser_t*>;
|
||||
|
||||
struct parser_proxy_t {
|
||||
private:
|
||||
ast_ctx_t &parent;
|
||||
public:
|
||||
parser_t &operator[](const std::string &name) const;
|
||||
parser_proxy_t(ast_ctx_t &parent): parent(parent) { }
|
||||
};
|
||||
std::list<constr_parser_t*> parsers;
|
||||
std::unordered_map<std::string, constr_parser_t*> insertion_points;
|
||||
|
||||
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:
|
||||
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);
|
||||
msg_stack_t &messages;
|
||||
std::vector<tok::token_t> &tokens;
|
||||
|
||||
bool parse(messages::msg_stack_t &messages, data::map_t &out);
|
||||
void add_parser(std::string name, parser_t &parser);
|
||||
void add_parser(std::string name, group_parser_t &parser);
|
||||
|
||||
group_parser_t();
|
||||
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) { }
|
||||
};
|
||||
|
||||
extern const constr_parser_t &glob_parser;
|
||||
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);
|
||||
}
|
75
include/compiler/treeifier/ast/helper.hh
Normal file
75
include/compiler/treeifier/ast/helper.hh
Normal 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;
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
20
src/compiler/treeifier/parsers/group.cc
Normal file
20
src/compiler/treeifier/parsers/group.cc
Normal 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
27
src/lang/common.cc
Normal 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user