From ee6c29bb7dbc14b9eb66faf52f248b80930a1455 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sun, 9 Oct 2022 14:18:38 +0300 Subject: [PATCH] feat: add namespace and import parsing --- .gitignore | 2 +- include/compiler/treeifier/ast.hh | 64 ++-- include/compiler/treeifier/ast/helper.hh | 94 ++++-- include/lang/common.hh | 18 +- include/utils/data.hh | 45 ++- include/utils/location.hh | 1 + include/utils/message.hh | 3 + scripts/common.mak | 8 +- src/{compiler/proj.txt => compiler.proj} | 2 +- src/compiler/treeifier/ast.cc | 45 ++- src/compiler/treeifier/ast/conv.cc | 80 +++++ src/compiler/treeifier/ast/parsers/glob.cc | 65 +++++ .../treeifier/{ => ast}/parsers/group.cc | 0 .../treeifier/ast/parsers/identifier.cc | 21 ++ src/compiler/treeifier/ast/parsers/nmsp.cc | 26 ++ src/compiler/treeifier/lexer.cc | 2 +- src/compiler/treeifier/parsers/glob.cc | 61 ---- src/{lang/proj.txt => lang.proj} | 0 src/lang/common.cc | 40 +++ src/lsproj.cc | 2 +- src/{main/proj.txt => main.proj} | 2 +- src/main/main.cc | 8 +- src/{utils/proj.txt => utils.proj} | 0 src/utils/data.cc | 276 ++++++++++-------- src/utils/message.cc | 124 ++++---- 25 files changed, 655 insertions(+), 334 deletions(-) rename src/{compiler/proj.txt => compiler.proj} (95%) create mode 100644 src/compiler/treeifier/ast/conv.cc create mode 100644 src/compiler/treeifier/ast/parsers/glob.cc rename src/compiler/treeifier/{ => ast}/parsers/group.cc (100%) create mode 100644 src/compiler/treeifier/ast/parsers/identifier.cc create mode 100644 src/compiler/treeifier/ast/parsers/nmsp.cc delete mode 100644 src/compiler/treeifier/parsers/glob.cc rename src/{lang/proj.txt => lang.proj} (100%) rename src/{main/proj.txt => main.proj} (95%) rename src/{utils/proj.txt => utils.proj} (100%) diff --git a/.gitignore b/.gitignore index f241371..df9f664 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,7 @@ !src/*/**/*.cc !src/*/**/*.h !src/*/**/*.hh -!src/*/proj.txt +!src/*.proj !src/lsproj.cc !scripts diff --git a/include/compiler/treeifier/ast.hh b/include/compiler/treeifier/ast.hh index 38f3b96..4eccdf1 100644 --- a/include/compiler/treeifier/ast.hh +++ b/include/compiler/treeifier/ast.hh @@ -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; - 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 parsers; - std::set groups; + std::unordered_map parsers; + std::set groups; public: msg_stack_t &messages; std::vector &tokens; - std::set imports; - located_t nmsp; + std::set 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 tokens): + ast_ctx_t &init() { + add_parser(glob_parser); + return *this; + } + + static bool parse(msg_stack_t &messages, std::vector &tokens, data::map_t &out); + + ast_ctx_t(msg_stack_t &messages, std::vector &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 &loc); + located_t 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); + } } \ No newline at end of file diff --git a/include/compiler/treeifier/ast/helper.hh b/include/compiler/treeifier/ast/helper.hh index e4c0193..08defde 100644 --- a/include/compiler/treeifier/ast/helper.hh +++ b/include/compiler/treeifier/ast/helper.hh @@ -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); - } - catch (messages::message_t msg) { - if (!silent) ctx.messages.push(msg); - return false; - } + + bool submit(bool inc_i = true) { + res_i = (i += inc_i); + return true; } - 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; } diff --git a/include/lang/common.hh b/include/lang/common.hh index 69a2137..2bb6186 100644 --- a/include/lang/common.hh +++ b/include/lang/common.hh @@ -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 segments): base(segments.begin(), segments.end()) { } }; + struct loc_namespace_name_t : public std::vector> { + using base = std::vector>; + + 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> 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); } } diff --git a/include/utils/data.hh b/include/utils/data.hh index 9f5b1cd..5ea2fc3 100644 --- a/include/utils/data.hh +++ b/include/utils/data.hh @@ -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> 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 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> vals) { + for (const auto &pair : vals) { + values.insert(pair); + } + } }; class array_t { @@ -87,9 +107,10 @@ namespace ppc::data { std::vector 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 &val): values(val) { } + array_t(std::initializer_list val): values(val) { } }; } \ No newline at end of file diff --git a/include/utils/location.hh b/include/utils/location.hh index 0257414..0ab706f 100644 --- a/include/utils/location.hh +++ b/include/utils/location.hh @@ -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; diff --git a/include/utils/message.hh b/include/utils/message.hh index cf3ac52..63a73b8 100644 --- a/include/utils/message.hh +++ b/include/utils/message.hh @@ -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; diff --git a/scripts/common.mak b/scripts/common.mak index 608e459..626748c 100644 --- a/scripts/common.mak +++ b/scripts/common.mak @@ -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 diff --git a/src/compiler/proj.txt b/src/compiler.proj similarity index 95% rename from src/compiler/proj.txt rename to src/compiler.proj index b181367..6fa4f42 100644 --- a/src/compiler/proj.txt +++ b/src/compiler.proj @@ -1,2 +1,2 @@ -compiler +compiler utils, lang \ No newline at end of file diff --git a/src/compiler/treeifier/ast.cc b/src/compiler/treeifier/ast.cc index 1805400..fadbca8 100644 --- a/src/compiler/treeifier/ast.cc +++ b/src/compiler/treeifier/ast.cc @@ -3,25 +3,44 @@ namespace ppc::comp::tree::ast { std::unordered_map 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 &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; + } + } } diff --git a/src/compiler/treeifier/ast/conv.cc b/src/compiler/treeifier/ast/conv.cc new file mode 100644 index 0000000..f323793 --- /dev/null +++ b/src/compiler/treeifier/ast/conv.cc @@ -0,0 +1,80 @@ +#include "compiler/treeifier/ast.hh" + +namespace ppc::comp::tree::ast::conv { + data::map_t identifier_to_map(const located_t &loc) { + return { + { "location", conv::loc_to_map(loc.location) }, + { "content", loc }, + { "$_name", identifier_parser.name() }, + }; + } + located_t 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; + } +} diff --git a/src/compiler/treeifier/ast/parsers/glob.cc b/src/compiler/treeifier/ast/parsers/glob.cc new file mode 100644 index 0000000..332ecea --- /dev/null +++ b/src/compiler/treeifier/ast/parsers/glob.cc @@ -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(); diff --git a/src/compiler/treeifier/parsers/group.cc b/src/compiler/treeifier/ast/parsers/group.cc similarity index 100% rename from src/compiler/treeifier/parsers/group.cc rename to src/compiler/treeifier/ast/parsers/group.cc diff --git a/src/compiler/treeifier/ast/parsers/identifier.cc b/src/compiler/treeifier/ast/parsers/identifier.cc new file mode 100644 index 0000000..b9b8557 --- /dev/null +++ b/src/compiler/treeifier/ast/parsers/identifier.cc @@ -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(); diff --git a/src/compiler/treeifier/ast/parsers/nmsp.cc b/src/compiler/treeifier/ast/parsers/nmsp.cc new file mode 100644 index 0000000..910ed7e --- /dev/null +++ b/src/compiler/treeifier/ast/parsers/nmsp.cc @@ -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(); diff --git a/src/compiler/treeifier/lexer.cc b/src/compiler/treeifier/lexer.cc index e13b2a0..4012dee 100644 --- a/src/compiler/treeifier/lexer.cc +++ b/src/compiler/treeifier/lexer.cc @@ -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; diff --git a/src/compiler/treeifier/parsers/glob.cc b/src/compiler/treeifier/parsers/glob.cc deleted file mode 100644 index e574e3e..0000000 --- a/src/compiler/treeifier/parsers/glob.cc +++ /dev/null @@ -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 &out) const { - tree_helper_t h(ctx, res_i); - located_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 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(); -} diff --git a/src/lang/proj.txt b/src/lang.proj similarity index 100% rename from src/lang/proj.txt rename to src/lang.proj diff --git a/src/lang/common.cc b/src/lang/common.cc index 99aa799..36f1e8a 100644 --- a/src/lang/common.cc +++ b/src/lang/common.cc @@ -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; @@ -13,6 +23,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; + } + } diff --git a/src/lsproj.cc b/src/lsproj.cc index 934dd33..e133779 100644 --- a/src/lsproj.cc +++ b/src/lsproj.cc @@ -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 }; diff --git a/src/main/proj.txt b/src/main.proj similarity index 95% rename from src/main/proj.txt rename to src/main.proj index 23e5243..dd1bfcc 100644 --- a/src/main/proj.txt +++ b/src/main.proj @@ -1,2 +1,2 @@ -main +main utils, compiler \ No newline at end of file diff --git a/src/main/main.cc b/src/main/main.cc index bb637ce..f9917ad 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -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(); diff --git a/src/utils/proj.txt b/src/utils.proj similarity index 100% rename from src/utils/proj.txt rename to src/utils.proj diff --git a/src/utils/data.cc b/src/utils/data.cc index 65b849b..f0d1f79 100644 --- a/src/utils/data.cc +++ b/src/utils/data.cc @@ -1,135 +1,165 @@ #include "utils/data.hh" -bool ppc::data::value_t::is_null() const { - return type == type_t::Null; -} -bool ppc::data::value_t::is_map() const { - return type == type_t::Map; -} -bool ppc::data::value_t::is_array() const { - return type == type_t::Arr; -} -bool ppc::data::value_t::is_number() const { - return type == type_t::Num; -} -bool ppc::data::value_t::is_string() const { - return type == type_t::Str; -} -bool ppc::data::value_t::is_bool() const { - return type == type_t::Bool; -} +namespace ppc::data { + bool value_t::is_null() const { + return type == type_t::Null; + } + bool value_t::is_map() const { + return type == type_t::Map; + } + bool value_t::is_array() const { + return type == type_t::Arr; + } + bool value_t::is_number() const { + return type == type_t::Num; + } + bool value_t::is_string() const { + return type == type_t::Str; + } + bool value_t::is_bool() const { + return type == type_t::Bool; + } -bool ppc::data::value_t::array(ppc::data::array_t &out) const { - if (is_array()) { - out = *val.arr; - return true; + bool value_t::array(array_t &out) const { + if (is_array()) { + out = *val.arr; + return true; + } + return false; } - return false; -} -bool ppc::data::value_t::map(ppc::data::map_t &out) const { - if (is_map()) { - out = *val.map; - return true; + bool value_t::map(map_t &out) const { + if (is_map()) { + out = *val.map; + return true; + } + return false; } - return false; -} -bool ppc::data::value_t::number(ppc::data::number_t &out) const { - if (is_number()) { - out = val.num; - return true; + bool value_t::number(number_t &out) const { + if (is_number()) { + out = val.num; + return true; + } + return false; } - return false; -} -bool ppc::data::value_t::string(ppc::data::string_t &out) const { - if (is_string()) { - out = *val.str; - return true; + bool value_t::string(string_t &out) const { + if (is_string()) { + out = *val.str; + return true; + } + return false; } - return false; -} -bool ppc::data::value_t::boolean(ppc::data::bool_t &out) const { - if (is_bool()) { - out = val.bl; - return true; + bool value_t::boolean(bool_t &out) const { + if (is_bool()) { + 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."; } -} -ppc::data::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; + map_t &value_t::map() const { + if (is_map()) return *val.map; + else throw (std::string)"The value isn't a map."; + } + number_t value_t::number() const { + if (is_number()) return val.num; + else throw (std::string)"The value isn't a number."; + } + string_t &value_t::string() const { + if (is_string()) return *val.str; + else throw (std::string)"The value isn't a string."; + } + bool_t value_t::boolean() const { + 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> 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; + } + +} diff --git a/src/utils/message.cc b/src/utils/message.cc index 8b49f57..61959ea 100644 --- a/src/utils/message.cc +++ b/src/utils/message.cc @@ -4,68 +4,70 @@ using namespace ppc; -std::string messages::message_t::to_string() const { - std::string loc_readable = location.to_string(); - std::string level_readable; +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; - 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; + switch (level) { + 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; } - if (loc_readable.length()) output << loc_readable << ": "; - output << msg.content; - if (color_output) output << "\e[0m"; - output << std::endl; + std::stringstream res { }; + + if (loc_readable.length()) res << loc_readable << ": "; + 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; + } + } +} \ No newline at end of file