feat: add namespace and import parsing
This commit is contained in:
parent
0a68529c3b
commit
ee6c29bb7d
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,7 +18,7 @@
|
|||||||
!src/*/**/*.cc
|
!src/*/**/*.cc
|
||||||
!src/*/**/*.h
|
!src/*/**/*.h
|
||||||
!src/*/**/*.hh
|
!src/*/**/*.hh
|
||||||
!src/*/proj.txt
|
!src/*.proj
|
||||||
!src/lsproj.cc
|
!src/lsproj.cc
|
||||||
|
|
||||||
!scripts
|
!scripts
|
||||||
|
@ -17,54 +17,71 @@ namespace ppc::comp::tree::ast {
|
|||||||
class parser_t;
|
class parser_t;
|
||||||
class group_parser_t;
|
class group_parser_t;
|
||||||
|
|
||||||
|
extern const parser_t &glob_parser;
|
||||||
|
extern const parser_t &identifier_parser;
|
||||||
|
extern const parser_t &nmsp_parser;
|
||||||
|
|
||||||
struct ast_ctx_t {
|
struct ast_ctx_t {
|
||||||
private:
|
private:
|
||||||
using named_parser_t = std::pair<std::string, parser_t*>;
|
|
||||||
|
|
||||||
struct parser_proxy_t {
|
struct parser_proxy_t {
|
||||||
private:
|
private:
|
||||||
ast_ctx_t &parent;
|
ast_ctx_t *parent;
|
||||||
public:
|
public:
|
||||||
parser_t &operator[](const std::string &name) const;
|
const parser_t &operator[](const std::string &name) const;
|
||||||
parser_proxy_t(ast_ctx_t &parent): parent(parent) { }
|
parser_proxy_t(ast_ctx_t *parent): parent(parent) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct group_proxy_t {
|
struct group_proxy_t {
|
||||||
private:
|
private:
|
||||||
ast_ctx_t &parent;
|
ast_ctx_t *parent;
|
||||||
public:
|
public:
|
||||||
group_parser_t &operator[](const std::string &name) const;
|
const group_parser_t &operator[](const std::string &name) const;
|
||||||
group_proxy_t(ast_ctx_t &parent): parent(parent) { }
|
group_proxy_t(ast_ctx_t *parent): parent(parent) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<std::string, parser_t*> parsers;
|
std::unordered_map<std::string, const parser_t*> parsers;
|
||||||
std::set<parser_t*> groups;
|
std::set<const parser_t*> groups;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
msg_stack_t &messages;
|
msg_stack_t &messages;
|
||||||
std::vector<token_t> &tokens;
|
std::vector<token_t> &tokens;
|
||||||
std::set<lang::namespace_name_t> imports;
|
std::set<loc_namespace_name_t> imports;
|
||||||
located_t<namespace_name_t> nmsp;
|
loc_namespace_name_t nmsp;
|
||||||
|
|
||||||
void add_parser(std::string name, parser_t &parser);
|
void add_parser(const parser_t &parser);
|
||||||
void add_parser(std::string name, group_parser_t &parser);
|
void add_parser(const group_parser_t &parser);
|
||||||
|
|
||||||
const parser_proxy_t parser;
|
const parser_proxy_t parser;
|
||||||
const group_proxy_t group;
|
const group_proxy_t group;
|
||||||
|
|
||||||
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> tokens):
|
ast_ctx_t &init() {
|
||||||
|
add_parser(glob_parser);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse(msg_stack_t &messages, std::vector<token_t> &tokens, data::map_t &out);
|
||||||
|
|
||||||
|
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens):
|
||||||
messages(messages),
|
messages(messages),
|
||||||
tokens(tokens),
|
tokens(tokens),
|
||||||
parser(*this),
|
parser(this),
|
||||||
group(*this) { }
|
group(this) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class parser_t {
|
class parser_t {
|
||||||
public:
|
private:
|
||||||
|
std::string _name;
|
||||||
|
protected:
|
||||||
virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0;
|
virtual bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const = 0;
|
||||||
|
public:
|
||||||
|
const std::string &name() const { return _name; }
|
||||||
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
|
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
|
||||||
|
data::map_t res;
|
||||||
|
out["$_name"] = _name;
|
||||||
return parse(ctx, i, out);
|
return parse(ctx, i, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser_t(const std::string &name): _name(name) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class group_parser_t : public parser_t {
|
class group_parser_t : public parser_t {
|
||||||
@ -78,7 +95,14 @@ namespace ppc::comp::tree::ast {
|
|||||||
bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
|
bool parse(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const parser_t &glob_parser;
|
namespace conv {
|
||||||
|
data::map_t identifier_to_map(const located_t<std::string> &loc);
|
||||||
|
located_t<std::string> map_to_identifier(const data::map_t &map);
|
||||||
|
|
||||||
const group_parser_t &get_group(std::string name);
|
data::map_t loc_to_map(const location_t &loc);
|
||||||
|
location_t map_to_loc(const data::map_t &map);
|
||||||
|
|
||||||
|
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp);
|
||||||
|
loc_namespace_name_t map_to_nmsp(const data::map_t &map);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,11 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
#include "compiler/treeifier/ast.hh"
|
||||||
|
|
||||||
|
using namespace ppc;
|
||||||
|
using namespace ppc::lang;
|
||||||
|
using namespace ppc::data;
|
||||||
|
using namespace ppc::comp::tree;
|
||||||
|
using namespace ppc::comp::tree::ast;
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
namespace ppc::comp::tree::ast {
|
||||||
struct tree_helper_t {
|
struct tree_helper_t {
|
||||||
private:
|
private:
|
||||||
@ -15,20 +21,6 @@ namespace ppc::comp::tree::ast {
|
|||||||
public:
|
public:
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
bool submit() {
|
|
||||||
res_i = i;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ended() {
|
|
||||||
return i == ctx.tokens.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
token_t &curr() {
|
|
||||||
throw_ended();
|
|
||||||
return ctx.tokens[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
location_t next_loc(size_t n = 1) {
|
location_t next_loc(size_t n = 1) {
|
||||||
location_t res = loc();
|
location_t res = loc();
|
||||||
res.start += res.length;
|
res.start += res.length;
|
||||||
@ -56,26 +48,22 @@ namespace ppc::comp::tree::ast {
|
|||||||
else return ctx.tokens[res_i].location.intersect(loc());
|
else return ctx.tokens[res_i].location.intersect(loc());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse(const parser_t &parser, data::map_t &out) {
|
void err(std::string message) {
|
||||||
return parser(ctx, i, out);
|
throw message_t::error(message, loc());
|
||||||
}
|
}
|
||||||
bool try_parse(const parser_t &parser, data::map_t &out, bool silent = true) {
|
|
||||||
try {
|
bool submit(bool inc_i = true) {
|
||||||
return parser(ctx, i, out);
|
res_i = (i += inc_i);
|
||||||
}
|
return true;
|
||||||
catch (messages::message_t msg) {
|
|
||||||
if (!silent) ctx.messages.push(msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool try_parse(const parser_t &parser, data::map_t &out, message_t &err) {
|
|
||||||
try {
|
bool ended() {
|
||||||
return parser(ctx, i, out);
|
return i == ctx.tokens.size();
|
||||||
}
|
}
|
||||||
catch (messages::message_t msg) {
|
|
||||||
err = msg;
|
token_t &curr() {
|
||||||
return false;
|
throw_ended();
|
||||||
}
|
return ctx.tokens[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_advance() {
|
bool try_advance() {
|
||||||
@ -94,6 +82,48 @@ namespace ppc::comp::tree::ast {
|
|||||||
throw_ended(reason);
|
throw_ended(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool push_parse(const parser_t &parser, data::array_t &out) {
|
||||||
|
data::map_t res;
|
||||||
|
if (parser(ctx, i, res)) {
|
||||||
|
out.push(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse(const parser_t &parser, data::map_t &out) {
|
||||||
|
return parser(ctx, i, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_push_parse(const parser_t &parser, std::string message, data::array_t &out) {
|
||||||
|
advance(message);
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
try {
|
||||||
|
success = push_parse(parser, out);
|
||||||
|
}
|
||||||
|
catch (const message_t &msg) {
|
||||||
|
ctx.messages.push(msg);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) err(message);
|
||||||
|
}
|
||||||
|
void force_parse(const parser_t &parser, std::string message, data::map_t &out) {
|
||||||
|
advance(message);
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
try {
|
||||||
|
success = parse(parser, out);
|
||||||
|
}
|
||||||
|
catch (const message_t &msg) {
|
||||||
|
ctx.messages.push(msg);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) err(message);
|
||||||
|
}
|
||||||
|
|
||||||
tree_helper_t(ast_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) {
|
tree_helper_t(ast_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) {
|
||||||
this->i = i;
|
this->i = i;
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,31 @@ namespace ppc::lang {
|
|||||||
bool operator ==(const namespace_name_t &other) const;
|
bool operator ==(const namespace_name_t &other) const;
|
||||||
bool operator !=(const namespace_name_t &other) const;
|
bool operator !=(const namespace_name_t &other) const;
|
||||||
|
|
||||||
|
operator std::string() const { return to_string(); }
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
namespace_name_t() { }
|
namespace_name_t() { }
|
||||||
namespace_name_t(std::initializer_list<std::string> segments): base(segments.begin(), segments.end()) { }
|
namespace_name_t(std::initializer_list<std::string> segments): base(segments.begin(), segments.end()) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct loc_namespace_name_t : public std::vector<located_t<std::string>> {
|
||||||
|
using base = std::vector<located_t<std::string>>;
|
||||||
|
|
||||||
|
bool operator ==(const loc_namespace_name_t &other) const;
|
||||||
|
bool operator !=(const loc_namespace_name_t &other) const;
|
||||||
|
|
||||||
|
namespace_name_t strip_location();
|
||||||
|
|
||||||
|
operator std::string() const { return to_string(); }
|
||||||
|
std::string to_string() const;
|
||||||
|
|
||||||
|
loc_namespace_name_t() { }
|
||||||
|
loc_namespace_name_t(std::initializer_list<located_t<std::string>> segments): base(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);
|
||||||
inline bool is_identifier_valid(const std::string &name) {
|
inline bool is_identifier_valid(const std::string &name) {
|
||||||
messages::msg_stack_t ms { };
|
messages::msg_stack_t ms;
|
||||||
return is_identifier_valid(ms, { }, name);
|
return is_identifier_valid(ms, { }, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,22 +45,26 @@ namespace ppc::data {
|
|||||||
bool string(string_t &out) const;
|
bool string(string_t &out) const;
|
||||||
bool boolean(bool_t &out) const;
|
bool boolean(bool_t &out) const;
|
||||||
|
|
||||||
const array_t &array() const;
|
array_t &array() const;
|
||||||
const map_t &map() const;
|
map_t &map() const;
|
||||||
number_t number() const;
|
number_t number() const;
|
||||||
const string_t &string() const;
|
string_t &string() const;
|
||||||
bool_t boolean() const;
|
bool_t boolean() const;
|
||||||
|
|
||||||
// value_t &operator=(const value_t &other);
|
value_t &operator=(const value_t &other);
|
||||||
|
|
||||||
~value_t();
|
~value_t();
|
||||||
value_t();
|
value_t();
|
||||||
value_t(const array_t &val);
|
value_t(const array_t &val);
|
||||||
value_t(const map_t &val);
|
value_t(const map_t &val);
|
||||||
|
value_t(std::initializer_list<std::pair<std::string, value_t>> map);
|
||||||
value_t(number_t val);
|
value_t(number_t val);
|
||||||
value_t(const string_t &val);
|
value_t(const string_t &val);
|
||||||
value_t(bool_t val);
|
value_t(bool_t val);
|
||||||
value_t(const value_t &other);
|
value_t(const value_t &other);
|
||||||
|
|
||||||
|
static value_t mk_arr();
|
||||||
|
static value_t mk_map();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -68,18 +72,34 @@ namespace ppc::data {
|
|||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, value_t> values;
|
std::unordered_map<std::string, value_t> values;
|
||||||
public:
|
public:
|
||||||
value_t &operator [](std::string name) {
|
value_t &operator [](std::string name){
|
||||||
if (values.find(name) == values.end()) {
|
auto res = values.find(name);
|
||||||
values.emplace(name, value_t());
|
if (res == values.end()) {
|
||||||
|
res = values.emplace(name, value_t()).first;
|
||||||
}
|
}
|
||||||
|
return res->second;
|
||||||
|
}
|
||||||
|
const value_t &operator [](std::string name) const {
|
||||||
|
auto res = values.find(name);
|
||||||
|
if (res == values.end()) throw "The map doesn't contain a key '" + name + "'.";
|
||||||
|
return res->second;
|
||||||
|
}
|
||||||
|
|
||||||
return values[name];
|
bool has(std::string key) const {
|
||||||
|
return values.find(key) != values.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t size() const { return values.size(); }
|
std::size_t size() const { return values.size(); }
|
||||||
|
|
||||||
auto begin() const { return values.begin(); }
|
auto begin() const { return values.begin(); }
|
||||||
auto end() const { return values.end(); }
|
auto end() const { return values.end(); }
|
||||||
|
|
||||||
|
map_t() { }
|
||||||
|
map_t(std::initializer_list<std::pair<std::string, value_t>> vals) {
|
||||||
|
for (const auto &pair : vals) {
|
||||||
|
values.insert(pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class array_t {
|
class array_t {
|
||||||
@ -87,9 +107,10 @@ namespace ppc::data {
|
|||||||
std::vector<value_t> values;
|
std::vector<value_t> values;
|
||||||
public:
|
public:
|
||||||
value_t &operator [](std::size_t i) { return values[i]; }
|
value_t &operator [](std::size_t i) { return values[i]; }
|
||||||
|
const value_t &operator [](std::size_t i) const { return values[i]; }
|
||||||
|
|
||||||
auto begin() { return values.begin(); }
|
auto begin() const { return values.begin(); }
|
||||||
auto end() { return values.end(); }
|
auto end() const { return values.end(); }
|
||||||
|
|
||||||
void push(const value_t &val) { values.push_back(val); }
|
void push(const value_t &val) { values.push_back(val); }
|
||||||
void insert(const value_t &val, std::size_t i = 0) { values.insert(begin() + i, val); }
|
void insert(const value_t &val, std::size_t i = 0) { values.insert(begin() + i, val); }
|
||||||
@ -97,5 +118,9 @@ namespace ppc::data {
|
|||||||
void remove(std::size_t i = 0) { values.erase(begin() + i); }
|
void remove(std::size_t i = 0) { values.erase(begin() + i); }
|
||||||
|
|
||||||
std::size_t size() const { return values.size(); }
|
std::size_t size() const { return values.size(); }
|
||||||
|
|
||||||
|
array_t() { }
|
||||||
|
array_t(const std::vector<value_t> &val): values(val) { }
|
||||||
|
array_t(std::initializer_list<value_t> val): values(val) { }
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ namespace ppc {
|
|||||||
std::size_t code_start;
|
std::size_t code_start;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|
||||||
|
operator std::string() const { return to_string(); }
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
location_t intersect(location_t other) const;
|
location_t intersect(location_t other) const;
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ namespace ppc::messages {
|
|||||||
location(loc) { }
|
location(loc) { }
|
||||||
message_t() : message_t(DEBUG, "") { }
|
message_t() : message_t(DEBUG, "") { }
|
||||||
|
|
||||||
|
operator std::string() const { return to_string(); }
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
bool is_severe() const;
|
bool is_severe() const;
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ namespace ppc::messages {
|
|||||||
inline auto end() { return messages.end(); }
|
inline auto end() { return messages.end(); }
|
||||||
|
|
||||||
void push(const message_t &msg) { messages.push_back(msg); }
|
void push(const message_t &msg) { messages.push_back(msg); }
|
||||||
|
const message_t &peek() { return messages.back(); }
|
||||||
void clear() { messages.clear(); }
|
void clear() { messages.clear(); }
|
||||||
|
|
||||||
bool is_failed() const;
|
bool is_failed() const;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
export lsproj = $(bin)/lsproj$(exe)
|
export lsproj = $(bin)/lsproj$(exe)
|
||||||
export flags += "-I$(inc)" -D$(OS) -DPPC_VERSION_MAJOR=$(version-major) -DPPC_VERSION_MINOR=$(version-minor) -DPPC_VERSION_BUILD=$(version-build)
|
export flags += "-I$(inc)" -D$(OS) -DPPC_VERSION_MAJOR=$(version-major) -DPPC_VERSION_MINOR=$(version-minor) -DPPC_VERSION_BUILD=$(version-build)
|
||||||
|
|
||||||
|
$(shell make -f scripts/lsproj.mak lsproj=$(lsproj) src=$(src) $(lsproj))
|
||||||
|
|
||||||
rwildcard=$(foreach d, $(wildcard $(1:=/*)),\
|
rwildcard=$(foreach d, $(wildcard $(1:=/*)),\
|
||||||
$(call rwildcard,$d,$2)\
|
$(call rwildcard,$d,$2)\
|
||||||
$(filter $(subst *,%,$2),$d)\
|
$(filter $(subst *,%,$2),$d)\
|
||||||
@ -30,13 +32,9 @@ lrdeps=$(foreach dep,$(call rdeps,$1),-l$(lib)$(call modoutput,$(dep)))
|
|||||||
|
|
||||||
modules = $(patsubst $(src)/%/,$(bin)/lib$(lib)%$(so),$(filter-out $(src)/$(mainmodule)/,$(wildcard $(src)/*/)))
|
modules = $(patsubst $(src)/%/,$(bin)/lib$(lib)%$(so),$(filter-out $(src)/$(mainmodule)/,$(wildcard $(src)/*/)))
|
||||||
sources = $(call rwildcard,$(src)/$1,*.cc)
|
sources = $(call rwildcard,$(src)/$1,*.cc)
|
||||||
headers = $(call rwildcard,$(inc),*.h)
|
headers = $(call rwildcard,$(inc),*.hh)
|
||||||
binaries = $(patsubst $(src)/%.cc,$(bin)/tmp/%.o,$(call sources,$1))
|
binaries = $(patsubst $(src)/%.cc,$(bin)/tmp/%.o,$(call sources,$1))
|
||||||
|
|
||||||
ifneq ($(nolsproj),yes)
|
|
||||||
$(shell make -f scripts/lsproj.mak lsproj=$(lsproj) src=$(src) $(lsproj))
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
.PRECIOUS: $(bin)/tmp/%.o
|
.PRECIOUS: $(bin)/tmp/%.o
|
||||||
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
compiler
|
compiler
|
||||||
utils, lang
|
utils, lang
|
@ -3,25 +3,44 @@
|
|||||||
namespace ppc::comp::tree::ast {
|
namespace ppc::comp::tree::ast {
|
||||||
std::unordered_map<std::string, group_parser_t> parsers;
|
std::unordered_map<std::string, group_parser_t> parsers;
|
||||||
|
|
||||||
parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
|
const parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
|
||||||
auto it = parent.parsers.find(name);
|
auto it = parent->parsers.find(name);
|
||||||
if (it == parent.parsers.end()) throw "The parser '" + name + "' doesn't exist.";
|
if (it == parent->parsers.end()) throw "The parser '" + name + "' doesn't exist.";
|
||||||
return *it->second;
|
return *it->second;
|
||||||
}
|
}
|
||||||
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
const group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
||||||
parser_t *p = &parent.parser[name];
|
auto p = &parent->parser[name];
|
||||||
if (parent.groups.find(p) == parent.groups.end()) throw "A parser '" + name + "' exists, but isn't a group.";
|
if (parent->groups.find(p) == parent->groups.end()) throw "A parser '" + name + "' exists, but isn't a group.";
|
||||||
return *(group_parser_t*)p;
|
return *(const group_parser_t*)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_ctx_t::add_parser(std::string name, parser_t &parser) {
|
void ast_ctx_t::add_parser(const parser_t &parser) {
|
||||||
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
|
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
|
||||||
parsers[name] = &parser;
|
parsers[parser.name()] = &parser;
|
||||||
}
|
}
|
||||||
void ast_ctx_t::add_parser(std::string name, group_parser_t &parser) {
|
void ast_ctx_t::add_parser(const group_parser_t &parser) {
|
||||||
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
|
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
|
||||||
parsers[name] = &parser;
|
parsers[parser.name()] = &parser;
|
||||||
groups.emplace(&parser);
|
groups.emplace(&parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ast_ctx_t::parse(msg_stack_t &messages, std::vector<token_t> &tokens, data::map_t &out) {
|
||||||
|
ast_ctx_t ctx(messages, tokens);
|
||||||
|
ctx.init();
|
||||||
|
data::map_t res;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (glob_parser(ctx, i, out)) {
|
||||||
|
out = res;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
catch (const message_t &msg) {
|
||||||
|
messages.push(msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
80
src/compiler/treeifier/ast/conv.cc
Normal file
80
src/compiler/treeifier/ast/conv.cc
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include "compiler/treeifier/ast.hh"
|
||||||
|
|
||||||
|
namespace ppc::comp::tree::ast::conv {
|
||||||
|
data::map_t identifier_to_map(const located_t<std::string> &loc) {
|
||||||
|
return {
|
||||||
|
{ "location", conv::loc_to_map(loc.location) },
|
||||||
|
{ "content", loc },
|
||||||
|
{ "$_name", identifier_parser.name() },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
located_t<std::string> map_to_identifier(const data::map_t &map) {
|
||||||
|
return { conv::map_to_loc(map["location"].map()), map["content"].string() };
|
||||||
|
}
|
||||||
|
|
||||||
|
data::map_t loc_to_map(const location_t &loc) {
|
||||||
|
data::map_t res = {
|
||||||
|
{ "$_name", "$_loc" },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loc.filename != "") res["filename"] = loc.filename;
|
||||||
|
if (loc.start != -1u) res["start"] = (float)loc.start;
|
||||||
|
if (loc.code_start != -1u) res["code_start"] = (float)loc.code_start;
|
||||||
|
if (loc.length != -1u) res["length"] = (float)loc.length;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
location_t map_to_loc(const data::map_t &map) {
|
||||||
|
location_t res;
|
||||||
|
|
||||||
|
if (map.has("filename")) {
|
||||||
|
if (map["filename"].is_string()) res.filename = map["filename"].string();
|
||||||
|
else throw "Expected key 'filename' to be a string.";
|
||||||
|
}
|
||||||
|
if (map.has("start")) {
|
||||||
|
if (map["start"].is_number()) res.start = (size_t)map["start"].number();
|
||||||
|
else throw "Expected key 'start' to be a number.";
|
||||||
|
}
|
||||||
|
if (map.has("length")) {
|
||||||
|
if (map["length"].is_number()) res.length = (size_t)map["length"].number();
|
||||||
|
else throw "Expected key 'length' to be a number.";
|
||||||
|
}
|
||||||
|
if (map.has("code_start")) {
|
||||||
|
if (map["code_start"].is_number()) res.code_start = (size_t)map["code_start"].number();
|
||||||
|
else throw "Expected key 'code_start' to be a number.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp) {
|
||||||
|
data::map_t res;
|
||||||
|
|
||||||
|
auto arr = (res["content"] = data::array_t()).array();
|
||||||
|
|
||||||
|
for (const auto &segment : nmsp) {
|
||||||
|
arr.push({
|
||||||
|
{ "location", loc_to_map(segment.location) },
|
||||||
|
{ "content", segment },
|
||||||
|
{ "$_name", nmsp_parser.name() },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
loc_namespace_name_t map_to_nmsp(const data::map_t &map) {
|
||||||
|
loc_namespace_name_t res;
|
||||||
|
|
||||||
|
for (const auto &segment : map["content"].array()) {
|
||||||
|
try {
|
||||||
|
auto val = map_to_identifier(segment.map());
|
||||||
|
res.push_back(val);
|
||||||
|
}
|
||||||
|
catch (const message_t &) {
|
||||||
|
throw "'content' of a namespace map must contain only identifiers.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
65
src/compiler/treeifier/ast/parsers/glob.cc
Normal file
65
src/compiler/treeifier/ast/parsers/glob.cc
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "compiler/treeifier/ast.hh"
|
||||||
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
|
using namespace ppc::comp::tree::ast;
|
||||||
|
|
||||||
|
class nmsp_def_parser_t : public parser_t {
|
||||||
|
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
|
||||||
|
tree_helper_t h(ctx, res_i);
|
||||||
|
if (h.ended()) return false;
|
||||||
|
|
||||||
|
if (!h.curr().is_identifier("namespace")) return false;
|
||||||
|
h.force_parse(nmsp_parser, "Expected a namespace.", res);
|
||||||
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) h.err("Expected a semicolon.");
|
||||||
|
|
||||||
|
return h.submit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: nmsp_def_parser_t(): parser_t("$_nmsp_def") { }
|
||||||
|
};
|
||||||
|
class import_parser_t : public parser_t {
|
||||||
|
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) const {
|
||||||
|
tree_helper_t h(ctx, res_i);
|
||||||
|
if (h.ended()) return false;
|
||||||
|
|
||||||
|
if (!h.curr().is_identifier("import")) return false;
|
||||||
|
h.force_parse(nmsp_parser, "Expected a namespace.", res);
|
||||||
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) h.err("Expected a semicolon.");
|
||||||
|
|
||||||
|
return h.submit(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: import_parser_t(): parser_t("$_import") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
const parser_t &import_parser = import_parser_t();
|
||||||
|
const parser_t &nmsp_def_parser = nmsp_def_parser_t();
|
||||||
|
|
||||||
|
class glob_parser_t : public parser_t {
|
||||||
|
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const {
|
||||||
|
tree_helper_t h(ctx, res_i);
|
||||||
|
if (h.ended()) return true;
|
||||||
|
h.parse(nmsp_def_parser, (out["namespace"] = map_t()).map());
|
||||||
|
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
|
||||||
|
|
||||||
|
auto imports = (out["imports"] = array_t()).array();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
map_t map;
|
||||||
|
imports.push(map);
|
||||||
|
if (!h.parse(import_parser, map)) break;
|
||||||
|
auto nmsp = conv::map_to_nmsp(map);
|
||||||
|
|
||||||
|
if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.ended()) h.err("Invalid token.");
|
||||||
|
|
||||||
|
return h.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
glob_parser_t(): parser_t("$_glob") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
const parser_t &ppc::comp::tree::ast::glob_parser = glob_parser_t();
|
21
src/compiler/treeifier/ast/parsers/identifier.cc
Normal file
21
src/compiler/treeifier/ast/parsers/identifier.cc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
|
class identifier_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.curr().is_identifier()) {
|
||||||
|
auto loc = h.loc();
|
||||||
|
out["location"] = conv::loc_to_map(loc);
|
||||||
|
out["content"] = h.curr().identifier();
|
||||||
|
return h.submit();
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public: identifier_parser_t(): parser_t("$_identifier") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
const parser_t &ppc::comp::tree::ast::identifier_parser = identifier_parser_t();
|
26
src/compiler/treeifier/ast/parsers/nmsp.cc
Normal file
26
src/compiler/treeifier/ast/parsers/nmsp.cc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "compiler/treeifier/ast/helper.hh"
|
||||||
|
|
||||||
|
class nmsp_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;
|
||||||
|
|
||||||
|
auto &arr = (out["content"] = array_t()).array();
|
||||||
|
|
||||||
|
if (!h.push_parse(identifier_parser, arr)) return false;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (h.ended()) break;
|
||||||
|
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
|
||||||
|
h.force_push_parse(identifier_parser, "Expected an identifier.", arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
out["location"] = conv::loc_to_map(h.res_loc());
|
||||||
|
return h.submit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public: nmsp_parser_t(): parser_t("$_nmsp") { }
|
||||||
|
};
|
||||||
|
|
||||||
|
const parser_t &ppc::comp::tree::ast::nmsp_parser = nmsp_parser_t();
|
@ -189,7 +189,7 @@ const lexlet_t LEXLET_OPERATOR = (lexlet_t) {
|
|||||||
},
|
},
|
||||||
.process = [] (char curr) {
|
.process = [] (char curr) {
|
||||||
bool failed = true;
|
bool failed = true;
|
||||||
if (first_op == curr && op_i == 1 && is_any(curr, "+-&|?<>")) failed = false;
|
if (first_op == curr && op_i == 1 && is_any(curr, ":+-&|?<>")) failed = false;
|
||||||
if (curr == '=') {
|
if (curr == '=') {
|
||||||
if (op_i == 1 && is_any(first_op, "<>=!+-/*%")) failed = false;
|
if (op_i == 1 && is_any(first_op, "<>=!+-/*%")) failed = false;
|
||||||
if (op_i == 2 && is_any(first_op, "<>?")) failed = false;
|
if (op_i == 2 && is_any(first_op, "<>?")) failed = false;
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
|
||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
|
||||||
class glob_parser_t : public parser_t {
|
|
||||||
bool parse_nmsp(ast_ctx_t &ctx, size_t &res_i, located_t<namespace_name_t> &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
located_t<namespace_name_t> res;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
auto &curr = h.curr();
|
|
||||||
|
|
||||||
if (h.ended() || !curr.is_identifier()) return false;
|
|
||||||
else res.push_back(curr.identifier());
|
|
||||||
|
|
||||||
if (!h.try_advance() || !h.curr().is_operator(operator_t::DOUBLE_COLON)) {
|
|
||||||
out = res;
|
|
||||||
return h.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool parse_nmsp_def(ast_ctx_t &ctx, size_t &res_i) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
if (h.ended()) return true;
|
|
||||||
|
|
||||||
if (h.curr().is_identifier("namespace")) {
|
|
||||||
h.advance("Expected a namespace name.");
|
|
||||||
if (!parse_nmsp(ctx, h.i, ctx.nmsp)) throw message_t::error("Expected a namespace name.", h.loc());
|
|
||||||
return h.submit();
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
bool parse_import(ast_ctx_t &ctx, size_t &res_i) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
if (h.ended()) return true;
|
|
||||||
|
|
||||||
if (h.curr().is_identifier("import")) {
|
|
||||||
h.advance("Expected a namespace name.");
|
|
||||||
located_t<namespace_name_t> name;
|
|
||||||
if (!parse_nmsp(ctx, h.i, name)) throw message_t::error("Expected a namespace name.", h.loc());
|
|
||||||
if (!ctx.imports.emplace(name).second) {
|
|
||||||
throw message_t::error("The namespace '" + name.to_string() + "' is already imported.", h.loc());
|
|
||||||
}
|
|
||||||
return h.submit();
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
if (h.ended()) return true;
|
|
||||||
parse_nmsp_def(ctx, h.i);
|
|
||||||
|
|
||||||
while (parse_import(ctx, h.i));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const parser_t &glob_parser = glob_parser_t();
|
|
||||||
}
|
|
@ -3,6 +3,16 @@
|
|||||||
#include "lang/common.hh"
|
#include "lang/common.hh"
|
||||||
|
|
||||||
namespace ppc::lang {
|
namespace ppc::lang {
|
||||||
|
std::string loc_namespace_name_t::to_string() const {
|
||||||
|
std::stringstream res;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size(); i++) {
|
||||||
|
if (i != 0) res << "::";
|
||||||
|
res << (*this)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.str();
|
||||||
|
}
|
||||||
std::string namespace_name_t::to_string() const {
|
std::string namespace_name_t::to_string() const {
|
||||||
std::stringstream res;
|
std::stringstream res;
|
||||||
|
|
||||||
@ -13,6 +23,25 @@ namespace ppc::lang {
|
|||||||
|
|
||||||
return res.str();
|
return res.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool loc_namespace_name_t::operator==(const loc_namespace_name_t &other) const {
|
||||||
|
if (other.size() != size()) return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size(); i++) {
|
||||||
|
if (other[i] != (*this)[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool loc_namespace_name_t::operator!=(const loc_namespace_name_t &other) const {
|
||||||
|
if (other.size() != size()) return true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size(); i++) {
|
||||||
|
if (other[i] == (*this)[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool namespace_name_t::operator==(const namespace_name_t &other) const {
|
bool namespace_name_t::operator==(const namespace_name_t &other) const {
|
||||||
if (other.size() != size()) return false;
|
if (other.size() != size()) return false;
|
||||||
@ -32,5 +61,16 @@ namespace ppc::lang {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace_name_t loc_namespace_name_t::strip_location() {
|
||||||
|
namespace_name_t res;
|
||||||
|
|
||||||
|
for (const auto &el : *this) {
|
||||||
|
res.push_back(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
throw (std::string)"Incorrect usage. Syntax: [src-dir] [project-name] [output|deps].";
|
throw (std::string)"Incorrect usage. Syntax: [src-dir] [project-name] [output|deps].";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string proj_path = (std::string)argv[0] + "/" + argv[1] + "/proj.txt";
|
std::string proj_path = (std::string)argv[0] + "/" + argv[1] + ".proj";
|
||||||
proj_name = argv[1];
|
proj_name = argv[1];
|
||||||
|
|
||||||
std::ifstream f { proj_path, std::ios_base::in };
|
std::ifstream f { proj_path, std::ios_base::in };
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
main
|
main
|
||||||
utils, compiler
|
utils, compiler
|
@ -24,6 +24,7 @@
|
|||||||
#include "utils/strings.hh"
|
#include "utils/strings.hh"
|
||||||
#include "compiler/treeifier/lexer.hh"
|
#include "compiler/treeifier/lexer.hh"
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
#include "compiler/treeifier/tokenizer.hh"
|
||||||
|
#include "compiler/treeifier/ast.hh"
|
||||||
#include "./opions.hh"
|
#include "./opions.hh"
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
@ -152,9 +153,10 @@ int main(int argc, const char *argv[]) {
|
|||||||
for (const auto &file : files) {
|
for (const auto &file : files) {
|
||||||
std::ifstream f { file, std::ios_base::in };
|
std::ifstream f { file, std::ios_base::in };
|
||||||
try {
|
try {
|
||||||
auto res = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
|
auto tokens = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
|
||||||
|
data::map_t ast;
|
||||||
for (auto tok : res) {
|
if (!ast::ast_ctx_t::parse(msg_stack, tokens, ast)) throw msg_stack.peek();
|
||||||
|
for (auto tok : tokens) {
|
||||||
if (tok.is_identifier()) std::cout << "Identifier: \t" << tok.identifier();
|
if (tok.is_identifier()) std::cout << "Identifier: \t" << tok.identifier();
|
||||||
if (tok.is_operator()) std::cout << "Operator: \t" << operator_stringify(tok._operator());
|
if (tok.is_operator()) std::cout << "Operator: \t" << operator_stringify(tok._operator());
|
||||||
if (tok.is_float_lit()) std::cout << "Float: \t" << tok.float_lit();
|
if (tok.is_float_lit()) std::cout << "Float: \t" << tok.float_lit();
|
||||||
|
@ -1,135 +1,165 @@
|
|||||||
#include "utils/data.hh"
|
#include "utils/data.hh"
|
||||||
|
|
||||||
bool ppc::data::value_t::is_null() const {
|
namespace ppc::data {
|
||||||
return type == type_t::Null;
|
bool value_t::is_null() const {
|
||||||
}
|
return type == type_t::Null;
|
||||||
bool ppc::data::value_t::is_map() const {
|
}
|
||||||
return type == type_t::Map;
|
bool value_t::is_map() const {
|
||||||
}
|
return type == type_t::Map;
|
||||||
bool ppc::data::value_t::is_array() const {
|
}
|
||||||
return type == type_t::Arr;
|
bool value_t::is_array() const {
|
||||||
}
|
return type == type_t::Arr;
|
||||||
bool ppc::data::value_t::is_number() const {
|
}
|
||||||
return type == type_t::Num;
|
bool value_t::is_number() const {
|
||||||
}
|
return type == type_t::Num;
|
||||||
bool ppc::data::value_t::is_string() const {
|
}
|
||||||
return type == type_t::Str;
|
bool value_t::is_string() const {
|
||||||
}
|
return type == type_t::Str;
|
||||||
bool ppc::data::value_t::is_bool() const {
|
}
|
||||||
return type == type_t::Bool;
|
bool value_t::is_bool() const {
|
||||||
}
|
return type == type_t::Bool;
|
||||||
|
}
|
||||||
|
|
||||||
bool ppc::data::value_t::array(ppc::data::array_t &out) const {
|
bool value_t::array(array_t &out) const {
|
||||||
if (is_array()) {
|
if (is_array()) {
|
||||||
out = *val.arr;
|
out = *val.arr;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
bool value_t::map(map_t &out) const {
|
||||||
}
|
if (is_map()) {
|
||||||
bool ppc::data::value_t::map(ppc::data::map_t &out) const {
|
out = *val.map;
|
||||||
if (is_map()) {
|
return true;
|
||||||
out = *val.map;
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
bool value_t::number(number_t &out) const {
|
||||||
}
|
if (is_number()) {
|
||||||
bool ppc::data::value_t::number(ppc::data::number_t &out) const {
|
out = val.num;
|
||||||
if (is_number()) {
|
return true;
|
||||||
out = val.num;
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
bool value_t::string(string_t &out) const {
|
||||||
}
|
if (is_string()) {
|
||||||
bool ppc::data::value_t::string(ppc::data::string_t &out) const {
|
out = *val.str;
|
||||||
if (is_string()) {
|
return true;
|
||||||
out = *val.str;
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
bool value_t::boolean(bool_t &out) const {
|
||||||
}
|
if (is_bool()) {
|
||||||
bool ppc::data::value_t::boolean(ppc::data::bool_t &out) const {
|
out = val.bl;
|
||||||
if (is_bool()) {
|
return true;
|
||||||
out = val.bl;
|
}
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ppc::data::array_t &ppc::data::value_t::array() const {
|
|
||||||
if (is_array()) return *val.arr;
|
|
||||||
else throw (std::string)"The value isn't an array.";
|
|
||||||
}
|
|
||||||
const ppc::data::map_t &ppc::data::value_t::map() const {
|
|
||||||
if (is_map()) return *val.map;
|
|
||||||
else throw (std::string)"The value isn't a map.";
|
|
||||||
}
|
|
||||||
ppc::data::number_t ppc::data::value_t::number() const {
|
|
||||||
if (is_number()) return val.num;
|
|
||||||
else throw (std::string)"The value isn't a number.";
|
|
||||||
}
|
|
||||||
const ppc::data::string_t &ppc::data::value_t::string() const {
|
|
||||||
if (is_string()) return *val.str;
|
|
||||||
else throw (std::string)"The value isn't a string.";
|
|
||||||
}
|
|
||||||
ppc::data::bool_t ppc::data::value_t::boolean() const {
|
|
||||||
if (is_bool()) return val.bl;
|
|
||||||
else throw (std::string)"The value isn't a bool.";
|
|
||||||
}
|
|
||||||
|
|
||||||
ppc::data::value_t::value_t() {
|
|
||||||
this->type = type_t::Null;
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(const ppc::data::array_t &val) {
|
|
||||||
this->type = type_t::Arr;
|
|
||||||
this->val.arr = new array_t(val);
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(const ppc::data::map_t &val) {
|
|
||||||
this->type = type_t::Map;
|
|
||||||
this->val.map = new map_t(val);
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(const ppc::data::string_t &val) {
|
|
||||||
this->type = type_t::Str;
|
|
||||||
this->val.str = new string_t(val);
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(ppc::data::bool_t val) {
|
|
||||||
this->type = type_t::Bool;
|
|
||||||
this->val.bl = val;
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(ppc::data::number_t val) {
|
|
||||||
this->type = type_t::Num;
|
|
||||||
this->val.num = val;
|
|
||||||
}
|
|
||||||
ppc::data::value_t::value_t(const ppc::data::value_t &other) {
|
|
||||||
type = other.type;
|
|
||||||
switch (other.type) {
|
|
||||||
case type_t::Map:
|
|
||||||
val.map = new map_t(*other.val.map);
|
|
||||||
break;
|
|
||||||
case type_t::Arr:
|
|
||||||
val.arr = new array_t(*other.val.arr);
|
|
||||||
break;
|
|
||||||
case type_t::Str:
|
|
||||||
val.str = new string_t(*other.val.str);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
val = other.val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
array_t &value_t::array() const {
|
||||||
|
if (is_array()) return *val.arr;
|
||||||
|
else throw (std::string)"The value isn't an array.";
|
||||||
}
|
}
|
||||||
}
|
map_t &value_t::map() const {
|
||||||
ppc::data::value_t::~value_t() {
|
if (is_map()) return *val.map;
|
||||||
switch (type) {
|
else throw (std::string)"The value isn't a map.";
|
||||||
case type_t::Map:
|
}
|
||||||
delete val.map;
|
number_t value_t::number() const {
|
||||||
break;
|
if (is_number()) return val.num;
|
||||||
case type_t::Arr:
|
else throw (std::string)"The value isn't a number.";
|
||||||
delete val.arr;
|
}
|
||||||
break;
|
string_t &value_t::string() const {
|
||||||
case type_t::Str:
|
if (is_string()) return *val.str;
|
||||||
delete val.str;
|
else throw (std::string)"The value isn't a string.";
|
||||||
break;
|
}
|
||||||
default:
|
bool_t value_t::boolean() const {
|
||||||
break;
|
if (is_bool()) return val.bl;
|
||||||
|
else throw (std::string)"The value isn't a bool.";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
value_t::value_t() {
|
||||||
|
this->type = type_t::Null;
|
||||||
|
}
|
||||||
|
value_t::value_t(const array_t &val) {
|
||||||
|
this->type = type_t::Arr;
|
||||||
|
this->val.arr = new array_t(val);
|
||||||
|
}
|
||||||
|
value_t::value_t(const map_t &val) {
|
||||||
|
this->type = type_t::Map;
|
||||||
|
this->val.map = new map_t(val);
|
||||||
|
}
|
||||||
|
value_t::value_t(const string_t &val) {
|
||||||
|
this->type = type_t::Str;
|
||||||
|
this->val.str = new string_t(val);
|
||||||
|
}
|
||||||
|
value_t::value_t(bool_t val) {
|
||||||
|
this->type = type_t::Bool;
|
||||||
|
this->val.bl = val;
|
||||||
|
}
|
||||||
|
value_t::value_t(number_t val) {
|
||||||
|
this->type = type_t::Num;
|
||||||
|
this->val.num = val;
|
||||||
|
}
|
||||||
|
value_t::value_t(const value_t &other) {
|
||||||
|
type = other.type;
|
||||||
|
switch (other.type) {
|
||||||
|
case type_t::Map:
|
||||||
|
val.map = new map_t(*other.val.map);
|
||||||
|
break;
|
||||||
|
case type_t::Arr:
|
||||||
|
val.arr = new array_t(*other.val.arr);
|
||||||
|
break;
|
||||||
|
case type_t::Str:
|
||||||
|
val.str = new string_t(*other.val.str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
val = other.val;
|
||||||
|
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) {
|
||||||
|
case type_t::Map:
|
||||||
|
delete val.map;
|
||||||
|
break;
|
||||||
|
case type_t::Arr:
|
||||||
|
delete val.arr;
|
||||||
|
break;
|
||||||
|
case type_t::Str:
|
||||||
|
delete val.str;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value_t::value_t(std::initializer_list<std::pair<std::string, value_t>> map):
|
||||||
|
value_t(map_t(map)) { }
|
||||||
|
|
||||||
|
value_t &value_t::operator=(const value_t &other) {
|
||||||
|
type = other.type;
|
||||||
|
switch (other.type) {
|
||||||
|
case type_t::Map:
|
||||||
|
val.map = new map_t(*other.val.map);
|
||||||
|
break;
|
||||||
|
case type_t::Arr:
|
||||||
|
val.arr = new array_t(*other.val.arr);
|
||||||
|
break;
|
||||||
|
case type_t::Str:
|
||||||
|
val.str = new string_t(*other.val.str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
val = other.val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -4,68 +4,70 @@
|
|||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
|
|
||||||
std::string messages::message_t::to_string() const {
|
namespace ppc::messages {
|
||||||
std::string loc_readable = location.to_string();
|
std::string message_t::to_string() const {
|
||||||
std::string level_readable;
|
std::string loc_readable = location.to_string();
|
||||||
|
std::string level_readable;
|
||||||
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case messages::message_t::DEBUG: level_readable = "debug"; break;
|
case message_t::DEBUG: level_readable = "debug"; break;
|
||||||
case messages::message_t::SUGGESTION: level_readable = "suggestion"; break;
|
case message_t::SUGGESTION: level_readable = "suggestion"; break;
|
||||||
case messages::message_t::INFO: level_readable = "info"; break;
|
case message_t::INFO: level_readable = "info"; break;
|
||||||
case messages::message_t::WARNING: level_readable = "warning"; break;
|
case message_t::WARNING: level_readable = "warning"; break;
|
||||||
case messages::message_t::ERROR: level_readable = "error"; break;
|
case message_t::ERROR: level_readable = "error"; break;
|
||||||
default: level_readable = "what?"; break;
|
default: level_readable = "what?"; break;
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream res { };
|
|
||||||
|
|
||||||
if (loc_readable.length()) res << loc_readable << ": ";
|
|
||||||
res << level_readable << ": " << content;
|
|
||||||
|
|
||||||
return res.str();
|
|
||||||
}
|
|
||||||
bool messages::message_t::is_severe() const {
|
|
||||||
return level > messages::message_t::WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool messages::msg_stack_t::is_failed() const {
|
|
||||||
for (const auto &msg : messages) {
|
|
||||||
if (msg.is_severe()) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void messages::msg_stack_t::print(std::ostream &output, messages::message_t::level_t threshold, bool color_output) const {
|
|
||||||
if (!messages.size()) return;
|
|
||||||
|
|
||||||
for (const auto &msg : messages) {
|
|
||||||
if (msg.level < threshold) continue;
|
|
||||||
|
|
||||||
std::string loc_readable = msg.location.to_string();
|
|
||||||
|
|
||||||
switch (msg.level) {
|
|
||||||
case messages::message_t::DEBUG:
|
|
||||||
output << (color_output ? "\e[38;5;8mdebug: " : "debug: ");
|
|
||||||
break;
|
|
||||||
case messages::message_t::SUGGESTION:
|
|
||||||
output << (color_output ? "\e[38;5;45msuggestion: " : "suggestion: ");
|
|
||||||
break;
|
|
||||||
case messages::message_t::INFO:
|
|
||||||
output << (color_output ? "\e[38;5;33minfo: ": "info: ");
|
|
||||||
break;
|
|
||||||
case messages::message_t::WARNING:
|
|
||||||
output << (color_output ? "\e[38;5;214mwarning: " : "warning: ");
|
|
||||||
break;
|
|
||||||
case messages::message_t::ERROR:
|
|
||||||
output << (color_output ? "\e[38;5;196merror: " : "error: ");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output << (color_output ? "\e[38;5;196mw\e[38;5;226mh\e[38;5;118ma\e[38;5;162mt\e[38;5;129m?\e[0m: " : "what?: ");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loc_readable.length()) output << loc_readable << ": ";
|
std::stringstream res { };
|
||||||
output << msg.content;
|
|
||||||
if (color_output) output << "\e[0m";
|
if (loc_readable.length()) res << loc_readable << ": ";
|
||||||
output << std::endl;
|
res << level_readable << ": " << content;
|
||||||
|
|
||||||
|
return res.str();
|
||||||
}
|
}
|
||||||
}
|
bool message_t::is_severe() const {
|
||||||
|
return level > message_t::WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool msg_stack_t::is_failed() const {
|
||||||
|
for (const auto &msg : messages) {
|
||||||
|
if (msg.is_severe()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void msg_stack_t::print(std::ostream &output, message_t::level_t threshold, bool color_output) const {
|
||||||
|
if (!messages.size()) return;
|
||||||
|
|
||||||
|
for (const auto &msg : messages) {
|
||||||
|
if (msg.level < threshold) continue;
|
||||||
|
|
||||||
|
std::string loc_readable = msg.location.to_string();
|
||||||
|
|
||||||
|
switch (msg.level) {
|
||||||
|
case message_t::DEBUG:
|
||||||
|
output << (color_output ? "\e[38;5;8mdebug: " : "debug: ");
|
||||||
|
break;
|
||||||
|
case message_t::SUGGESTION:
|
||||||
|
output << (color_output ? "\e[38;5;45msuggestion: " : "suggestion: ");
|
||||||
|
break;
|
||||||
|
case message_t::INFO:
|
||||||
|
output << (color_output ? "\e[38;5;33minfo: ": "info: ");
|
||||||
|
break;
|
||||||
|
case message_t::WARNING:
|
||||||
|
output << (color_output ? "\e[38;5;214mwarning: " : "warning: ");
|
||||||
|
break;
|
||||||
|
case message_t::ERROR:
|
||||||
|
output << (color_output ? "\e[38;5;196merror: " : "error: ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
output << (color_output ? "\e[38;5;196mw\e[38;5;226mh\e[38;5;118ma\e[38;5;162mt\e[38;5;129m?\e[0m: " : "what?: ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loc_readable.length()) output << loc_readable << ": ";
|
||||||
|
output << msg.content;
|
||||||
|
if (color_output) output << "\e[0m";
|
||||||
|
output << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user