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/*/**/*.h
|
||||
!src/*/**/*.hh
|
||||
!src/*/proj.txt
|
||||
!src/*.proj
|
||||
!src/lsproj.cc
|
||||
|
||||
!scripts
|
||||
|
@ -17,54 +17,71 @@ namespace ppc::comp::tree::ast {
|
||||
class 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 {
|
||||
private:
|
||||
using named_parser_t = std::pair<std::string, parser_t*>;
|
||||
|
||||
struct parser_proxy_t {
|
||||
private:
|
||||
ast_ctx_t &parent;
|
||||
ast_ctx_t *parent;
|
||||
public:
|
||||
parser_t &operator[](const std::string &name) const;
|
||||
parser_proxy_t(ast_ctx_t &parent): parent(parent) { }
|
||||
const parser_t &operator[](const std::string &name) const;
|
||||
parser_proxy_t(ast_ctx_t *parent): parent(parent) { }
|
||||
};
|
||||
|
||||
struct group_proxy_t {
|
||||
private:
|
||||
ast_ctx_t &parent;
|
||||
ast_ctx_t *parent;
|
||||
public:
|
||||
group_parser_t &operator[](const std::string &name) const;
|
||||
group_proxy_t(ast_ctx_t &parent): parent(parent) { }
|
||||
const group_parser_t &operator[](const std::string &name) const;
|
||||
group_proxy_t(ast_ctx_t *parent): parent(parent) { }
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, parser_t*> parsers;
|
||||
std::set<parser_t*> groups;
|
||||
std::unordered_map<std::string, const parser_t*> parsers;
|
||||
std::set<const parser_t*> groups;
|
||||
|
||||
public:
|
||||
msg_stack_t &messages;
|
||||
std::vector<token_t> &tokens;
|
||||
std::set<lang::namespace_name_t> imports;
|
||||
located_t<namespace_name_t> nmsp;
|
||||
std::set<loc_namespace_name_t> imports;
|
||||
loc_namespace_name_t nmsp;
|
||||
|
||||
void add_parser(std::string name, parser_t &parser);
|
||||
void add_parser(std::string name, group_parser_t &parser);
|
||||
void add_parser(const parser_t &parser);
|
||||
void add_parser(const group_parser_t &parser);
|
||||
|
||||
const parser_proxy_t parser;
|
||||
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),
|
||||
tokens(tokens),
|
||||
parser(*this),
|
||||
group(*this) { }
|
||||
parser(this),
|
||||
group(this) { }
|
||||
};
|
||||
|
||||
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;
|
||||
public:
|
||||
const std::string &name() const { return _name; }
|
||||
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);
|
||||
}
|
||||
|
||||
parser_t(const std::string &name): _name(name) { }
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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"
|
||||
|
||||
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 {
|
||||
struct tree_helper_t {
|
||||
private:
|
||||
@ -15,20 +21,6 @@ namespace ppc::comp::tree::ast {
|
||||
public:
|
||||
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 res = loc();
|
||||
res.start += res.length;
|
||||
@ -56,26 +48,22 @@ namespace ppc::comp::tree::ast {
|
||||
else return ctx.tokens[res_i].location.intersect(loc());
|
||||
}
|
||||
|
||||
bool parse(const parser_t &parser, data::map_t &out) {
|
||||
return parser(ctx, i, out);
|
||||
void err(std::string message) {
|
||||
throw message_t::error(message, loc());
|
||||
}
|
||||
bool try_parse(const parser_t &parser, data::map_t &out, bool silent = true) {
|
||||
try {
|
||||
return parser(ctx, i, out);
|
||||
|
||||
bool submit(bool inc_i = true) {
|
||||
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 {
|
||||
return parser(ctx, i, out);
|
||||
}
|
||||
catch (messages::message_t msg) {
|
||||
err = msg;
|
||||
return false;
|
||||
|
||||
bool ended() {
|
||||
return i == ctx.tokens.size();
|
||||
}
|
||||
|
||||
token_t &curr() {
|
||||
throw_ended();
|
||||
return ctx.tokens[i];
|
||||
}
|
||||
|
||||
bool try_advance() {
|
||||
@ -94,6 +82,48 @@ namespace ppc::comp::tree::ast {
|
||||
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) {
|
||||
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;
|
||||
|
||||
operator std::string() const { return to_string(); }
|
||||
std::string to_string() const;
|
||||
|
||||
namespace_name_t() { }
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -45,22 +45,26 @@ namespace ppc::data {
|
||||
bool string(string_t &out) const;
|
||||
bool boolean(bool_t &out) const;
|
||||
|
||||
const array_t &array() const;
|
||||
const map_t &map() const;
|
||||
array_t &array() const;
|
||||
map_t &map() const;
|
||||
number_t number() const;
|
||||
const string_t &string() const;
|
||||
string_t &string() 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(const array_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(const string_t &val);
|
||||
value_t(bool_t val);
|
||||
value_t(const value_t &other);
|
||||
|
||||
static value_t mk_arr();
|
||||
static value_t mk_map();
|
||||
};
|
||||
|
||||
|
||||
@ -68,18 +72,34 @@ namespace ppc::data {
|
||||
private:
|
||||
std::unordered_map<std::string, value_t> values;
|
||||
public:
|
||||
value_t &operator [](std::string name) {
|
||||
if (values.find(name) == values.end()) {
|
||||
values.emplace(name, value_t());
|
||||
value_t &operator [](std::string name){
|
||||
auto res = values.find(name);
|
||||
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(); }
|
||||
|
||||
auto begin() const { return values.begin(); }
|
||||
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 {
|
||||
@ -87,9 +107,10 @@ namespace ppc::data {
|
||||
std::vector<value_t> values;
|
||||
public:
|
||||
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 end() { return values.end(); }
|
||||
auto begin() const { return values.begin(); }
|
||||
auto end() const { return values.end(); }
|
||||
|
||||
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); }
|
||||
@ -97,5 +118,9 @@ namespace ppc::data {
|
||||
void remove(std::size_t i = 0) { values.erase(begin() + i); }
|
||||
|
||||
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::string filename;
|
||||
|
||||
operator std::string() const { return to_string(); }
|
||||
std::string to_string() const;
|
||||
location_t intersect(location_t other) const;
|
||||
|
||||
|
@ -23,6 +23,8 @@ namespace ppc::messages {
|
||||
location(loc) { }
|
||||
message_t() : message_t(DEBUG, "") { }
|
||||
|
||||
operator std::string() const { return to_string(); }
|
||||
|
||||
std::string to_string() const;
|
||||
bool is_severe() const;
|
||||
|
||||
@ -37,6 +39,7 @@ namespace ppc::messages {
|
||||
inline auto end() { return messages.end(); }
|
||||
|
||||
void push(const message_t &msg) { messages.push_back(msg); }
|
||||
const message_t &peek() { return messages.back(); }
|
||||
void clear() { messages.clear(); }
|
||||
|
||||
bool is_failed() const;
|
||||
|
@ -1,6 +1,8 @@
|
||||
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)
|
||||
|
||||
$(shell make -f scripts/lsproj.mak lsproj=$(lsproj) src=$(src) $(lsproj))
|
||||
|
||||
rwildcard=$(foreach d, $(wildcard $(1:=/*)),\
|
||||
$(call rwildcard,$d,$2)\
|
||||
$(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)/*/)))
|
||||
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))
|
||||
|
||||
ifneq ($(nolsproj),yes)
|
||||
$(shell make -f scripts/lsproj.mak lsproj=$(lsproj) src=$(src) $(lsproj))
|
||||
endif
|
||||
|
||||
.PHONY: build
|
||||
.PRECIOUS: $(bin)/tmp/%.o
|
||||
|
||||
|
@ -3,25 +3,44 @@
|
||||
namespace ppc::comp::tree::ast {
|
||||
std::unordered_map<std::string, group_parser_t> parsers;
|
||||
|
||||
parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
|
||||
auto it = parent.parsers.find(name);
|
||||
if (it == parent.parsers.end()) throw "The parser '" + name + "' doesn't exist.";
|
||||
const parser_t &ast_ctx_t::parser_proxy_t::operator[](const std::string &name) const {
|
||||
auto it = parent->parsers.find(name);
|
||||
if (it == parent->parsers.end()) throw "The parser '" + name + "' doesn't exist.";
|
||||
return *it->second;
|
||||
}
|
||||
group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
||||
parser_t *p = &parent.parser[name];
|
||||
if (parent.groups.find(p) == parent.groups.end()) throw "A parser '" + name + "' exists, but isn't a group.";
|
||||
return *(group_parser_t*)p;
|
||||
const group_parser_t &ast_ctx_t::group_proxy_t::operator[](const std::string &name) const {
|
||||
auto p = &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;
|
||||
}
|
||||
|
||||
void ast_ctx_t::add_parser(std::string name, parser_t &parser) {
|
||||
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
|
||||
parsers[name] = &parser;
|
||||
void ast_ctx_t::add_parser(const parser_t &parser) {
|
||||
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
|
||||
parsers[parser.name()] = &parser;
|
||||
}
|
||||
void ast_ctx_t::add_parser(std::string name, group_parser_t &parser) {
|
||||
if (parsers.find(name) != parsers.end()) throw "The parser '" + name + "' already exists.";
|
||||
parsers[name] = &parser;
|
||||
void ast_ctx_t::add_parser(const group_parser_t &parser) {
|
||||
if (parsers.find(parser.name()) != parsers.end()) throw "The parser '" + parser.name() + "' already exists.";
|
||||
parsers[parser.name()] = &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) {
|
||||
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 (op_i == 1 && 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"
|
||||
|
||||
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::stringstream res;
|
||||
|
||||
@ -14,6 +24,25 @@ namespace ppc::lang {
|
||||
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 {
|
||||
if (other.size() != size()) return false;
|
||||
|
||||
@ -32,5 +61,16 @@ namespace ppc::lang {
|
||||
|
||||
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].";
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
std::ifstream f { proj_path, std::ios_base::in };
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "utils/strings.hh"
|
||||
#include "compiler/treeifier/lexer.hh"
|
||||
#include "compiler/treeifier/tokenizer.hh"
|
||||
#include "compiler/treeifier/ast.hh"
|
||||
#include "./opions.hh"
|
||||
|
||||
using std::cout;
|
||||
@ -152,9 +153,10 @@ int main(int argc, const char *argv[]) {
|
||||
for (const auto &file : files) {
|
||||
std::ifstream f { file, std::ios_base::in };
|
||||
try {
|
||||
auto res = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
|
||||
|
||||
for (auto tok : res) {
|
||||
auto tokens = token_t::parse_many(msg_stack, lex::token_t::parse_file(msg_stack, file, f));
|
||||
data::map_t ast;
|
||||
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_operator()) std::cout << "Operator: \t" << operator_stringify(tok._operator());
|
||||
if (tok.is_float_lit()) std::cout << "Float: \t" << tok.float_lit();
|
||||
|
@ -1,105 +1,106 @@
|
||||
#include "utils/data.hh"
|
||||
|
||||
bool ppc::data::value_t::is_null() const {
|
||||
namespace ppc::data {
|
||||
bool value_t::is_null() const {
|
||||
return type == type_t::Null;
|
||||
}
|
||||
bool ppc::data::value_t::is_map() const {
|
||||
}
|
||||
bool value_t::is_map() const {
|
||||
return type == type_t::Map;
|
||||
}
|
||||
bool ppc::data::value_t::is_array() const {
|
||||
}
|
||||
bool value_t::is_array() const {
|
||||
return type == type_t::Arr;
|
||||
}
|
||||
bool ppc::data::value_t::is_number() const {
|
||||
}
|
||||
bool value_t::is_number() const {
|
||||
return type == type_t::Num;
|
||||
}
|
||||
bool ppc::data::value_t::is_string() const {
|
||||
}
|
||||
bool value_t::is_string() const {
|
||||
return type == type_t::Str;
|
||||
}
|
||||
bool ppc::data::value_t::is_bool() const {
|
||||
}
|
||||
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()) {
|
||||
out = *val.arr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ppc::data::value_t::map(ppc::data::map_t &out) const {
|
||||
}
|
||||
bool value_t::map(map_t &out) const {
|
||||
if (is_map()) {
|
||||
out = *val.map;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ppc::data::value_t::number(ppc::data::number_t &out) const {
|
||||
}
|
||||
bool value_t::number(number_t &out) const {
|
||||
if (is_number()) {
|
||||
out = val.num;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ppc::data::value_t::string(ppc::data::string_t &out) const {
|
||||
}
|
||||
bool value_t::string(string_t &out) const {
|
||||
if (is_string()) {
|
||||
out = *val.str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool ppc::data::value_t::boolean(ppc::data::bool_t &out) const {
|
||||
}
|
||||
bool value_t::boolean(bool_t &out) const {
|
||||
if (is_bool()) {
|
||||
out = val.bl;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const ppc::data::array_t &ppc::data::value_t::array() const {
|
||||
array_t &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 {
|
||||
}
|
||||
map_t &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 {
|
||||
}
|
||||
number_t 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 {
|
||||
}
|
||||
string_t &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 {
|
||||
}
|
||||
bool_t 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() {
|
||||
value_t::value_t() {
|
||||
this->type = type_t::Null;
|
||||
}
|
||||
ppc::data::value_t::value_t(const ppc::data::array_t &val) {
|
||||
}
|
||||
value_t::value_t(const 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) {
|
||||
}
|
||||
value_t::value_t(const 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) {
|
||||
}
|
||||
value_t::value_t(const 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) {
|
||||
}
|
||||
value_t::value_t(bool_t val) {
|
||||
this->type = type_t::Bool;
|
||||
this->val.bl = val;
|
||||
}
|
||||
ppc::data::value_t::value_t(ppc::data::number_t val) {
|
||||
}
|
||||
value_t::value_t(number_t val) {
|
||||
this->type = type_t::Num;
|
||||
this->val.num = val;
|
||||
}
|
||||
ppc::data::value_t::value_t(const ppc::data::value_t &other) {
|
||||
}
|
||||
value_t::value_t(const value_t &other) {
|
||||
type = other.type;
|
||||
switch (other.type) {
|
||||
case type_t::Map:
|
||||
@ -114,10 +115,16 @@ ppc::data::value_t::value_t(const ppc::data::value_t &other) {
|
||||
default:
|
||||
val = other.val;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
ppc::data::value_t::~value_t() {
|
||||
}
|
||||
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;
|
||||
@ -131,5 +138,28 @@ ppc::data::value_t::~value_t() {
|
||||
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,16 +4,17 @@
|
||||
|
||||
using namespace ppc;
|
||||
|
||||
std::string messages::message_t::to_string() const {
|
||||
namespace ppc::messages {
|
||||
std::string message_t::to_string() const {
|
||||
std::string loc_readable = location.to_string();
|
||||
std::string level_readable;
|
||||
|
||||
switch (level) {
|
||||
case messages::message_t::DEBUG: level_readable = "debug"; break;
|
||||
case messages::message_t::SUGGESTION: level_readable = "suggestion"; break;
|
||||
case messages::message_t::INFO: level_readable = "info"; break;
|
||||
case messages::message_t::WARNING: level_readable = "warning"; break;
|
||||
case messages::message_t::ERROR: level_readable = "error"; break;
|
||||
case message_t::DEBUG: level_readable = "debug"; break;
|
||||
case message_t::SUGGESTION: level_readable = "suggestion"; break;
|
||||
case message_t::INFO: level_readable = "info"; break;
|
||||
case message_t::WARNING: level_readable = "warning"; break;
|
||||
case message_t::ERROR: level_readable = "error"; break;
|
||||
default: level_readable = "what?"; break;
|
||||
}
|
||||
|
||||
@ -23,18 +24,18 @@ std::string messages::message_t::to_string() const {
|
||||
res << level_readable << ": " << content;
|
||||
|
||||
return res.str();
|
||||
}
|
||||
bool messages::message_t::is_severe() const {
|
||||
return level > messages::message_t::WARNING;
|
||||
}
|
||||
}
|
||||
bool message_t::is_severe() const {
|
||||
return level > message_t::WARNING;
|
||||
}
|
||||
|
||||
bool messages::msg_stack_t::is_failed() const {
|
||||
bool 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 {
|
||||
}
|
||||
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) {
|
||||
@ -43,19 +44,19 @@ void messages::msg_stack_t::print(std::ostream &output, messages::message_t::lev
|
||||
std::string loc_readable = msg.location.to_string();
|
||||
|
||||
switch (msg.level) {
|
||||
case messages::message_t::DEBUG:
|
||||
case message_t::DEBUG:
|
||||
output << (color_output ? "\e[38;5;8mdebug: " : "debug: ");
|
||||
break;
|
||||
case messages::message_t::SUGGESTION:
|
||||
case message_t::SUGGESTION:
|
||||
output << (color_output ? "\e[38;5;45msuggestion: " : "suggestion: ");
|
||||
break;
|
||||
case messages::message_t::INFO:
|
||||
case message_t::INFO:
|
||||
output << (color_output ? "\e[38;5;33minfo: ": "info: ");
|
||||
break;
|
||||
case messages::message_t::WARNING:
|
||||
case message_t::WARNING:
|
||||
output << (color_output ? "\e[38;5;214mwarning: " : "warning: ");
|
||||
break;
|
||||
case messages::message_t::ERROR:
|
||||
case message_t::ERROR:
|
||||
output << (color_output ? "\e[38;5;196merror: " : "error: ");
|
||||
break;
|
||||
default:
|
||||
@ -68,4 +69,5 @@ void messages::msg_stack_t::print(std::ostream &output, messages::message_t::lev
|
||||
if (color_output) output << "\e[0m";
|
||||
output << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user