AST building #2
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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({
|
||||
|
44
src/compiler/treeifier/ast/parsers/field.cc
Normal file
44
src/compiler/treeifier/ast/parsers/field.cc
Normal 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"); };
|
@ -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());
|
||||
};
|
||||
|
@ -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.";
|
||||
|
@ -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()); };
|
||||
|
@ -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()); };
|
||||
|
@ -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()); };
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user