feat: add namespace and import parsing

This commit is contained in:
TopchetoEU 2022-10-09 14:18:38 +03:00
parent 0a68529c3b
commit ee6c29bb7d
25 changed files with 655 additions and 334 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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);
}
} }

View File

@ -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;
} }

View File

@ -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);
} }
} }

View File

@ -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) { }
}; };
} }

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -1,2 +1,2 @@
compiler compiler
utils, lang utils, lang

View File

@ -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;
}
}
} }

View 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;
}
}

View 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();

View 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();

View 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();

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}
} }

View File

@ -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 };

View File

@ -1,2 +1,2 @@
main main
utils, compiler utils, compiler

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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;
}
}
}