chore: Rework AST innerworkings
This commit is contained in:
parent
7a4d81f5f8
commit
90461448f0
@ -1,43 +1,84 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
#include "compiler/treeifier/tokenizer.hh"
|
||||||
#include "utils/data.hh"
|
#include "utils/data.hh"
|
||||||
#include "utils/slice.hh"
|
|
||||||
#include "lang/common.hh"
|
#include "lang/common.hh"
|
||||||
|
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
|
using namespace ppc::messages;
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
namespace ppc::comp::tree::ast {
|
||||||
class constr_parser_t {
|
class parser_t;
|
||||||
private:
|
class group_parser_t;
|
||||||
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 group_parser_t : constr_parser_t {
|
struct ast_ctx_t {
|
||||||
private:
|
private:
|
||||||
struct named_parser {
|
using named_parser_t = std::pair<std::string, parser_t*>;
|
||||||
constr_parser_t *parser;
|
|
||||||
std::string name;
|
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:
|
public:
|
||||||
void add_insertion_point(constr_parser_t &parser, const std::string &name);
|
msg_stack_t &messages;
|
||||||
void add(constr_parser_t &parser);
|
std::vector<tok::token_t> &tokens;
|
||||||
void add(const std::string &ins_point, constr_parser_t &parser);
|
|
||||||
|
|
||||||
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"
|
#include "utils/location.hh"
|
||||||
|
|
||||||
namespace ppc::lang {
|
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 {
|
struct namespace_name_t {
|
||||||
std::vector<std::string> segments;
|
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);
|
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,
|
WARNING,
|
||||||
ERROR,
|
ERROR,
|
||||||
} level;
|
} level;
|
||||||
location_t location;
|
|
||||||
std::string content;
|
std::string content;
|
||||||
|
location_t location;
|
||||||
|
|
||||||
message_t(level_t level, std::string content, location_t loc = location_t::NONE) :
|
message_t(level_t level, std::string content, location_t loc = location_t::NONE) :
|
||||||
level(level),
|
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"
|
#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"
|
#include "compiler/treeifier/ast.hh"
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
namespace ppc::comp::tree::ast {
|
||||||
class glob_parser_t : public constr_parser_t {
|
class glob_parser_t : public parser_t {
|
||||||
bool parse(messages::msg_stack_t &messages, vec_slice_t<tok::token_t> &tokens, data::map_t &out) {
|
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