AST reprogramming #5
11
.gitignore
vendored
11
.gitignore
vendored
@ -18,17 +18,20 @@
|
|||||||
!src/*/**/*.cc
|
!src/*/**/*.cc
|
||||||
!src/*/**/*.h
|
!src/*/**/*.h
|
||||||
!src/*/**/*.hh
|
!src/*/**/*.hh
|
||||||
!src/*.proj
|
!src/ls*.cc
|
||||||
!src/lsproj.cc
|
|
||||||
|
|
||||||
!scripts
|
!scripts
|
||||||
!scripts/common.mak
|
!scripts/common.mak
|
||||||
!scripts/lsproj.mak
|
!scripts/ls.mak
|
||||||
!scripts/install.bat
|
!scripts/install.bat
|
||||||
!scripts/uninstall.bat
|
!scripts/uninstall.bat
|
||||||
|
|
||||||
|
!deps
|
||||||
|
!deps/*
|
||||||
|
|
||||||
!LICENSE
|
!LICENSE
|
||||||
!CONTRIBUTING.md
|
!CONTRIBUTING.md
|
||||||
!Makefile
|
!Makefile
|
||||||
!README.md
|
!README.md
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.clang-format
|
20
Makefile
20
Makefile
@ -1,7 +1,7 @@
|
|||||||
export MAKEFLAGS += --silent -r -j
|
export MAKEFLAGS += --silent -r -j
|
||||||
export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile) -fdiagnostics-color=always
|
export flags=-std=c++17 -Wall -Wno-main -Wno-trigraphs -Wno-missing-braces -Wno-stringop-overflow -DPROFILE_$(profile) -fdiagnostics-color=always
|
||||||
export ldflags=-L$(bin)/$(profile) -Wl,-rpath=bin/$(profile)
|
export ldflags=-L$(bin)/$(profile) -Wl,-rpath=bin/$(profile)
|
||||||
export lib=ppc$(version-major)-
|
export lib=ppc-$(version-major).$(version-minor)-
|
||||||
export profile=release
|
export profile=release
|
||||||
|
|
||||||
############# SETTINGS ############
|
############# SETTINGS ############
|
||||||
@ -12,6 +12,7 @@ export output = ppc
|
|||||||
export mainmodule = main
|
export mainmodule = main
|
||||||
export version-major=0
|
export version-major=0
|
||||||
export version-minor=0
|
export version-minor=0
|
||||||
|
export version-build=1
|
||||||
###################################
|
###################################
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
@ -43,8 +44,8 @@ export exe=.exe
|
|||||||
export CC=gcc
|
export CC=gcc
|
||||||
export CXX=g++
|
export CXX=g++
|
||||||
|
|
||||||
export version-build=$(if $(wildcard build.version),$(shell type build.version),0)
|
# export version-build=$(if $(wildcard build.version),$(shell type build.version),0)
|
||||||
export binary = $(bin)/$(output)$(version-major)-windows.exe
|
export binary = $(bin)/$(output)-$(version-major).$(version-minor)-windows.exe
|
||||||
|
|
||||||
build: version
|
build: version
|
||||||
echo ======================== Compiling =========================
|
echo ======================== Compiling =========================
|
||||||
@ -60,11 +61,10 @@ cleartmp:
|
|||||||
.ONESHELL:
|
.ONESHELL:
|
||||||
install: build
|
install: build
|
||||||
powershell -Command "start-process cmd -verb runas -args '/K pushd %CD%&set bin=$(bin)&set output=$(output)&.\scripts\install.bat&exit'"
|
powershell -Command "start-process cmd -verb runas -args '/K pushd %CD%&set bin=$(bin)&set output=$(output)&.\scripts\install.bat&exit'"
|
||||||
# .\scripts\install.bat
|
|
||||||
uninstall:
|
uninstall:
|
||||||
.\scripts\uninstall.bat
|
.\scripts\uninstall.bat
|
||||||
version:
|
# version:
|
||||||
cmd /c "set /a $(version-build) + 1 > build.version"
|
# cmd /c "set /a $(version-build) + 1 > build.version"
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ export mkdir=mkdir -p $$1
|
|||||||
export rmdir=rm -rf $$1
|
export rmdir=rm -rf $$1
|
||||||
export echo=echo "$$1"
|
export echo=echo "$$1"
|
||||||
export so=.so
|
export so=.so
|
||||||
export version-build=$(if $(wildcard build.version),$(shell cat build.version),0)
|
# export version-build=$(if $(wildcard build.version),$(shell cat build.version),0)
|
||||||
export binary = $(bin)/$(output)$(version-major)-linux
|
export binary = $(bin)/$(output)-$(version-major).$(version-minor)-linux
|
||||||
|
|
||||||
build: version
|
build: version
|
||||||
echo ======================== Compiling =========================
|
echo ======================== Compiling =========================
|
||||||
@ -98,8 +98,8 @@ uninstall:
|
|||||||
echo Uninstalling ++C compiler from your system...
|
echo Uninstalling ++C compiler from your system...
|
||||||
sudo rm $(patsubst $(bin)/%.so,/usr/lib/%*.so,$(bin)/*.so)
|
sudo rm $(patsubst $(bin)/%.so,/usr/lib/%*.so,$(bin)/*.so)
|
||||||
sudo rm /usr/bin/$(output)
|
sudo rm /usr/bin/$(output)
|
||||||
version:
|
# version:
|
||||||
echo $$(($(version-build) + 1)) > build.version
|
# echo $$(($(version-build) + 1)) > build.version
|
||||||
|
|
||||||
leak: build
|
leak: build
|
||||||
echo ====================== Leak scanning =======================
|
echo ====================== Leak scanning =======================
|
||||||
|
0
src/utils.proj → deps/lang
vendored
0
src/utils.proj → deps/lang
vendored
2
deps/treeifier
vendored
Normal file
2
deps/treeifier
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
utils
|
||||||
|
lang
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef PPC_COMPILER_H
|
#ifndef PPC_COMPILER_H
|
||||||
#define PPC_COMPILER_H 1
|
#define PPC_COMPILER_H 1
|
||||||
|
|
||||||
#include "compiler/treeifier.hh"
|
#include "treeifier.hh"
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,11 +0,0 @@
|
|||||||
#ifndef PPC_TREEIFIER_H
|
|
||||||
#define PPC_TREEIFIER_H 1
|
|
||||||
|
|
||||||
#include "utils/message.hh"
|
|
||||||
|
|
||||||
namespace ppc::compiler {
|
|
||||||
// bool treeify(ppc::messages::msg_stack_t &msg_stack, const std::string &filename, const std::string &source, namespace_t *pout);
|
|
||||||
// bool treeify_file(const std::string &filename, ppc::messages::msg_stack_t &pmsg_stack, namespace_t *pout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,82 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
|
||||||
#include "utils/data.hh"
|
|
||||||
#include "lang/common.hh"
|
|
||||||
|
|
||||||
using namespace std::string_literals;
|
|
||||||
using namespace ppc;
|
|
||||||
using namespace ppc::lang;
|
|
||||||
using namespace ppc::messages;
|
|
||||||
|
|
||||||
namespace ppc::comp::tree::ast {
|
|
||||||
struct ast_ctx_t;
|
|
||||||
using parser_func_t = bool (ast_ctx_t &ctx, size_t &res_i, data::map_t &out);
|
|
||||||
using parser_t = parser_func_t*;
|
|
||||||
|
|
||||||
class group_t {
|
|
||||||
private:
|
|
||||||
std::map<lang::namespace_name_t, std::string> named_parsers;
|
|
||||||
std::set<std::string> unnamed_parsers;
|
|
||||||
std::map<std::string, parser_t> parsers;
|
|
||||||
public:
|
|
||||||
group_t &replace(const std::string &name, parser_t parser);
|
|
||||||
group_t &add(const std::string &name, parser_t parser);
|
|
||||||
group_t &add(const std::string &name, const lang::namespace_name_t &identifier, parser_t parser);
|
|
||||||
|
|
||||||
bool operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ast_ctx_t {
|
|
||||||
private:
|
|
||||||
std::unordered_map<std::string, group_t> groups;
|
|
||||||
public:
|
|
||||||
msg_stack_t &messages;
|
|
||||||
std::vector<token_t> &tokens;
|
|
||||||
std::set<loc_namespace_name_t> imports;
|
|
||||||
loc_namespace_name_t nmsp;
|
|
||||||
|
|
||||||
ast_ctx_t &operator=(const ast_ctx_t &other) = delete;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool parse(const T &parser, size_t &i, data::map_t &out) {
|
|
||||||
return parser(*this, i, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
group_t &group(const std::string &name);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
static data::map_t parse(const T &glob, msg_stack_t &messages, std::vector<token_t> &tokens) {
|
|
||||||
ast_ctx_t ctx(messages, tokens);
|
|
||||||
data::map_t res;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
if (!ctx.parse(glob, i, res)) throw message_t::error("Failed to compile.");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens);
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
data::string_t loc_to_map(const location_t &loc);
|
|
||||||
location_t map_to_loc(const data::string_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
parser_func_t parse_glob, parse_nmsp, parse_identifier, parse_type, parse_exp, parse_stat_exp;
|
|
||||||
parser_func_t parse_func, parse_field, parse_export, parse_struct;
|
|
||||||
parser_func_t parse_if, parse_while, parse_return, parse_break, parse_continue, parse_stat_comp;
|
|
||||||
parser_func_t parse_exp_var, parse_exp_str_lit, parse_exp_int_lit, parse_exp_float_lit;
|
|
||||||
}
|
|
@ -4,29 +4,29 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ppc::lang {
|
namespace ppc::lang {
|
||||||
struct namespace_name_t : public std::vector<std::string> {
|
struct nmsp_t: public std::vector<std::string> {
|
||||||
using base = std::vector<std::string>;
|
using base = std::vector<std::string>;
|
||||||
|
|
||||||
int compare(const namespace_name_t &other) const;
|
int compare(const nmsp_t &other) const;
|
||||||
|
|
||||||
bool operator==(const namespace_name_t &other) const { return compare(other) == 0; }
|
bool operator==(const nmsp_t &other) const { return compare(other) == 0; }
|
||||||
bool operator!=(const namespace_name_t &other) const { return compare(other) != 0; }
|
bool operator!=(const nmsp_t &other) const { return compare(other) != 0; }
|
||||||
bool operator<(const namespace_name_t &other) const { return compare(other) < 0; }
|
bool operator<(const nmsp_t &other) const { return compare(other) < 0; }
|
||||||
bool operator<=(const namespace_name_t &other) const { return compare(other) <= 0; }
|
bool operator<=(const nmsp_t &other) const { return compare(other) <= 0; }
|
||||||
bool operator>(const namespace_name_t &other) const { return compare(other) > 0; }
|
bool operator>(const nmsp_t &other) const { return compare(other) > 0; }
|
||||||
bool operator>=(const namespace_name_t &other) const { return compare(other) >= 0; }
|
bool operator>=(const nmsp_t &other) const { return compare(other) >= 0; }
|
||||||
|
|
||||||
operator std::string() const { return to_string(); }
|
operator std::string() const { return to_string(); }
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
namespace_name_t() { }
|
nmsp_t() { }
|
||||||
namespace_name_t(std::initializer_list<std::string> segments): base(segments.begin(), segments.end()) { }
|
nmsp_t(std::initializer_list<std::string> segments): base(segments.begin(), segments.end()) { }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct std::hash<ppc::lang::namespace_name_t> {
|
struct std::hash<ppc::lang::nmsp_t> {
|
||||||
std::size_t operator()(const ppc::lang::namespace_name_t& k) const {
|
std::size_t operator()(const ppc::lang::nmsp_t& k) const {
|
||||||
size_t res = 0;
|
size_t res = 0;
|
||||||
|
|
||||||
for (auto &el : k) {
|
for (auto &el : k) {
|
||||||
@ -41,55 +41,48 @@ struct std::hash<ppc::lang::namespace_name_t> {
|
|||||||
#include "utils/location.hh"
|
#include "utils/location.hh"
|
||||||
|
|
||||||
namespace ppc::lang {
|
namespace ppc::lang {
|
||||||
template <class T>
|
template <class ParserT>
|
||||||
struct located_t : T {
|
struct located_t: ParserT {
|
||||||
location_t location;
|
location_t location;
|
||||||
|
|
||||||
located_t(location_t loc, const T &val): T(val), location(loc) { }
|
located_t(location_t loc, const ParserT &val): ParserT(val), location(loc) { }
|
||||||
located_t(const T &val): T(val), location(location_t::NONE) { }
|
located_t(const ParserT &val): ParserT(val), location(location_t::NONE) { }
|
||||||
located_t() { }
|
located_t() { }
|
||||||
};
|
};
|
||||||
template <class T>
|
|
||||||
struct slocated_t {
|
|
||||||
T value;
|
|
||||||
location_t location;
|
|
||||||
|
|
||||||
bool operator ==(const slocated_t<T> &other) {
|
struct loc_nmsp_t: public std::vector<located_t<std::string>> {
|
||||||
return value == other.value && location == other.location;
|
|
||||||
}
|
|
||||||
bool operator !=(const slocated_t<T> &other) {
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
slocated_t(location_t loc, const T &val): value(val), location(loc) { }
|
|
||||||
slocated_t(const T &val): value(val), location(location_t::NONE) { }
|
|
||||||
slocated_t() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct loc_namespace_name_t : public std::vector<located_t<std::string>> {
|
|
||||||
using base = std::vector<located_t<std::string>>;
|
using base = std::vector<located_t<std::string>>;
|
||||||
|
|
||||||
int compare(const loc_namespace_name_t &other) const;
|
int compare(const loc_nmsp_t &other) const;
|
||||||
|
|
||||||
bool operator==(const loc_namespace_name_t &other) const { return compare(other) == 0; }
|
bool operator==(const loc_nmsp_t &other) const { return compare(other) == 0; }
|
||||||
bool operator!=(const loc_namespace_name_t &other) const { return compare(other) != 0; }
|
bool operator!=(const loc_nmsp_t &other) const { return compare(other) != 0; }
|
||||||
bool operator<(const loc_namespace_name_t &other) const { return compare(other) < 0; }
|
bool operator<(const loc_nmsp_t &other) const { return compare(other) < 0; }
|
||||||
bool operator<=(const loc_namespace_name_t &other) const { return compare(other) <= 0; }
|
bool operator<=(const loc_nmsp_t &other) const { return compare(other) <= 0; }
|
||||||
bool operator>(const loc_namespace_name_t &other) const { return compare(other) > 0; }
|
bool operator>(const loc_nmsp_t &other) const { return compare(other) > 0; }
|
||||||
bool operator>=(const loc_namespace_name_t &other) const { return compare(other) >= 0; }
|
bool operator>=(const loc_nmsp_t &other) const { return compare(other) >= 0; }
|
||||||
|
|
||||||
namespace_name_t strip_location() const;
|
nmsp_t strip_location() const;
|
||||||
|
|
||||||
operator std::string() const { return to_string(); }
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
loc_namespace_name_t() { }
|
operator nmsp_t() const { return strip_location(); }
|
||||||
loc_namespace_name_t(std::initializer_list<located_t<std::string>> segments): base(segments.begin(), segments.end()) { }
|
operator std::string() const { return to_string(); }
|
||||||
|
|
||||||
|
loc_nmsp_t() { }
|
||||||
|
loc_nmsp_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);
|
template <class SetT>
|
||||||
inline bool is_identifier_valid(const std::string &name) {
|
bool resolve_name(const SetT &defs, const nmsp_t &src, const nmsp_t &target) {
|
||||||
messages::msg_stack_t ms;
|
if (src == target) return true;
|
||||||
return is_identifier_valid(ms, { }, name);
|
|
||||||
|
for (auto it : defs) {
|
||||||
|
nmsp_t val = (nmsp_t)(it);
|
||||||
|
val.insert(val.end(), src.begin(), src.end());
|
||||||
|
|
||||||
|
if (val == target) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,162 +0,0 @@
|
|||||||
#include <set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include "lang/common.hh"
|
|
||||||
|
|
||||||
namespace ppc::lang {
|
|
||||||
struct type_t {
|
|
||||||
namespace_name_t name;
|
|
||||||
size_t ptr_n;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct statement_t {
|
|
||||||
private:
|
|
||||||
enum kind_t {
|
|
||||||
CALL,
|
|
||||||
STACK,
|
|
||||||
RETURN,
|
|
||||||
} kind;
|
|
||||||
union val_t {
|
|
||||||
namespace_name_t *call;
|
|
||||||
int64_t stack;
|
|
||||||
} val;
|
|
||||||
|
|
||||||
~statement_t();
|
|
||||||
|
|
||||||
statement_t(kind_t kind, val_t val) {
|
|
||||||
this->kind = kind;
|
|
||||||
this->val = val;
|
|
||||||
}
|
|
||||||
statement_t(kind_t kind) {
|
|
||||||
this->kind = kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool is_call() const { return kind == CALL; }
|
|
||||||
bool is_stack() const { return kind == STACK; }
|
|
||||||
bool is_return() const { return kind == RETURN; }
|
|
||||||
|
|
||||||
auto &call() const {
|
|
||||||
if (!is_call()) throw (std::string)"Statement is not a call.";
|
|
||||||
return val.call;
|
|
||||||
}
|
|
||||||
auto stack() const {
|
|
||||||
if (!is_call()) throw (std::string)"Statement is not a stack.";
|
|
||||||
return val.stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
static statement_t call(const namespace_name_t &func);
|
|
||||||
static statement_t stack(int64_t stack);
|
|
||||||
static statement_t ret();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct field_t {
|
|
||||||
type_t type;
|
|
||||||
};
|
|
||||||
struct struct_t {
|
|
||||||
std::unordered_map<std::string, type_t> fields;
|
|
||||||
};
|
|
||||||
struct function_t {
|
|
||||||
std::unordered_map<std::string, type_t> args;
|
|
||||||
type_t type;
|
|
||||||
|
|
||||||
std::string get_signature();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct definition_t {
|
|
||||||
private:
|
|
||||||
enum {
|
|
||||||
FUNCTION,
|
|
||||||
STRUCT,
|
|
||||||
FIELD,
|
|
||||||
} kind;
|
|
||||||
union {
|
|
||||||
field_t *field;
|
|
||||||
struct_t *str;
|
|
||||||
function_t *func;
|
|
||||||
} val;
|
|
||||||
|
|
||||||
public:
|
|
||||||
~definition_t();
|
|
||||||
definition_t(field_t val);
|
|
||||||
definition_t(struct_t val);
|
|
||||||
definition_t(function_t val);
|
|
||||||
definition_t(const definition_t &other);
|
|
||||||
|
|
||||||
bool is_func() const { return kind == FUNCTION; }
|
|
||||||
bool is_struct() const { return kind == STRUCT; }
|
|
||||||
bool is_field() const { return kind == FIELD; }
|
|
||||||
|
|
||||||
function_t &get_func();
|
|
||||||
struct_t &get_struct();
|
|
||||||
field_t &get_field();
|
|
||||||
|
|
||||||
const function_t &get_func() const { return ((definition_t&)*this).get_func(); }
|
|
||||||
const struct_t &get_struct() const { return ((definition_t&)*this).get_struct(); }
|
|
||||||
const field_t &get_field() const { return ((definition_t&)*this).get_field(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct module_t {
|
|
||||||
private:
|
|
||||||
using fields_t = std::unordered_map<namespace_name_t, field_t>;
|
|
||||||
using structs_t = std::unordered_map<namespace_name_t, struct_t>;
|
|
||||||
using funcs_t = std::unordered_map<namespace_name_t, function_t>;
|
|
||||||
struct resolve_res_t {
|
|
||||||
namespace_name_t name;
|
|
||||||
definition_t def;
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
fields_t fields;
|
|
||||||
structs_t structs;
|
|
||||||
funcs_t funcs;
|
|
||||||
|
|
||||||
const definition_t &def(namespace_name_t name);
|
|
||||||
void add_def(namespace_name_t name, const definition_t &def) {
|
|
||||||
if (def.is_field()) fields.emplace(name, def.get_field());
|
|
||||||
if (def.is_func()) funcs.emplace(name, def.get_func());
|
|
||||||
if (def.is_struct()) structs.emplace(name, def.get_struct());
|
|
||||||
}
|
|
||||||
bool exists(namespace_name_t name) {
|
|
||||||
return
|
|
||||||
fields.find(name) != fields.end() ||
|
|
||||||
structs.find(name) != structs.end() ||
|
|
||||||
funcs.find(name) != funcs.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct resolve_res_t {
|
|
||||||
namespace_name_t name;
|
|
||||||
T value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool resolve_name(
|
|
||||||
const std::vector<namespace_name_t> &names, const std::set<namespace_name_t> &imports,
|
|
||||||
const namespace_name_t &name, namespace_name_t &res
|
|
||||||
);
|
|
||||||
|
|
||||||
template <class MapT>
|
|
||||||
bool resolve_name_map(
|
|
||||||
const MapT &defs, const std::set<namespace_name_t> &imports,
|
|
||||||
const namespace_name_t &name, namespace_name_t &res
|
|
||||||
) {
|
|
||||||
std::vector<namespace_name_t> names;
|
|
||||||
for (auto &it : defs) {
|
|
||||||
const namespace_name_t &val = it.first;
|
|
||||||
names.push_back(val);
|
|
||||||
}
|
|
||||||
return resolve_name(names, imports, name, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class MapT>
|
|
||||||
bool resolve(
|
|
||||||
const MapT &defs, const std::set<namespace_name_t> &imports,
|
|
||||||
const namespace_name_t &name, typename MapT::iterator &res
|
|
||||||
) {
|
|
||||||
if (resolve_name_map(defs, imports, name, res.name)) {
|
|
||||||
res.value = defs.find(res.name)->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,13 @@
|
|||||||
#ifndef PPC_H
|
#ifndef PPC_H
|
||||||
#define PPC_H 1
|
#define PPC_H 1
|
||||||
|
|
||||||
#include "compiler.h"
|
#include "lang/version.hh"
|
||||||
|
namespace ppc {
|
||||||
static const int VERSION_MAJOR = PPC_VERSION_MAJOR;
|
static const version_t VERSION(
|
||||||
static const int VERSION_MINOR = PPC_VERSION_MINOR;
|
PPC_VERSION_MAJOR,
|
||||||
static const int VERSION_BUILD = PPC_VERSION_BUILD;
|
PPC_VERSION_MINOR,
|
||||||
|
PPC_VERSION_BUILD
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
43
include/treeifier/constr.hh
Normal file
43
include/treeifier/constr.hh
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/message.hh"
|
||||||
|
#include "lang/common.hh"
|
||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
namespace ppc::tree {
|
||||||
|
using namespace ppc;
|
||||||
|
using namespace ppc::lang;
|
||||||
|
using namespace ppc::messages;
|
||||||
|
|
||||||
|
struct parse_ctx_t {
|
||||||
|
public:
|
||||||
|
msg_stack_t &messages;
|
||||||
|
std::vector<token_t> &tokens;
|
||||||
|
loc_nmsp_t nmsp;
|
||||||
|
|
||||||
|
parse_ctx_t &operator=(const parse_ctx_t &other) = delete;
|
||||||
|
parse_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace parse {
|
||||||
|
bool parse_identifier(parse_ctx_t &ctx, size_t &res_i, located_t<std::string> &out);
|
||||||
|
bool parse_nmsp(parse_ctx_t &ctx, size_t &res_i, loc_nmsp_t &out);
|
||||||
|
bool parse_nmsp_id(parse_ctx_t &ctx, size_t &res_i, std::set<nmsp_t> imports, nmsp_t nmsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// parser_func_t parse_glob, parse_nmsp, parse_identifier, parse_type, parse_exp, parse_stat_exp;
|
||||||
|
// parser_func_t parse_func, parse_field, parse_export, parse_struct;
|
||||||
|
// parser_func_t parse_if, parse_while, parse_return, parse_break, parse_continue, parse_stat_comp;
|
||||||
|
// parser_func_t parse_exp_var, parse_exp_str_lit, parse_exp_int_lit, parse_exp_float_lit;
|
||||||
|
}
|
40
include/treeifier/constructs/glob.hh
Normal file
40
include/treeifier/constructs/glob.hh
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include "lang/common.hh"
|
||||||
|
#include "utils/message.hh"
|
||||||
|
|
||||||
|
#ifdef PROFILE_debug
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ppc::tree::constr {
|
||||||
|
using namespace ppc::lang;
|
||||||
|
using namespace ppc::messages;
|
||||||
|
|
||||||
|
struct global_t;
|
||||||
|
|
||||||
|
struct definition_t {
|
||||||
|
virtual std::string name() const = 0;
|
||||||
|
|
||||||
|
virtual bool verify(msg_stack_t &msg_stack, global_t &glob) const { return true; }
|
||||||
|
virtual bool simplify(global_t &glob) const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct global_t {
|
||||||
|
loc_nmsp_t nmsp;
|
||||||
|
std::vector<std::unique_ptr<definition_t>> defs;
|
||||||
|
std::vector<loc_nmsp_t> imports;
|
||||||
|
|
||||||
|
#ifdef PROFILE_debug
|
||||||
|
void print() const {
|
||||||
|
std::cout << "Namespace: " << nmsp.to_string() << "\n";
|
||||||
|
std::cout << "Imports:\n";
|
||||||
|
for (auto &imp : imports) {
|
||||||
|
std::cout << " - " << imp.to_string() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
#include "utils/location.hh"
|
#include "utils/location.hh"
|
||||||
#include "utils/message.hh"
|
#include "utils/message.hh"
|
||||||
|
|
||||||
namespace ppc::comp::tree::lex {
|
namespace ppc::tree::lex {
|
||||||
struct token_t {
|
struct token_t {
|
||||||
enum kind_t {
|
enum kind_t {
|
||||||
NONE,
|
NONE,
|
13
include/treeifier/parsers/definition.hh
Normal file
13
include/treeifier/parsers/definition.hh
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lang/common.hh"
|
||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include "treeifier/constructs/glob.hh"
|
||||||
|
|
||||||
|
namespace ppc::tree::parse {
|
||||||
|
class definition_parser_t {
|
||||||
|
public:
|
||||||
|
virtual bool operator()(parse_ctx_t &ctx, size_t &res_i, constr::definition_t &res) const = 0;
|
||||||
|
};
|
||||||
|
}
|
16
include/treeifier/parsers/glob.hh
Normal file
16
include/treeifier/parsers/glob.hh
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lang/common.hh"
|
||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include "treeifier/constructs/glob.hh"
|
||||||
|
#include "treeifier/parsers/inspoint.hh"
|
||||||
|
|
||||||
|
namespace ppc::tree::parse {
|
||||||
|
using namespace constr;
|
||||||
|
|
||||||
|
class glob_parser_t {
|
||||||
|
public:
|
||||||
|
bool operator()(parse_ctx_t &ctx, global_t &out) const;
|
||||||
|
};
|
||||||
|
}
|
@ -1,15 +1,11 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
#pragma once
|
||||||
|
|
||||||
using namespace ppc;
|
#include "treeifier/constr.hh"
|
||||||
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::tree::parse {
|
||||||
struct tree_helper_t {
|
struct helper_t {
|
||||||
private:
|
private:
|
||||||
ast_ctx_t &ctx;
|
parse_ctx_t &ctx;
|
||||||
size_t &res_i;
|
size_t &res_i;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -104,53 +100,25 @@ namespace ppc::comp::tree::ast {
|
|||||||
throw_ended(reason);
|
throw_ended(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class ParserT, class ...ArgsT>
|
||||||
bool push_parse(const T &parser, data::array_t &out) {
|
bool parse(const ParserT &parser, ArgsT &...args) {
|
||||||
data::map_t res;
|
return parser(ctx, i, args...);
|
||||||
if (parse(parser, res)) {
|
|
||||||
out.push_back(res);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class ParserT, class ...ArgsT>
|
||||||
bool parse(const T &parser, data::map_t &out) {
|
void force_parse(const ParserT &parser, std::string message, ArgsT &...args) {
|
||||||
return ctx.parse(parser, i, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void force_push_parse(const T &parser, std::string message, data::array_t &out) {
|
|
||||||
throw_ended(message);
|
throw_ended(message);
|
||||||
bool success;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
success = push_parse(parser, out);
|
if (!parser(ctx, i, args...)) err(message);
|
||||||
}
|
}
|
||||||
catch (const message_t &msg) {
|
catch (const message_t &msg) {
|
||||||
ctx.messages.push(msg);
|
ctx.messages.push(msg);
|
||||||
success = false;
|
err(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) err(message);
|
|
||||||
}
|
|
||||||
template <class T>
|
|
||||||
void force_parse(const T &parser, std::string message, data::map_t &out) {
|
|
||||||
throw_ended(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) {
|
helper_t(parse_ctx_t &ctx, size_t &i): ctx(ctx), res_i(i) {
|
||||||
this->i = i;
|
this->i = i;
|
||||||
}
|
}
|
||||||
};
|
};
|
52
include/treeifier/parsers/inspoint.hh
Normal file
52
include/treeifier/parsers/inspoint.hh
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include "treeifier/parsers/helper.hh"
|
||||||
|
|
||||||
|
#ifdef PROFILE_debug
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ppc::tree::parse {
|
||||||
|
|
||||||
|
struct named_t {
|
||||||
|
virtual std::string name() = 0;
|
||||||
|
virtual ~named_t() = default;
|
||||||
|
|
||||||
|
#ifdef PROFILE_debug
|
||||||
|
virtual void print() { std::cout << "(" << name() << ")"; }
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class ParserT, class ResT>
|
||||||
|
class inspoint_t {
|
||||||
|
private:
|
||||||
|
std::map<std::string, std::unique_ptr<ParserT>> parsers;
|
||||||
|
public:
|
||||||
|
inspoint_t<ParserT, ResT> &add(const ParserT &parser, bool replace = false) {
|
||||||
|
const std::string &name = parser.name();
|
||||||
|
auto it = parsers.find(name);
|
||||||
|
if (it != parsers.end()) {
|
||||||
|
if (!replace) throw "The parser '" + name + "' is already in the group.";
|
||||||
|
it->second = std::make_unique(parser);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parsers.emplace(name, std::make_unique(parser));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(ppc::tree::parse_ctx_t &ctx, size_t &i, std::unique_ptr<ResT> &out) const override {
|
||||||
|
helper_t h(ctx, i);
|
||||||
|
|
||||||
|
if (h.ended()) return false;
|
||||||
|
|
||||||
|
for (std::pair<std::string, std::unique_ptr<ParserT>> &pair : parsers) {
|
||||||
|
if (pair.second(ctx, i, out)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include "utils/location.hh"
|
#include "utils/location.hh"
|
||||||
#include "utils/message.hh"
|
#include "utils/message.hh"
|
||||||
#include "compiler/treeifier/lexer.hh"
|
#include "treeifier/lexer.hh"
|
||||||
|
|
||||||
namespace ppc::comp::tree {
|
namespace ppc::tree {
|
||||||
enum operator_t {
|
enum operator_t {
|
||||||
NONE,
|
NONE,
|
||||||
|
|
@ -116,5 +116,5 @@ namespace ppc::data {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class array_t : public std::vector<value_t> { };
|
class array_t: public std::vector<value_t> { };
|
||||||
}
|
}
|
@ -7,8 +7,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace ppc::threading {
|
namespace ppc::threading {
|
||||||
template <class T>
|
template <class ParserT>
|
||||||
using thread_func_t = int (THREAD *)(T *data);
|
using thread_func_t = int (THREAD *)(ParserT *data);
|
||||||
using empty_thread_func_t = int (THREAD *)();
|
using empty_thread_func_t = int (THREAD *)();
|
||||||
|
|
||||||
struct thread_t {
|
struct thread_t {
|
||||||
@ -20,13 +20,13 @@ namespace ppc::threading {
|
|||||||
int join() const;
|
int join() const;
|
||||||
|
|
||||||
thread_t(void *handle) { this->handle = handle; }
|
thread_t(void *handle) { this->handle = handle; }
|
||||||
template <class T>
|
template <class ParserT>
|
||||||
inline static thread_t start(thread_func_t<T> func, const T &args) {
|
inline static thread_t start(thread_func_t<ParserT> func, const ParserT &args) {
|
||||||
T _args = args;
|
ParserT _args = args;
|
||||||
return start_impl((void*)func, &_args);
|
return start_impl((void*)func, &_args);
|
||||||
}
|
}
|
||||||
template <class T>
|
template <class ParserT>
|
||||||
inline static thread_t start(thread_func_t<T> func, T &args) {
|
inline static thread_t start(thread_func_t<ParserT> func, ParserT &args) {
|
||||||
return start_impl((void*)func, &args);
|
return start_impl((void*)func, &args);
|
||||||
}
|
}
|
||||||
inline static thread_t start(empty_thread_func_t func) {
|
inline static thread_t start(empty_thread_func_t func) {
|
||||||
|
@ -1,34 +1,19 @@
|
|||||||
export lsproj = $(bin)/lsproj$(exe)
|
export lsdep = $(bin)/lsdep$(exe)
|
||||||
|
export lsinc = $(bin)/lsinc$(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))
|
$(shell make -f scripts/ls.mak lsinc=$(lsinc) lsdep=$(lsdep) src=$(src) "flags=$(flags)" all)
|
||||||
|
|
||||||
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)\
|
||||||
)
|
)
|
||||||
|
|
||||||
uniq=$(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
deps=$(shell $(lsdep) --dir=deps $1)
|
||||||
modoutput=$(shell ./$(lsproj) $(src) $1 output)
|
rdeps=$(shell $(lsdep) --dir=deps --rec $1)
|
||||||
deps=$(strip \
|
|
||||||
$(foreach dep, $(shell ./$(lsproj) $(src) $1 deps),\
|
|
||||||
$(if $(wildcard src/$(dep)), $(dep),\
|
|
||||||
$(error The module '$(dep)' (dependency of '$1') doesn't exist)\
|
|
||||||
)\
|
|
||||||
)\
|
|
||||||
)
|
|
||||||
rdeps=$(call uniq,$(strip \
|
|
||||||
$(foreach dep, $(call deps,$1),\
|
|
||||||
$(call rdeps,$(dep))\
|
|
||||||
$(dep)\
|
|
||||||
)\
|
|
||||||
))
|
|
||||||
|
|
||||||
fdeps=$(foreach dep,$(call deps,$1),$(bin)/lib$(lib)$(call modoutput,$(dep))$(so))
|
frdeps=$(shell $(lsdep) --dir=deps --rec --transform=$(bin)/lib$(lib)*$(so) $1)
|
||||||
frdeps=$(foreach dep,$(call rdeps,$1),$(bin)/lib$(lib)$(call modoutput,$(dep))$(so))
|
ldeps=$(shell $(lsdep) --dir=deps --transform=-l$(lib) $1)
|
||||||
|
|
||||||
ldeps=$(foreach dep,$(call deps,$1),-l$(lib)$(call modoutput,$(dep)))
|
|
||||||
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)
|
||||||
@ -52,7 +37,8 @@ $(bin)/lib$(lib)%$(so): $$(call frdeps,$$*) $$(call binaries,$$*)
|
|||||||
$(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)"
|
$(CXX) -shared -fPIC $(flags) $(call binaries,$*) -o $@ $(ldflags) $(call ldeps,$*) -L$(bin) "-I$(inc)"
|
||||||
echo Compiling library '$(notdir $@)'...
|
echo Compiling library '$(notdir $@)'...
|
||||||
|
|
||||||
$(bin)/tmp/%.o: $(src)/%.cc $(headers)
|
.SECONDEXPANSION:
|
||||||
|
$(bin)/tmp/%.o: $(src)/%.cc $$(shell $(lsinc) $(inc) $(src)/%.cc)
|
||||||
$(call mkdir,$(dir $@))
|
$(call mkdir,$(dir $@))
|
||||||
$(CXX) -fPIC -c $(flags) $< -o $@
|
$(CXX) -fPIC -c $(flags) $< -o $@
|
||||||
echo - Compiling '$*.cc'...
|
echo - Compiling '$*.cc'...
|
||||||
|
11
scripts/ls.mak
Normal file
11
scripts/ls.mak
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
all: $(lsdep) $(lsinc)
|
||||||
|
|
||||||
|
$(lsdep): $(src)/lsdep.cc
|
||||||
|
$(call mkdir,$(dir $@))
|
||||||
|
echo - Compiling lsdep.cc... >&2
|
||||||
|
$(CXX) $(flags) $^ -o $@
|
||||||
|
|
||||||
|
$(lsinc): $(src)/lsinc.cc
|
||||||
|
echo - Compiling lsinc.cc... >&2
|
||||||
|
$(call mkdir,$(dir $@))
|
||||||
|
$(CXX) $(flags) $^ -o $@
|
@ -1,3 +0,0 @@
|
|||||||
$(lsproj): $(src)/lsproj.cc
|
|
||||||
$(call mkdir,$(dir $@))
|
|
||||||
$(CXX) $^ -o $@
|
|
@ -1,2 +0,0 @@
|
|||||||
compiler
|
|
||||||
utils, lang
|
|
@ -1,34 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
|
||||||
|
|
||||||
using namespace ppc;
|
|
||||||
using namespace ppc::data;
|
|
||||||
using namespace ppc::lang;
|
|
||||||
using namespace ppc::comp::tree::ast;
|
|
||||||
|
|
||||||
group_t &ast_ctx_t::group(const std::string &name) {
|
|
||||||
if (groups.find(name) == groups.end()) return groups[name] = { };
|
|
||||||
else return groups[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_ctx_t::ast_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens): messages(messages), tokens(tokens) {
|
|
||||||
group("$_exp_val")
|
|
||||||
.add("$_var", parse_exp_var)
|
|
||||||
.add("$_int", parse_exp_int_lit)
|
|
||||||
.add("$_string", parse_exp_str_lit);
|
|
||||||
// .add_last("$_float", parse_exp_float_lit)
|
|
||||||
group("$_stat")
|
|
||||||
.add("$_while", { "while" }, parse_while)
|
|
||||||
.add("$_if", { "if" }, parse_if)
|
|
||||||
.add("$_return", { "return" }, parse_return)
|
|
||||||
.add("$_break", { "break" }, parse_break)
|
|
||||||
.add("$_continue", { "continue" }, parse_continue)
|
|
||||||
.add("$_comp", parse_stat_comp)
|
|
||||||
.add("$_exp", parse_stat_exp);
|
|
||||||
group("$_def")
|
|
||||||
.add("$_func", parse_func)
|
|
||||||
.add("$_struct", { "struct" }, parse_struct)
|
|
||||||
.add("$_field", parse_field);
|
|
||||||
group("$_struct_def")
|
|
||||||
.add("$_func", parse_func)
|
|
||||||
.add("$_field", parse_field);
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
#include <sstream>
|
|
||||||
#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" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
located_t<std::string> map_to_identifier(const data::map_t &map) {
|
|
||||||
return { conv::map_to_loc(map["location"].string()), map["content"].string() };
|
|
||||||
}
|
|
||||||
|
|
||||||
data::string_t loc_to_map(const location_t &loc) {
|
|
||||||
std::stringstream res;
|
|
||||||
res << loc.filename << ':' << loc.line + 1 << ':' << loc.start + 1 << ':' << loc.code_start + 1 << ':' << loc.length + 1;
|
|
||||||
return res.str();
|
|
||||||
}
|
|
||||||
location_t map_to_loc(const data::string_t &map) {
|
|
||||||
std::stringstream res;
|
|
||||||
res.str(map);
|
|
||||||
|
|
||||||
std::string filename;
|
|
||||||
std::string line;
|
|
||||||
std::string start;
|
|
||||||
std::string code_start;
|
|
||||||
std::string length;
|
|
||||||
|
|
||||||
std::getline(res, filename, ':');
|
|
||||||
std::getline(res, line, ':');
|
|
||||||
std::getline(res, start, ':');
|
|
||||||
std::getline(res, code_start, ':');
|
|
||||||
std::getline(res, length, ':');
|
|
||||||
|
|
||||||
return { filename, std::stoull(line) - 1, std::stoull(start) - 1, std::stoull(code_start) - 1, std::stoull(length) - 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
data::map_t nmsp_to_map(const loc_namespace_name_t &nmsp) {
|
|
||||||
data::map_t res;
|
|
||||||
|
|
||||||
auto arr = res["content"].array({});
|
|
||||||
|
|
||||||
for (const auto &segment : nmsp) {
|
|
||||||
arr.push_back({
|
|
||||||
{ "location", loc_to_map(segment.location) },
|
|
||||||
{ "content", segment },
|
|
||||||
{ "$_name", "$_nmsp" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,364 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
enum precedence_t {
|
|
||||||
NONE,
|
|
||||||
POSTFIX,
|
|
||||||
PREFIX,
|
|
||||||
MULT,
|
|
||||||
ADD,
|
|
||||||
SHIFT,
|
|
||||||
COMP,
|
|
||||||
EQU,
|
|
||||||
BIN_AND,
|
|
||||||
BIN_XOR,
|
|
||||||
BIN_OR,
|
|
||||||
BOOL_AND,
|
|
||||||
BOOL_OR,
|
|
||||||
TERNARY,
|
|
||||||
ASSIGN,
|
|
||||||
PAREN,
|
|
||||||
CALL_START,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct op_data_t {
|
|
||||||
precedence_t precedence;
|
|
||||||
size_t op_n;
|
|
||||||
std::string name;
|
|
||||||
bool assoc;
|
|
||||||
};
|
|
||||||
|
|
||||||
op_data_t sizeof_data { precedence_t::PREFIX, 1, "sizeof", true };
|
|
||||||
|
|
||||||
std::map<operator_t, op_data_t> pre_ops {
|
|
||||||
{ operator_t::INCREASE, { precedence_t::PREFIX, 1, "inc_pre" } },
|
|
||||||
{ operator_t::DECREASE, { precedence_t::PREFIX, 1, "dec_pre" } },
|
|
||||||
{ operator_t::ADD, { precedence_t::PREFIX, 1, "positive" } },
|
|
||||||
{ operator_t::SUBTRACT, { precedence_t::PREFIX, 1, "negative" } },
|
|
||||||
{ operator_t::BITWISE_NEGATIVE, { precedence_t::PREFIX, 1, "flip" } },
|
|
||||||
{ operator_t::MULTIPLY, { precedence_t::PREFIX, 1, "dereference" } },
|
|
||||||
{ operator_t::AND, { precedence_t::PREFIX, 1, "reference" } },
|
|
||||||
};
|
|
||||||
std::map<operator_t, op_data_t> bin_ops {
|
|
||||||
{ operator_t::INCREASE, { precedence_t::POSTFIX, 1, "inc_post" } },
|
|
||||||
{ operator_t::DECREASE, { precedence_t::POSTFIX, 1, "dec_post" } },
|
|
||||||
{ (operator_t)-1, sizeof_data },
|
|
||||||
|
|
||||||
{ operator_t::ADD, { precedence_t::ADD, 2, "add" } },
|
|
||||||
{ operator_t::SUBTRACT, { precedence_t::ADD, 2, "subtract" } },
|
|
||||||
|
|
||||||
{ operator_t::MULTIPLY, { precedence_t::MULT, 2, "multiply" } },
|
|
||||||
{ operator_t::DIVIDE, { precedence_t::MULT, 2, "divide" } },
|
|
||||||
{ operator_t::MODULO, { precedence_t::MULT, 2, "modulo" } },
|
|
||||||
|
|
||||||
{ operator_t::SHIFT_LEFT, { precedence_t::SHIFT, 2, "shl" } },
|
|
||||||
{ operator_t::SHIFT_RIGHT, { precedence_t::SHIFT, 2, "shr" } },
|
|
||||||
|
|
||||||
{ operator_t::LESS_THAN, { precedence_t::COMP, 2, "less" } },
|
|
||||||
{ operator_t::LESS_THAN_EQUALS, { precedence_t::COMP, 2, "less_eq" } },
|
|
||||||
{ operator_t::GREATER_THAN, { precedence_t::COMP, 2, "great" } },
|
|
||||||
{ operator_t::GREATER_THAN_EQUALS, { precedence_t::COMP, 2, "great_eq" } },
|
|
||||||
|
|
||||||
{ operator_t::EQUALS, { precedence_t::EQU, 2, "eq" } },
|
|
||||||
{ operator_t::NOT_EQUALS, { precedence_t::EQU, 2, "neq" } },
|
|
||||||
|
|
||||||
{ operator_t::AND, { precedence_t::BIN_AND, 2, "great_eq" } },
|
|
||||||
{ operator_t::OR, { precedence_t::BIN_OR, 2, "great_eq" } },
|
|
||||||
{ operator_t::XOR, { precedence_t::BIN_XOR, 2, "great_eq" } },
|
|
||||||
|
|
||||||
{ operator_t::DOUBLE_AND, { precedence_t::BOOL_AND, 2, "great_eq" } },
|
|
||||||
{ operator_t::DOUBLE_OR, { precedence_t::BOOL_OR, 2, "great_eq" } },
|
|
||||||
|
|
||||||
{ operator_t::ASSIGN, { precedence_t::ASSIGN, 2, "assign", true } },
|
|
||||||
{ operator_t::ASSIGN_ADD, { precedence_t::ASSIGN, 2, "assign_add", true } },
|
|
||||||
{ operator_t::ASSIGN_SUBTRACT, { precedence_t::ASSIGN, 2, "assign_subtract", true } },
|
|
||||||
{ operator_t::ASSIGN_MULTIPLY, { precedence_t::ASSIGN, 2, "assign_multiply", true } },
|
|
||||||
{ operator_t::ASSIGN_DIVIDE, { precedence_t::ASSIGN, 2, "assign_divide", true } },
|
|
||||||
{ operator_t::ASSIGN_MODULO, { precedence_t::ASSIGN, 2, "assign_modulo", true } },
|
|
||||||
{ operator_t::ASSIGN_SHIFT_LEFT, { precedence_t::ASSIGN, 2, "assign_shl", true } },
|
|
||||||
{ operator_t::ASSIGN_SHIFT_RIGHT, { precedence_t::ASSIGN, 2, "assign_shr", true } },
|
|
||||||
{ operator_t::ASSIGN_XOR, { precedence_t::ASSIGN, 2, "assign_xor", true } },
|
|
||||||
{ operator_t::ASSIGN_AND, { precedence_t::ASSIGN, 2, "assign_and", true } },
|
|
||||||
{ operator_t::ASSIGN_OR, { precedence_t::ASSIGN, 2, "assign_or", true } },
|
|
||||||
{ operator_t::ASSIGN_DOUBLE_AND, { precedence_t::ASSIGN, 2, "assign_dand", true } },
|
|
||||||
{ operator_t::ASSIGN_DOUBLE_OR, { precedence_t::ASSIGN, 2, "assign_dor", true } },
|
|
||||||
{ operator_t::ASSIGN_NULL_COALESCING, { precedence_t::ASSIGN, 2, "assign_null_coal", true } },
|
|
||||||
};
|
|
||||||
|
|
||||||
map_t op_to_map(located_t<op_data_t> op) {
|
|
||||||
return {
|
|
||||||
{ "$_name", "$_operator" },
|
|
||||||
{ "ops", array_t() },
|
|
||||||
{ "location", conv::loc_to_map(op.location) },
|
|
||||||
{ "op", op.name },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pop(std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
|
|
||||||
if (op_stack.empty()) return false;
|
|
||||||
|
|
||||||
auto map = op_to_map(op_stack.back());
|
|
||||||
auto op_n = op_stack.back().op_n;
|
|
||||||
auto loc = op_stack.back().location;
|
|
||||||
op_stack.pop_back();
|
|
||||||
|
|
||||||
if (res.size() < op_n) return false;
|
|
||||||
|
|
||||||
auto &ops = map["ops"].array();
|
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = 0; i < op_n; i++) {
|
|
||||||
ops.push_back(res.back());
|
|
||||||
loc = loc.intersect(conv::map_to_loc(res.back().map()["location"].string()));
|
|
||||||
res.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
map["location"] = conv::loc_to_map(loc);
|
|
||||||
|
|
||||||
std::reverse(ops.begin(), ops.end());
|
|
||||||
res.push_back(map);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool pop_paren(std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
|
|
||||||
bool has_paren = false;
|
|
||||||
for (const auto &op : op_stack) {
|
|
||||||
if (op.precedence == precedence_t::PAREN) {
|
|
||||||
has_paren = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!has_paren) return false;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (op_stack.back().precedence == precedence_t::PAREN) break;
|
|
||||||
if (!pop(op_stack, res)) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
op_stack.pop_back();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool pop_call(size_t n, location_t loc, std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
|
|
||||||
map_t call = {
|
|
||||||
{ "$_name", "$_call" },
|
|
||||||
};
|
|
||||||
|
|
||||||
array_t &args = call["args"].array({});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (op_stack.back().precedence == precedence_t::CALL_START) break;
|
|
||||||
if (!pop(op_stack, res)) return false;
|
|
||||||
}
|
|
||||||
loc = loc.intersect(op_stack.back().location);
|
|
||||||
op_stack.pop_back();
|
|
||||||
call["location"] = conv::loc_to_map(loc);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
args.push_back(res.back());
|
|
||||||
res.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::reverse(args.begin(), args.end());
|
|
||||||
|
|
||||||
call["func"] = res.back();
|
|
||||||
res.pop_back();
|
|
||||||
res.push_back(call);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool pop_until(const op_data_t &data, tree_helper_t &h, std::vector<located_t<op_data_t>> &op_stack, array_t &res) {
|
|
||||||
while (!op_stack.empty()) {
|
|
||||||
auto &back_data = op_stack.back();
|
|
||||||
if (data.assoc ?
|
|
||||||
back_data.precedence >= data.precedence :
|
|
||||||
back_data.precedence > data.precedence
|
|
||||||
) break;
|
|
||||||
|
|
||||||
if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator.");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_exp_var(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
return ctx.parse(parse_nmsp, res_i, out);
|
|
||||||
}
|
|
||||||
bool ast::parse_exp_int_lit(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.curr().is_int_literal()) {
|
|
||||||
auto &arr = out["content"].array({});
|
|
||||||
for (auto b : h.curr().literal()) arr.push_back((float)b);
|
|
||||||
out["location"] = conv::loc_to_map(h.loc());
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool ast::parse_exp_str_lit(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.curr().is_str_literal()) {
|
|
||||||
auto &arr = out["content"].array({});
|
|
||||||
for (auto b : h.curr().literal()) arr.push_back((float)b);
|
|
||||||
out["location"] = conv::loc_to_map(h.loc());
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_exp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
bool last_val = false;
|
|
||||||
map_t val;
|
|
||||||
std::vector<located_t<op_data_t>> op_stack;
|
|
||||||
std::vector<size_t> call_args_n;
|
|
||||||
auto res = array_t();
|
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (h.ended()) break;
|
|
||||||
|
|
||||||
if (!last_val && h.curr().is_identifier("sizeof")) {
|
|
||||||
op_stack.push_back({ h.loc(), sizeof_data });
|
|
||||||
h.advance("Expected a value on the right side of the operator.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!last_val && h.push_parse(ctx.group("$_exp_val"), res)) {
|
|
||||||
last_val = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (h.curr().is_operator()) {
|
|
||||||
auto op = h.curr()._operator();
|
|
||||||
if (last_val) {
|
|
||||||
if (op == operator_t::PAREN_OPEN) {
|
|
||||||
h.advance("Expected an argument or closing parens.");
|
|
||||||
op_stack.push_back({ h.loc(), { precedence_t::CALL_START } });
|
|
||||||
if (h.curr().is_operator(operator_t::PAREN_CLOSE)) {
|
|
||||||
pop_call(0, h.loc(), op_stack, res);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
call_args_n.push_back(1);
|
|
||||||
}
|
|
||||||
last_val = false;
|
|
||||||
}
|
|
||||||
else if (op == operator_t::PAREN_CLOSE) {
|
|
||||||
bool is_call = false, is_paren = false;
|
|
||||||
|
|
||||||
for (auto i = op_stack.rbegin(); i != op_stack.rend(); i++) {
|
|
||||||
if (i->precedence == precedence_t::PAREN) {
|
|
||||||
is_paren = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (i->precedence == precedence_t::CALL_START) {
|
|
||||||
is_call = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_call) {
|
|
||||||
pop_call(call_args_n.back(), h.loc(), op_stack, res);
|
|
||||||
call_args_n.pop_back();
|
|
||||||
}
|
|
||||||
else if (is_paren) pop_paren(op_stack, res);
|
|
||||||
else break;
|
|
||||||
|
|
||||||
if (!h.try_advance()) break;
|
|
||||||
}
|
|
||||||
else if (op == operator_t::COMMA) {
|
|
||||||
if (call_args_n.size() == 0) break;
|
|
||||||
h.advance("Expected an argument.");
|
|
||||||
|
|
||||||
pop_until({ .precedence = precedence_t::CALL_START, .assoc = true }, h, op_stack, res);
|
|
||||||
call_args_n.back()++;
|
|
||||||
last_val = false;
|
|
||||||
}
|
|
||||||
else if (op == operator_t::COLON) {
|
|
||||||
h.advance("Expected a type.");
|
|
||||||
pop_until({ .precedence = precedence_t::PREFIX, .assoc = true }, h, op_stack, res);
|
|
||||||
map_t cast = {
|
|
||||||
{ "$_name", "$_cast" },
|
|
||||||
{ "exp", res.back() },
|
|
||||||
};
|
|
||||||
|
|
||||||
res.pop_back();
|
|
||||||
h.force_parse(parse_type, "Expected a type.", cast["type"].map({}));
|
|
||||||
cast["location"] = conv::loc_to_map(location_t::intersect(
|
|
||||||
conv::map_to_loc(cast["exp"].map()["location"].string()),
|
|
||||||
conv::map_to_loc(cast["type"].map()["location"].string())
|
|
||||||
));
|
|
||||||
res.push_back(cast);
|
|
||||||
}
|
|
||||||
else if (op == operator_t::DOT || op == operator_t::PTR_MEMBER) {
|
|
||||||
h.advance("Expected an identifier.");
|
|
||||||
pop_until({ .precedence = precedence_t::POSTFIX, .assoc = true }, h, op_stack, res);
|
|
||||||
|
|
||||||
map_t member_access = {
|
|
||||||
{ "exp", res.back() },
|
|
||||||
{ "is_ptr", op == operator_t::PTR_MEMBER },
|
|
||||||
};
|
|
||||||
h.force_parse(parse_identifier, "Expected an identifier.", member_access["name"].map({}));
|
|
||||||
member_access["location"] = conv::loc_to_map(
|
|
||||||
conv::map_to_loc(member_access["name"].map()["location"].string()).intersect(
|
|
||||||
conv::map_to_loc(res.back().map()["location"].string())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
res.pop_back();
|
|
||||||
res.push_back(member_access);
|
|
||||||
}
|
|
||||||
else if (bin_ops.find(op) != bin_ops.end()) {
|
|
||||||
auto data = bin_ops[op];
|
|
||||||
pop_until(data, h, op_stack, res);
|
|
||||||
op_stack.push_back({ h.loc(), data });
|
|
||||||
|
|
||||||
if (data.op_n == 1) {
|
|
||||||
last_val = true;
|
|
||||||
if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator.");
|
|
||||||
if (h.try_advance()) break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
last_val = false;
|
|
||||||
h.advance("Expected a value on the right side of the operator.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (op == operator_t::PAREN_OPEN) {
|
|
||||||
op_stack.push_back({ h.loc(), { precedence_t::PAREN } });
|
|
||||||
h.advance("Expected a value.");
|
|
||||||
last_val = false;
|
|
||||||
}
|
|
||||||
else if (pre_ops.find(op) != pre_ops.end()) {
|
|
||||||
op_stack.push_back({ h.loc(), pre_ops[op] });
|
|
||||||
h.advance("Expected a value on the right side of the operator.");
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.size() == 0) return false;
|
|
||||||
|
|
||||||
while (!op_stack.empty()) {
|
|
||||||
if (op_stack.back().precedence == precedence_t::PAREN) throw message_t::error("Unclosed paren.", op_stack.back().location);
|
|
||||||
if (op_stack.back().precedence == precedence_t::CALL_START) throw message_t::error("Unclosed call.", op_stack.back().location);
|
|
||||||
if (!pop(op_stack, res)) return h.err("Expected an expression on the right side of this operator.");
|
|
||||||
}
|
|
||||||
|
|
||||||
out = res.front().map();
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
bool ast::parse_stat_exp(ast_ctx_t &ctx, size_t &i, map_t &res) {
|
|
||||||
tree_helper_t h(ctx, i);
|
|
||||||
if (!h.parse(parse_exp, res)) return false;
|
|
||||||
if (!h.ended() && h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
|
|
||||||
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_export(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
if (!h.curr().is_identifier("export")) return false;
|
|
||||||
h.advance("Unexpected end after export.");
|
|
||||||
|
|
||||||
if (out["exported"].is_true()) {
|
|
||||||
ctx.messages.push(message_t(message_t::WARNING, "Export is alredy specified for this definition.", h.prev_loc()));
|
|
||||||
}
|
|
||||||
out["exported"] = true;
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_field(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
h.parse(parse_export, out);
|
|
||||||
|
|
||||||
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
|
|
||||||
|
|
||||||
bool type = false, defval = false;
|
|
||||||
|
|
||||||
h.throw_ended("Expected a colon or an equals sign.");
|
|
||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
|
||||||
h.advance();
|
|
||||||
h.force_parse(parse_type, "Expected a type.", out["type"].map({}));
|
|
||||||
type = true;
|
|
||||||
}
|
|
||||||
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
|
||||||
h.advance();
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", out["value"].map({}));
|
|
||||||
type = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!h.ended() && h.curr().is_operator(operator_t::SEMICOLON)) {
|
|
||||||
if (type || defval) return h.submit();
|
|
||||||
else return h.err("A type or a default value must be specified ");
|
|
||||||
}
|
|
||||||
else if (type || defval) {
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
else return false;
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
static bool parse_arg(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
h.parse(parse_export, out);
|
|
||||||
|
|
||||||
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
|
|
||||||
|
|
||||||
bool type = false, defval = false;
|
|
||||||
|
|
||||||
h.throw_ended("Expected a colon or an equals sign.");
|
|
||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
|
||||||
h.advance();
|
|
||||||
h.force_parse(parse_type, "Expected a type.", out["type"].map({}));
|
|
||||||
type = true;
|
|
||||||
}
|
|
||||||
if (h.curr().is_operator(operator_t::ASSIGN)) {
|
|
||||||
h.advance();
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", out["value"].map({}));
|
|
||||||
type = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!type && !defval) {
|
|
||||||
ctx.messages.push(message_t::error("Expected a type or a default value.", h.loc(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_func(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
h.parse(parse_export, out);
|
|
||||||
|
|
||||||
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
|
|
||||||
if (h.ended()) return false;
|
|
||||||
if (!h.curr().is_operator(operator_t::PAREN_OPEN)) return false;
|
|
||||||
h.advance("Expected a closing paren or a parameter.");
|
|
||||||
|
|
||||||
auto ¶ms = out["params"].array({});
|
|
||||||
auto &content = out["content"].array({});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (h.curr().is_operator(operator_t::PAREN_CLOSE)) {
|
|
||||||
h.advance("Expected a function body.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
h.force_push_parse(parse_arg, "Expected a parameter.", params);
|
|
||||||
if (h.curr().is_operator(operator_t::COMMA)) {
|
|
||||||
h.advance("Expected a parameter.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h.curr().is_operator(operator_t::COLON)) {
|
|
||||||
h.advance("Expected a type.");
|
|
||||||
h.force_parse(parse_type, "Expected a type", out["type"].map({}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
|
|
||||||
else if (h.curr().is_operator(operator_t::LAMBDA)) {
|
|
||||||
h.advance("Expected an expression.");
|
|
||||||
map_t exp;
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", exp);
|
|
||||||
content.push_back({
|
|
||||||
{ "$_name", "$_return" },
|
|
||||||
{ "content", exp },
|
|
||||||
});
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
else if (h.curr().is_operator(operator_t::BRACE_OPEN)) {
|
|
||||||
h.advance("Expected a statement.");
|
|
||||||
while (true) {
|
|
||||||
if (h.curr().is_operator(operator_t::BRACE_CLOSE)) {
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
h.force_push_parse(ctx.group("$_stat"), "Expected an expression.", content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon, brace open or a lambda operator.", h.loc(1)));
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast.hh"
|
|
||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
// #include "./type.cc"
|
|
||||||
|
|
||||||
using namespace ppc::comp::tree::ast;
|
|
||||||
|
|
||||||
static bool nmsp_def(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
if (!h.curr().is_identifier("namespace")) return false;
|
|
||||||
h.advance("Expected a namespace");
|
|
||||||
h.force_parse(parse_nmsp, "Expected a namespace.", res);
|
|
||||||
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
static bool import(ast_ctx_t &ctx, size_t &res_i, data::map_t &res) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
if (!h.curr().is_identifier("import")) return false;
|
|
||||||
h.advance("Expected a namespace");
|
|
||||||
h.force_parse(parse_nmsp, "Expected a namespace.", res);
|
|
||||||
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
|
||||||
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_glob(ast_ctx_t &ctx, size_t &res_i, data::map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return true;
|
|
||||||
if (h.parse(nmsp_def, out["namespace"].map({}))) {
|
|
||||||
ctx.nmsp = conv::map_to_nmsp(out["namespace"].map());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out["namespace"] = data::null;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &imports = out["imports"].array({});
|
|
||||||
auto &contents = out["content"].array({});
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
map_t map;
|
|
||||||
if (!h.parse(import, map)) break;
|
|
||||||
imports.push_back(map);
|
|
||||||
auto nmsp = conv::map_to_nmsp(map);
|
|
||||||
|
|
||||||
if (!ctx.imports.emplace(nmsp).second) h.err("The namespace '" + nmsp.to_string() + "' is already imported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (h.ended()) break;
|
|
||||||
if (!h.push_parse(ctx.group("$_def"), contents)) {
|
|
||||||
ctx.messages.push(message_t::error("Invalid token.", h.loc()));
|
|
||||||
h.i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!h.ended()) h.err("Invalid token.");
|
|
||||||
|
|
||||||
return h.submit();
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
#include "lang/module.hh"
|
|
||||||
#include "compiler/treeifier/ast.hh"
|
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
|
||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace ppc::comp::tree;
|
|
||||||
using namespace ppc::comp::tree::ast;
|
|
||||||
using namespace std::string_literals;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &name) {
|
|
||||||
tree_helper_t h(ctx, i);
|
|
||||||
map_t res;
|
|
||||||
if (!h.parse(parse_nmsp, res)) return false;
|
|
||||||
name = conv::map_to_nmsp(res);
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
group_t &group_t::replace(const std::string &name, parser_t parser) {
|
|
||||||
auto it = parsers.find(name);
|
|
||||||
|
|
||||||
if (parsers.find(name) == parsers.end()) {
|
|
||||||
throw "The parser '" + name + "' isn't in the group.";
|
|
||||||
}
|
|
||||||
|
|
||||||
it->second = parser;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
group_t &group_t::add(const std::string &name, parser_t parser) {
|
|
||||||
if (parsers.find(name) != parsers.end()) {
|
|
||||||
throw "The parser '" + name + "' is already in the group.";
|
|
||||||
}
|
|
||||||
|
|
||||||
parsers.emplace(name, parser);
|
|
||||||
unnamed_parsers.emplace(name);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
group_t &group_t::add(const std::string &name, const lang::namespace_name_t &identifier, parser_t parser) {
|
|
||||||
if (parsers.find(name) != parsers.end()) {
|
|
||||||
throw "The parser '" + name + "' is already in the group.";
|
|
||||||
}
|
|
||||||
|
|
||||||
parsers.emplace(name, parser);
|
|
||||||
named_parsers.emplace(identifier, name);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool group_t::operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
|
|
||||||
tree_helper_t h(ctx, i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
std::set<namespace_name_t> names;
|
|
||||||
|
|
||||||
for (auto &import : ctx.imports) names.insert(import.strip_location());
|
|
||||||
|
|
||||||
loc_namespace_name_t name;
|
|
||||||
if (read_nmsp(ctx, h.i, name)) {
|
|
||||||
namespace_name_t actual;
|
|
||||||
|
|
||||||
if (resolve_name_map(
|
|
||||||
named_parsers, names,
|
|
||||||
name.strip_location(), actual
|
|
||||||
)) {
|
|
||||||
auto parser = parsers.find(this->named_parsers.find(actual)->second);
|
|
||||||
out.clear();
|
|
||||||
out["$_name"] = parser->first;
|
|
||||||
if (h.parse(parser->second, out)) return h.submit(false);
|
|
||||||
else throw message_t::error("Unexpected construct specifier.", h.res_loc());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto name : unnamed_parsers) {
|
|
||||||
out["$_name"] = name;
|
|
||||||
out.clear();
|
|
||||||
if (parsers.at(name)(ctx, i, out)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringstream m;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_identifier(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_nmsp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
auto &arr = (out["content"] = array_t()).array();
|
|
||||||
|
|
||||||
if (!h.push_parse(parse_identifier, arr)) return false;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (h.ended()) break;
|
|
||||||
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
|
|
||||||
h.advance("Expected an identifier.");
|
|
||||||
h.force_push_parse(parse_identifier, "Expected an identifier.", arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
out["location"] = conv::loc_to_map(h.res_loc());
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_if(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
h.throw_ended("Expected open parens after if keyword.");
|
|
||||||
if (!h.curr("Expected open parens after if keyword.").is_operator(operator_t::PAREN_OPEN)) {
|
|
||||||
throw message_t::error("Expected open parens after if keyword.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
h.advance("Expected an expression.");
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", out["condition"].map({}));
|
|
||||||
|
|
||||||
if (!h.curr("Expected closed parens.").is_operator(operator_t::PAREN_CLOSE)) {
|
|
||||||
throw message_t::error("Expected closed parens.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
h.advance("Expected a statement.");
|
|
||||||
h.force_parse(ctx.group("$_stat"), "Expected a statement.", out["if"].map({}));
|
|
||||||
|
|
||||||
if (h.ended() || !h.curr().is_identifier("else")) return h.submit(false);
|
|
||||||
|
|
||||||
h.advance("Expected a statement.");
|
|
||||||
h.force_parse(ctx.group("$_stat"), "Expected a statement.", out["else"].map({}));
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_while(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
h.throw_ended("Expected open parens after while keyword.");
|
|
||||||
if (!h.curr("Expected open parens after while keyword.").is_operator(operator_t::PAREN_OPEN)) {
|
|
||||||
throw message_t::error("Expected open parens after while keyword.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
h.advance("Expected an expression.");
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", out["condition"].map({}));
|
|
||||||
|
|
||||||
if (!h.curr("Expected closed parens.").is_operator(operator_t::PAREN_CLOSE)) {
|
|
||||||
throw message_t::error("Expected closed parens.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
h.advance("Expected a statement.");
|
|
||||||
h.force_parse(ctx.group("$_stat"), "Expected a statement.", out["while"].map({}));
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_return(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
h.throw_ended("Expected an expression.");
|
|
||||||
h.force_parse(parse_exp, "Expected an expression.", out["condition"].map({}));
|
|
||||||
|
|
||||||
if (!h.curr("Expected a semicolon.").is_operator(operator_t::SEMICOLON)) {
|
|
||||||
throw message_t::error("Expected a semicolon.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_break(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (!h.curr("Expected a semicolon.").is_operator(operator_t::SEMICOLON)) {
|
|
||||||
throw message_t::error("Expected a semicolon.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_continue(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (!h.curr("Expected a semicolon.").is_operator(operator_t::SEMICOLON)) {
|
|
||||||
throw message_t::error("Expected a semicolon.", h.loc(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ast::parse_stat_comp(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
if (!h.curr().is_operator(operator_t::BRACE_OPEN)) return false;
|
|
||||||
h.advance("Expected a statement or a closing brace.");
|
|
||||||
|
|
||||||
auto &content = out["content"].array({});
|
|
||||||
|
|
||||||
while (!h.curr().is_operator(operator_t::BRACE_CLOSE)) {
|
|
||||||
h.throw_ended("Expected a statement or a closing brace.");
|
|
||||||
h.push_parse(ctx.group("$_stat"), content);
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_struct(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
if (!h.parse(parse_identifier, out["name"].map({}))) return false;
|
|
||||||
|
|
||||||
auto &content = out["content"].array({});
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
if (h.curr().is_operator(operator_t::SEMICOLON)) return h.submit(true);
|
|
||||||
if (!h.curr().is_operator(operator_t::BRACE_OPEN)) return false;
|
|
||||||
h.advance("Expected a definition, a closing brace, or a semicolon.");
|
|
||||||
|
|
||||||
|
|
||||||
while (!h.curr().is_operator(operator_t::BRACE_CLOSE)) {
|
|
||||||
h.throw_ended("Expected a definition or a closing brace.");
|
|
||||||
h.push_parse(ctx.group("$_struct_def"), content);
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(true);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
#include "compiler/treeifier/ast/helper.hh"
|
|
||||||
|
|
||||||
bool ast::parse_type(ast_ctx_t &ctx, size_t &res_i, map_t &out) {
|
|
||||||
tree_helper_t h(ctx, res_i);
|
|
||||||
|
|
||||||
if (h.ended()) return false;
|
|
||||||
|
|
||||||
auto &nmsp = out["namespace"].map({});
|
|
||||||
size_t ptr_n = 0;
|
|
||||||
|
|
||||||
if (!h.parse(parse_nmsp, nmsp)) return false;
|
|
||||||
|
|
||||||
while (!h.ended() && h.curr().is_operator(operator_t::MULTIPLY)) {
|
|
||||||
ptr_n++;
|
|
||||||
if (!h.try_advance()) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto &nmsp_arr = nmsp["content"].array();
|
|
||||||
|
|
||||||
h.i--;
|
|
||||||
out["location"] = conv::loc_to_map(h.res_loc());
|
|
||||||
h.i++;
|
|
||||||
out["name"] = nmsp_arr.back();
|
|
||||||
out["ptr_n"] = (float)ptr_n;
|
|
||||||
nmsp_arr.pop_back();
|
|
||||||
if (nmsp_arr.empty()) out["namespace"] = null;
|
|
||||||
else {
|
|
||||||
auto loc_1 = conv::map_to_loc(nmsp_arr.front().map()["location"].string());
|
|
||||||
auto loc_2 = conv::map_to_loc(nmsp_arr.back().map()["location"].string());
|
|
||||||
auto loc = loc_1.intersect(loc_2);
|
|
||||||
nmsp["location"] = conv::loc_to_map(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.submit(false);
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
lang
|
|
||||||
utils
|
|
@ -1,9 +1,8 @@
|
|||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include "lang/common.hh"
|
#include "lang/common.hh"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace ppc::lang {
|
namespace ppc::lang {
|
||||||
std::string loc_namespace_name_t::to_string() const {
|
std::string loc_nmsp_t::to_string() const {
|
||||||
std::stringstream res;
|
std::stringstream res;
|
||||||
|
|
||||||
for (size_t i = 0; i < size(); i++) {
|
for (size_t i = 0; i < size(); i++) {
|
||||||
@ -13,7 +12,7 @@ namespace ppc::lang {
|
|||||||
|
|
||||||
return res.str();
|
return res.str();
|
||||||
}
|
}
|
||||||
std::string namespace_name_t::to_string() const {
|
std::string nmsp_t::to_string() const {
|
||||||
std::stringstream res;
|
std::stringstream res;
|
||||||
|
|
||||||
for (size_t i = 0; i < size(); i++) {
|
for (size_t i = 0; i < size(); i++) {
|
||||||
@ -24,7 +23,7 @@ namespace ppc::lang {
|
|||||||
return res.str();
|
return res.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int namespace_name_t::compare(const namespace_name_t &b) const {
|
int nmsp_t::compare(const nmsp_t &b) const {
|
||||||
const auto &a = *this;
|
const auto &a = *this;
|
||||||
for (size_t i = 0; i < a.size() && i < b.size(); i++) {
|
for (size_t i = 0; i < a.size() && i < b.size(); i++) {
|
||||||
auto cmp = a[i].compare(b[i]);
|
auto cmp = a[i].compare(b[i]);
|
||||||
@ -35,7 +34,7 @@ namespace ppc::lang {
|
|||||||
else if (a.size() == b.size()) return 0;
|
else if (a.size() == b.size()) return 0;
|
||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
int loc_namespace_name_t::compare(const loc_namespace_name_t &b) const {
|
int loc_nmsp_t::compare(const loc_nmsp_t &b) const {
|
||||||
const auto &a = *this;
|
const auto &a = *this;
|
||||||
for (size_t i = 0; i < a.size() && i < b.size(); i++) {
|
for (size_t i = 0; i < a.size() && i < b.size(); i++) {
|
||||||
auto cmp = a[i].compare(b[i]);
|
auto cmp = a[i].compare(b[i]);
|
||||||
@ -47,8 +46,8 @@ namespace ppc::lang {
|
|||||||
else return -1;
|
else return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace_name_t loc_namespace_name_t::strip_location() const {
|
nmsp_t loc_nmsp_t::strip_location() const {
|
||||||
namespace_name_t res;
|
nmsp_t res;
|
||||||
|
|
||||||
for (const auto &el : *this) {
|
for (const auto &el : *this) {
|
||||||
res.push_back(el);
|
res.push_back(el);
|
||||||
@ -57,4 +56,3 @@ namespace ppc::lang {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
#include "lang/module.hh"
|
|
||||||
|
|
||||||
using namespace std::string_literals;
|
|
||||||
using namespace ppc::lang;
|
|
||||||
|
|
||||||
definition_t::definition_t(function_t val) {
|
|
||||||
this->kind = FUNCTION;
|
|
||||||
this->val.func = new auto(val);
|
|
||||||
}
|
|
||||||
definition_t::definition_t(struct_t val) {
|
|
||||||
this->kind = STRUCT;
|
|
||||||
this->val.str = new auto(val);
|
|
||||||
}
|
|
||||||
definition_t::definition_t(field_t val) {
|
|
||||||
this->kind = FIELD;
|
|
||||||
this->val.field = new auto(val);
|
|
||||||
}
|
|
||||||
definition_t::definition_t(const definition_t &val) {
|
|
||||||
this->kind = val.kind;
|
|
||||||
switch (val.kind) {
|
|
||||||
case STRUCT:
|
|
||||||
this->val.str = new auto(*val.val.str);
|
|
||||||
break;
|
|
||||||
case FUNCTION:
|
|
||||||
this->val.func = new auto(*val.val.func);
|
|
||||||
break;
|
|
||||||
case FIELD:
|
|
||||||
this->val.field = new auto(*val.val.field);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
definition_t::~definition_t() {
|
|
||||||
switch (this->kind) {
|
|
||||||
case FUNCTION: delete this->val.func; break;
|
|
||||||
case FIELD: delete this->val.field; break;
|
|
||||||
case STRUCT: delete this->val.str; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function_t &definition_t::get_func() {
|
|
||||||
if (!this->is_func()) throw "Definition is not a function."s;
|
|
||||||
return *this->val.func;
|
|
||||||
}
|
|
||||||
struct_t &definition_t::get_struct() {
|
|
||||||
if (!this->is_struct()) throw "Definition is not a struct."s;
|
|
||||||
return *this->val.str;
|
|
||||||
}
|
|
||||||
field_t &definition_t::get_field() {
|
|
||||||
if (!this->is_field()) throw "Definition is not a field."s;
|
|
||||||
return *this->val.field;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
statement_t statement_t::call(const namespace_name_t &func) {
|
|
||||||
return { CALL, { .call = new auto(func) }};
|
|
||||||
}
|
|
||||||
statement_t statement_t::stack(int64_t stack) {
|
|
||||||
return { STACK, { .stack = stack }};
|
|
||||||
}
|
|
||||||
statement_t statement_t::ret() {
|
|
||||||
return { RETURN };
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ppc::lang::resolve_name(
|
|
||||||
const std::vector<namespace_name_t> &names, const std::set<namespace_name_t> &imports,
|
|
||||||
const namespace_name_t &name, namespace_name_t &res
|
|
||||||
) {
|
|
||||||
for (auto &curr : names) {
|
|
||||||
if (curr == name) {
|
|
||||||
res = curr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto &import : imports) {
|
|
||||||
auto new_name = name;
|
|
||||||
new_name.insert(new_name.begin(), import.begin(), import.end());
|
|
||||||
for (auto &curr : names) {
|
|
||||||
if (curr == new_name) {
|
|
||||||
res = curr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
146
src/lsdep.cc
Normal file
146
src/lsdep.cc
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
using std::size_t;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
fs::path proj_dir;
|
||||||
|
bool recursive = false;
|
||||||
|
std::string prefix = "", suffix = "";
|
||||||
|
|
||||||
|
static inline void ltrim(std::string &s) {
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
static inline void rtrim(std::string &s) {
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}).base(), s.end());
|
||||||
|
}
|
||||||
|
static inline void trim(std::string &s) {
|
||||||
|
rtrim(s);
|
||||||
|
ltrim(s);
|
||||||
|
}
|
||||||
|
static bool read_line(std::istream &str, std::string &res) {
|
||||||
|
if (str.eof()) return false;
|
||||||
|
std::getline(str, res);
|
||||||
|
trim(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_project_rec(const std::string &name, std::set<std::string> &res, bool rec = false) {
|
||||||
|
static std::set<std::string> prev;
|
||||||
|
|
||||||
|
if (!prev.emplace(name).second) throw name + ": Circular dependency detected.";
|
||||||
|
|
||||||
|
std::ifstream f(proj_dir / name);
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (read_line(f, line)) {
|
||||||
|
if (line.find('#') != std::string::npos) {
|
||||||
|
line = line.substr(0, line.find('#'));
|
||||||
|
}
|
||||||
|
|
||||||
|
trim(line);
|
||||||
|
|
||||||
|
if (line.size() == 0) continue;
|
||||||
|
if (line == name) throw name + ": Depends on itself.";
|
||||||
|
|
||||||
|
res.emplace(line);
|
||||||
|
if (rec) read_project_rec(line, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_err(const std::string &error, const std::string &context) {
|
||||||
|
std::cerr << context << ": " << error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_transform(const std::string &val) {
|
||||||
|
size_t i = 0;
|
||||||
|
bool last_percent = false;
|
||||||
|
bool is_prefix = true;
|
||||||
|
prefix = "", suffix = "";
|
||||||
|
|
||||||
|
for (; i < val.length(); i++) {
|
||||||
|
if (is_prefix) {
|
||||||
|
if (val[i] == '*') {
|
||||||
|
if (last_percent) {
|
||||||
|
last_percent = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last_percent = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (last_percent) {
|
||||||
|
is_prefix = false;
|
||||||
|
last_percent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_prefix) prefix += val[i];
|
||||||
|
else suffix += val[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_arg(std::string arg) {
|
||||||
|
if (arg.find("--") != 0) return false;
|
||||||
|
arg = arg.substr(2);
|
||||||
|
|
||||||
|
if (arg == "rec") {
|
||||||
|
recursive = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (arg.find("transform=") == 0) {
|
||||||
|
arg = arg.substr(10);
|
||||||
|
set_transform(arg);
|
||||||
|
}
|
||||||
|
else if (arg.find("dir=") == 0) {
|
||||||
|
arg = arg.substr(4);
|
||||||
|
proj_dir = arg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw "Incorrect usage. Syntax: [--rec] [--transform=prefix%suffix] [--dir=dir] [projects...]"s;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
try {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
std::set<std::string> deps;
|
||||||
|
|
||||||
|
while (argc > 0 && process_arg(argv[0])) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
while (argc > 0) {
|
||||||
|
// if (recursive) read_project_rec(argv[0], deps);
|
||||||
|
// else read_project(argv[0], deps);
|
||||||
|
read_project_rec(argv[0], deps, recursive);
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &dep : deps) {
|
||||||
|
std::cout << prefix + dep + suffix << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (std::string err) {
|
||||||
|
std::cerr << "error: lsdep: " << err << std::endl;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
132
src/lsinc.cc
Normal file
132
src/lsinc.cc
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
static inline void ltrim(std::string &s) {
|
||||||
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
static inline void rtrim(std::string &s) {
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}).base(), s.end());
|
||||||
|
}
|
||||||
|
static inline void trim(std::string &s) {
|
||||||
|
rtrim(s);
|
||||||
|
ltrim(s);
|
||||||
|
}
|
||||||
|
static bool read_line(std::istream &str, std::string &res) {
|
||||||
|
if (str.eof()) return false;
|
||||||
|
std::getline(str, res);
|
||||||
|
trim(res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path find_file(fs::path original, fs::path include) {
|
||||||
|
if (fs::exists(original)) return original;
|
||||||
|
if (fs::exists(include / original)) return include / original;
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_import(std::string line, fs::path root, fs::path &import) {
|
||||||
|
if (line.rfind("#include") != 0) return false;
|
||||||
|
line = line.substr(8);
|
||||||
|
trim(line);
|
||||||
|
if (line.length() < 3) throw "Invalid import syntax."s;
|
||||||
|
if (line[0] == '<') return false;
|
||||||
|
if (line[0] == '"') {
|
||||||
|
if (line[line.length() - 1] != '"') throw "Invalid import syntax."s;
|
||||||
|
auto path = line.substr(1, line.length() - 2);
|
||||||
|
|
||||||
|
if (path.rfind("./") == 0 || path.rfind(".\\") == 0) {
|
||||||
|
import = root / path.substr(2);
|
||||||
|
}
|
||||||
|
else import = path;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Invalid import syntax."s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_imports(fs::path file, fs::path include, std::set<fs::path> &res) {
|
||||||
|
static std::set<fs::path> parents = { };
|
||||||
|
static std::vector<fs::path> tmp = { };
|
||||||
|
|
||||||
|
if (!parents.emplace(file).second) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Circular dependency encountered (";
|
||||||
|
auto it = tmp.rbegin();
|
||||||
|
|
||||||
|
for (; it != tmp.rend(); it++) {
|
||||||
|
if (*it == file) break;
|
||||||
|
ss << *it << "<-";
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << *it << ")";
|
||||||
|
|
||||||
|
parents.clear();
|
||||||
|
tmp.clear();
|
||||||
|
|
||||||
|
throw ss.str();
|
||||||
|
}
|
||||||
|
tmp.push_back(file);
|
||||||
|
|
||||||
|
std::ifstream f(file.string());
|
||||||
|
if (f.is_open() && !f.eof()) {
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (read_line(f, line)) {
|
||||||
|
fs::path import;
|
||||||
|
if (get_import(line, file.parent_path(), import)) {
|
||||||
|
auto child = find_file(import, include);
|
||||||
|
res.emplace(child);
|
||||||
|
get_imports(child, include, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parents.erase(file);
|
||||||
|
tmp.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
try {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
throw "Incorrect usage. Syntax: [inc-path] [files...]."s;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path inc(argv[0]);
|
||||||
|
std::set<fs::path> res;
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
fs::path file(argv[i]);
|
||||||
|
get_imports(file, inc, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &i : res) {
|
||||||
|
std::cout << i.string() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (std::string err) {
|
||||||
|
std::cerr << "error: lsinc: " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
136
src/lsproj.cc
136
src/lsproj.cc
@ -1,136 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
struct project_t {
|
|
||||||
std::string output;
|
|
||||||
std::vector<std::string> deps;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars, int &end_char) {
|
|
||||||
std::vector<char> res { };
|
|
||||||
int c;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
c = f.get();
|
|
||||||
auto a = end_chars.find(c);
|
|
||||||
if (c == -1 || a != std::string::npos) {
|
|
||||||
end_char = c;
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if ((a = skip_chars.find(c)) == std::string::npos) {
|
|
||||||
f.unget();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
c = f.get();
|
|
||||||
if (c == -1 || end_chars.find(c) != std::string::npos) {
|
|
||||||
end_char = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.push_back(c);
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
if (skip_chars.find(res.back()) != std::string::npos) res.pop_back();
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::string { res.begin(), res.end() };
|
|
||||||
}
|
|
||||||
std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars) {
|
|
||||||
int end_char;
|
|
||||||
return read_str(f, skip_chars, end_chars, end_char);
|
|
||||||
}
|
|
||||||
|
|
||||||
project_t read_project(std::istream &f) {
|
|
||||||
int end_ch;
|
|
||||||
std::string name = read_str(f, " \v\t\r\n", "\n", end_ch);
|
|
||||||
std::size_t cap = 16, n = 0;
|
|
||||||
std::vector<std::string> deps { };
|
|
||||||
|
|
||||||
if (name.length() == 0) {
|
|
||||||
throw (std::string)"The name of a project may not be empty.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end_ch == -1) {
|
|
||||||
return project_t {
|
|
||||||
.output = name,
|
|
||||||
.deps = deps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.find(',') != std::string::npos || name.find(' ') != std::string::npos) {
|
|
||||||
throw (std::string)"The name of a project may not contain spaces or commas.";
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
std::string dep = read_str(f, " \v\t\r\n", ",\n", end_ch);
|
|
||||||
|
|
||||||
if (dep.find(' ') != std::string::npos) {
|
|
||||||
throw (std::string)"The name of a dependency may not contain spaces.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dep.length()) {
|
|
||||||
deps.push_back(dep);
|
|
||||||
if (end_ch == '\n') break;
|
|
||||||
}
|
|
||||||
if (end_ch == -1) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return project_t {
|
|
||||||
.output = name,
|
|
||||||
.deps = deps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_err(const std::string &error, const std::string &context) {
|
|
||||||
std::cerr << context << ": " << error;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
|
||||||
std::string proj_name = "";
|
|
||||||
try {
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
if (argc != 3) {
|
|
||||||
throw (std::string)"Incorrect usage. Syntax: [src-dir] [project-name] [output|deps].";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string proj_path = (std::string)argv[0] + "/" + argv[1] + ".proj";
|
|
||||||
proj_name = argv[1];
|
|
||||||
|
|
||||||
std::ifstream f { proj_path, std::ios_base::in };
|
|
||||||
|
|
||||||
if (!f.is_open()) {
|
|
||||||
throw (std::string)"The project '" + argv[1] +"' doesn't exist.";
|
|
||||||
}
|
|
||||||
|
|
||||||
project_t project = read_project(f);
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
if ((std::string)argv[2] == "output") {
|
|
||||||
std::cout << project.output;
|
|
||||||
}
|
|
||||||
else if ((std::string)argv[2] == "deps") {
|
|
||||||
for (std::string dep : project.deps) {
|
|
||||||
std::cout << dep << " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw (std::string)"Invalid command given. Available commands: output, deps.";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (std::string err) {
|
|
||||||
if (proj_name.length()) std::cerr << "Error: " << proj_name << ": " << err << std::endl;
|
|
||||||
else std::cerr << "Error: " << err << std::endl;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
main
|
|
||||||
utils, compiler
|
|
@ -8,31 +8,31 @@
|
|||||||
#define DISABLE_NEWLINE_AUTO_RETURN 0x8
|
#define DISABLE_NEWLINE_AUTO_RETURN 0x8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <conio.h>
|
#include <conio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
#undef ERROR
|
#undef ERROR
|
||||||
#undef INFO
|
#undef INFO
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sstream>
|
#include "./opions.hh"
|
||||||
|
#include "treeifier/lexer.hh"
|
||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
|
#include "treeifier/constructs/glob.hh"
|
||||||
|
#include "treeifier/parsers/glob.hh"
|
||||||
|
#include "utils/json.hh"
|
||||||
|
#include "utils/strings.hh"
|
||||||
|
#include "utils/threading.hh"
|
||||||
|
#include <cstdio>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdio>
|
#include <sstream>
|
||||||
#include "utils/threading.hh"
|
|
||||||
#include "utils/strings.hh"
|
|
||||||
#include "utils/json.hh"
|
|
||||||
#include "compiler/treeifier/lexer.hh"
|
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
|
||||||
#include "compiler/treeifier/ast.hh"
|
|
||||||
#include "./opions.hh"
|
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
using namespace ppc::comp::tree;
|
using namespace ppc::tree;
|
||||||
using namespace ppc::comp::tree::ast;
|
|
||||||
|
|
||||||
void add_flags(options::parser_t &parser) {
|
void add_flags(options::parser_t &parser) {
|
||||||
parser.add_flag({
|
parser.add_flag({
|
||||||
@ -40,15 +40,15 @@ void add_flags(options::parser_t &parser) {
|
|||||||
.shorthands = "v",
|
.shorthands = "v",
|
||||||
.description = "Displays version and license agreement of this binary",
|
.description = "Displays version and license agreement of this binary",
|
||||||
.execute = [](options::parser_t &parser, const std::string &option, ppc::messages::msg_stack_t &global_stack) {
|
.execute = [](options::parser_t &parser, const std::string &option, ppc::messages::msg_stack_t &global_stack) {
|
||||||
cout << "++C compiler\n"
|
cout << "++C compiler\n";
|
||||||
<< " Version: v" << PPC_VERSION_MAJOR << '.' << PPC_VERSION_MINOR << '.' << PPC_VERSION_BUILD
|
cout << " Version: v" << PPC_VERSION_MAJOR << '.' << PPC_VERSION_MINOR << '.' << PPC_VERSION_BUILD;
|
||||||
#if WINDOWS
|
#if WINDOWS
|
||||||
<< " (Windows)"
|
cout << " (Windows)";
|
||||||
#elif LINUX
|
#elif LINUX
|
||||||
<< " (Linux)"
|
cout << " (Linux)";
|
||||||
#endif
|
#endif
|
||||||
<< "\n"
|
cout << "\n";
|
||||||
<< " License: MIT Copyright (C) TopchetoEU\n";
|
cout << " License: MIT Copyright (C) TopchetoEU\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -57,10 +57,10 @@ void add_flags(options::parser_t &parser) {
|
|||||||
.shorthands = "h",
|
.shorthands = "h",
|
||||||
.description = "Displays a list of all flags and their meaning",
|
.description = "Displays a list of all flags and their meaning",
|
||||||
.execute = [](options::parser_t &parser, const std::string &option, ppc::messages::msg_stack_t &global_stack) {
|
.execute = [](options::parser_t &parser, const std::string &option, ppc::messages::msg_stack_t &global_stack) {
|
||||||
cout << "Usage: ...flags ...files\n\n"
|
cout << "Usage: ...flags ...files\n\n";
|
||||||
<< "Flags and file names can be interlaced\n"
|
cout << "Flags and file names can be interlaced\n";
|
||||||
<< "Flags will execute in the order they're written, then compilation begins\n\n"
|
cout << "Flags will execute in the order they're written, then compilation begins\n\n";
|
||||||
<< "Flags:\n";
|
cout << "Flags:\n";
|
||||||
|
|
||||||
for (const auto &flag : parser) {
|
for (const auto &flag : parser) {
|
||||||
std::stringstream buff;
|
std::stringstream buff;
|
||||||
@ -89,19 +89,23 @@ void add_flags(options::parser_t &parser) {
|
|||||||
const size_t padding = 24;
|
const size_t padding = 24;
|
||||||
const size_t msg_width = 80 - padding;
|
const size_t msg_width = 80 - padding;
|
||||||
|
|
||||||
for (size_t i = 0; i < padding - n; i++) cout << ' ';
|
for (size_t i = 0; i < padding - n; i++)
|
||||||
|
cout << ' ';
|
||||||
|
|
||||||
int len = flag.description.length();
|
int len = flag.description.length();
|
||||||
|
|
||||||
for (size_t i = 0; i < len / msg_width; i++) {
|
for (size_t i = 0; i < len / msg_width; i++) {
|
||||||
for (size_t j = 0; j < msg_width; j++) cout << flag.description[i * msg_width + j];
|
for (size_t j = 0; j < msg_width; j++)
|
||||||
|
cout << flag.description[i * msg_width + j];
|
||||||
cout << std::endl;
|
cout << std::endl;
|
||||||
for (size_t j = 0; j < padding; j++) cout << ' ';
|
for (size_t j = 0; j < padding; j++)
|
||||||
|
cout << ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
int remainder = len % msg_width;
|
int remainder = len % msg_width;
|
||||||
|
|
||||||
for (int i = 0; i < remainder; i++) cout << flag.description[len - remainder + i];
|
for (int i = 0; i < remainder; i++)
|
||||||
|
cout << flag.description[len - remainder + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@ -129,16 +133,16 @@ void add_flags(options::parser_t &parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
int main(int argc, const char *argv[]) {
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE handleOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
DWORD consoleMode;
|
DWORD consoleMode;
|
||||||
GetConsoleMode(handleOut, &consoleMode);
|
GetConsoleMode(handleOut, &consoleMode);
|
||||||
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
consoleMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
consoleMode |= DISABLE_NEWLINE_AUTO_RETURN;
|
||||||
SetConsoleMode(handleOut, consoleMode);
|
SetConsoleMode(handleOut, consoleMode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::string> args{ argv + 1, argv + argc };
|
std::vector<std::string> args { argv + 1, argv + argc };
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
messages::msg_stack_t msg_stack;
|
messages::msg_stack_t msg_stack;
|
||||||
|
|
||||||
@ -158,9 +162,12 @@ int main(int argc, const char *argv[]) {
|
|||||||
std::ifstream f { file, std::ios_base::in };
|
std::ifstream f { file, std::ios_base::in };
|
||||||
if (!f.is_open()) throw message_t::error("The file doesn't exist.", { file });
|
if (!f.is_open()) throw message_t::error("The file doesn't exist.", { file });
|
||||||
auto tokens = 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));
|
||||||
auto ast = ast_ctx_t::parse(ast::parse_glob, msg_stack, tokens);
|
constr::global_t glob;
|
||||||
|
auto ctx = parse_ctx_t(msg_stack, tokens);
|
||||||
std::cout << data::json::stringify(ast) << std::endl;
|
parse::glob_parser_t()(ctx, glob);
|
||||||
|
#ifdef PROFILE_debug
|
||||||
|
glob.print();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (const messages::message_t &msg) {
|
catch (const messages::message_t &msg) {
|
||||||
msg_stack.push(msg);
|
msg_stack.push(msg);
|
||||||
@ -170,7 +177,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
catch (const messages::message_t &msg) {
|
catch (const messages::message_t &msg) {
|
||||||
msg_stack.push(msg);
|
msg_stack.push(msg);
|
||||||
}
|
}
|
||||||
#ifndef PROFILE_debug
|
#ifndef PROFILE_debug
|
||||||
catch (const std::string &msg) {
|
catch (const std::string &msg) {
|
||||||
msg_stack.push(message_t::error(msg));
|
msg_stack.push(message_t::error(msg));
|
||||||
}
|
}
|
||||||
@ -178,7 +185,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
msg_stack.push(message_t::error("A fatal error occurred."));
|
msg_stack.push(message_t::error("A fatal error occurred."));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
msg_stack.print(std::cout, messages::message_t::DEBUG, true);
|
msg_stack.print(std::cout, messages::message_t::DEBUG, true);
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "utils/message.hh"
|
|
||||||
#include "utils/data.hh"
|
#include "utils/data.hh"
|
||||||
|
#include "utils/message.hh"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace ppc::options {
|
namespace ppc::options {
|
||||||
enum flag_match_type_t {
|
enum flag_match_type_t {
|
||||||
@ -21,9 +21,9 @@ namespace ppc::options {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct parser_t {
|
struct parser_t {
|
||||||
private:
|
private:
|
||||||
std::vector<flag_t> flags;
|
std::vector<flag_t> flags;
|
||||||
public:
|
public:
|
||||||
void add_flag(const flag_t &flag);
|
void add_flag(const flag_t &flag);
|
||||||
void clear_flags();
|
void clear_flags();
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <set>
|
|
||||||
#include "./opions.hh"
|
#include "./opions.hh"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
|
|
||||||
|
34
src/treeifier/ast.cc
Normal file
34
src/treeifier/ast.cc
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace ppc;
|
||||||
|
using namespace ppc::lang;
|
||||||
|
using namespace ppc::tree;
|
||||||
|
|
||||||
|
// ppc::tree::constr::inspoint_t &parse_ctx_t::group(const std::string &name) {
|
||||||
|
// if (groups.find(name) == groups.end()) return groups[name] = {};
|
||||||
|
// else return groups[name];
|
||||||
|
// }
|
||||||
|
|
||||||
|
parse_ctx_t::parse_ctx_t(msg_stack_t &messages, std::vector<token_t> &tokens): messages(messages), tokens(tokens) {
|
||||||
|
// group("$_exp_val")
|
||||||
|
// .add("$_var", parse_exp_var)
|
||||||
|
// .add("$_int", parse_exp_int_lit)
|
||||||
|
// .add("$_string", parse_exp_str_lit);
|
||||||
|
// // .add_last("$_float", parse_exp_float_lit)
|
||||||
|
// group("$_stat")
|
||||||
|
// .add("$_while", { "while" }, parse_while)
|
||||||
|
// .add("$_if", { "if" }, parse_if)
|
||||||
|
// .add("$_return", { "return" }, parse_return)
|
||||||
|
// .add("$_break", { "break" }, parse_break)
|
||||||
|
// .add("$_continue", { "continue" }, parse_continue)
|
||||||
|
// .add("$_comp", parse_stat_comp)
|
||||||
|
// .add("$_exp", parse_stat_exp);
|
||||||
|
// group("$_def")
|
||||||
|
// .add("$_func", parse_func)
|
||||||
|
// .add("$_struct", { "struct" }, parse_struct)
|
||||||
|
// .add("$_field", parse_field);
|
||||||
|
// group("$_struct_def")
|
||||||
|
// .add("$_func", parse_func)
|
||||||
|
// .add("$_field", parse_field);
|
||||||
|
}
|
48
src/treeifier/constr.cc
Normal file
48
src/treeifier/constr.cc
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include "treeifier/parsers/helper.hh"
|
||||||
|
#include "lang/common.hh"
|
||||||
|
|
||||||
|
using namespace ppc::tree;
|
||||||
|
|
||||||
|
bool parse::parse_identifier(parse_ctx_t &ctx, size_t &res_i, located_t<std::string> &out) {
|
||||||
|
helper_t h(ctx, res_i);
|
||||||
|
|
||||||
|
if (h.ended()) return false;
|
||||||
|
|
||||||
|
if (h.curr().is_identifier()) {
|
||||||
|
out = located_t<std::string>(h.loc(), h.curr().identifier());
|
||||||
|
return h.submit();
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse::parse_nmsp(parse_ctx_t &ctx, size_t &res_i, loc_nmsp_t &out) {
|
||||||
|
helper_t h(ctx, res_i);
|
||||||
|
|
||||||
|
if (h.ended()) return false;
|
||||||
|
|
||||||
|
out.clear();
|
||||||
|
located_t<std::string> val;
|
||||||
|
|
||||||
|
if (!h.parse(parse_identifier, val)) return false;
|
||||||
|
else out.push_back(val);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (h.ended()) break;
|
||||||
|
if (!h.curr().is_operator(operator_t::DOUBLE_COLON)) break;
|
||||||
|
h.advance("Expected an identifier.");
|
||||||
|
h.force_parse(parse_identifier, "Expected an identifier.", val);
|
||||||
|
out.push_back(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.submit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse::parse_nmsp_id(parse_ctx_t &ctx, size_t &res_i, std::set<nmsp_t> glob, nmsp_t nmsp) {
|
||||||
|
helper_t h(ctx, res_i);
|
||||||
|
loc_nmsp_t src;
|
||||||
|
|
||||||
|
if (!h.parse(parse_nmsp, src)) return false;
|
||||||
|
if (resolve_name(glob, src, nmsp)) return h.submit(false);
|
||||||
|
else return false;
|
||||||
|
}
|
43
src/treeifier/constr/glob.cc
Normal file
43
src/treeifier/constr/glob.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "treeifier/constr.hh"
|
||||||
|
#include "treeifier/parsers/helper.hh"
|
||||||
|
#include "treeifier/parsers/glob.hh"
|
||||||
|
#include "treeifier/constructs/glob.hh"
|
||||||
|
|
||||||
|
using namespace ppc::tree;
|
||||||
|
|
||||||
|
bool parse::glob_parser_t::operator()(parse_ctx_t &ctx, constr::global_t &out) const {
|
||||||
|
size_t res_i = 0;
|
||||||
|
helper_t h(ctx, res_i);
|
||||||
|
out = {};
|
||||||
|
|
||||||
|
if (h.ended()) return h.submit(false);
|
||||||
|
|
||||||
|
if (h.curr().is_identifier("namespace")) {
|
||||||
|
h.advance("Expected a namespace");
|
||||||
|
h.force_parse(parse_nmsp, "Expected a namespace.", out.nmsp);
|
||||||
|
|
||||||
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
||||||
|
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.try_advance()) return h.submit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (h.curr().is_identifier("import")) {
|
||||||
|
loc_nmsp_t res;
|
||||||
|
|
||||||
|
h.advance("Expected a namespace");
|
||||||
|
h.force_parse(parse_nmsp, "Expected a namespace.", res);
|
||||||
|
|
||||||
|
if (!h.curr().is_operator(operator_t::SEMICOLON)) {
|
||||||
|
ctx.messages.push(message_t::error("Expected a semicolon.", h.loc(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
out.imports.push_back(res);
|
||||||
|
if (!h.try_advance()) return h.submit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!h.ended()) h.err("Invalid token.");
|
||||||
|
|
||||||
|
return h.submit(false);
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
#include <sstream>
|
#include "treeifier/lexer.hh"
|
||||||
#include "compiler/treeifier/lexer.hh"
|
|
||||||
#include "utils/message.hh"
|
#include "utils/message.hh"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
using namespace ppc::messages;
|
using namespace ppc::messages;
|
||||||
using namespace ppc::comp::tree::lex;
|
using namespace ppc::tree::lex;
|
||||||
|
|
||||||
struct res_t;
|
struct res_t;
|
||||||
using lexlet_t = res_t (*)(char c, std::vector<char> &tok);
|
using lexlet_t = res_t (*)(char c, std::vector<char> &tok);
|
||||||
@ -26,7 +26,7 @@ struct res_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static inline bool isoct(char c) {
|
static inline bool is_oct(char c) {
|
||||||
return c >= '0' && c <= '7';
|
return c >= '0' && c <= '7';
|
||||||
}
|
}
|
||||||
static inline bool is_any(char c, std::string chars) {
|
static inline bool is_any(char c, std::string chars) {
|
||||||
@ -70,10 +70,10 @@ static res_t lexlet_bin(char c, std::vector<char> &tok) {
|
|||||||
else return lexer_end(token_t::BIN_LITERAL);
|
else return lexer_end(token_t::BIN_LITERAL);
|
||||||
};
|
};
|
||||||
static res_t lexlet_oct(char c, std::vector<char> &tok) {
|
static res_t lexlet_oct(char c, std::vector<char> &tok) {
|
||||||
if (isoct(c)) return lexer_none();
|
if (is_oct(c)) return lexer_none();
|
||||||
else if (isdigit(c)) throw message_t::error("An octal literal may only contain octal digits.");
|
else if (isdigit(c)) throw message_t::error("An octal literal may only contain octal digits.");
|
||||||
else return lexer_end(token_t::OCT_LITERAL);
|
else return lexer_end(token_t::OCT_LITERAL);
|
||||||
};
|
};
|
||||||
static res_t lexlet_float(char c, std::vector<char> &tok) {
|
static res_t lexlet_float(char c, std::vector<char> &tok) {
|
||||||
if (isdigit(c)) return lexer_none();
|
if (isdigit(c)) return lexer_none();
|
||||||
else return lexer_end(token_t::FLOAT_LITERAL);
|
else return lexer_end(token_t::FLOAT_LITERAL);
|
||||||
@ -193,7 +193,7 @@ std::vector<token_t> token_t::parse_many(ppc::messages::msg_stack_t &msg_stack,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const messages::message_t &msg) {
|
catch (const messages::message_t &msg) {
|
||||||
throw message_t(msg.level, msg.content, location_t(filename, line, start, i - curr_token.size(), curr_token.size()));
|
throw message_t(msg.level, msg.content, location_t(filename, line, start, i - curr_token.size(), curr_token.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,7 +214,8 @@ std::vector<token_t> token_t::parse_file(ppc::messages::msg_stack_t &msg_stack,
|
|||||||
std::vector<char> contents;
|
std::vector<char> contents;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
while ((c = f.get()) != EOF) contents.push_back(c);
|
while ((c = f.get()) != EOF)
|
||||||
|
contents.push_back(c);
|
||||||
|
|
||||||
return parse_many(msg_stack, filename, std::string { contents.begin(), contents.end() });
|
return parse_many(msg_stack, filename, std::string { contents.begin(), contents.end() });
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
|
||||||
|
|
||||||
using namespace ppc::comp::tree;
|
using namespace ppc;
|
||||||
using namespace ppc::comp;
|
using namespace ppc::tree;
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
|||||||
#include <string>
|
#include "treeifier/lexer.hh"
|
||||||
|
#include "treeifier/tokenizer.hh"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "compiler/treeifier/tokenizer.hh"
|
#include <string>
|
||||||
#include "compiler/treeifier/lexer.hh"
|
|
||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
using namespace messages;
|
using namespace messages;
|
||||||
using namespace comp::tree;
|
using namespace ppc::tree;
|
||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
static std::vector<uint8_t> parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) {
|
static std::vector<uint8_t> parse_string(msg_stack_t &msg_stack, bool is_char, const lex::token_t &token) {
|
@ -1,4 +1,7 @@
|
|||||||
#include "utils/data.hh"
|
#include "utils/data.hh"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
namespace ppc::data {
|
namespace ppc::data {
|
||||||
bool value_t::is_null() const {
|
bool value_t::is_null() const {
|
||||||
@ -44,45 +47,45 @@ namespace ppc::data {
|
|||||||
|
|
||||||
array_t &value_t::array() {
|
array_t &value_t::array() {
|
||||||
if (is_array()) return *val.arr;
|
if (is_array()) return *val.arr;
|
||||||
else throw (std::string)"The value isn't an array.";
|
else throw "The value isn't an array."s;
|
||||||
}
|
}
|
||||||
map_t &value_t::map() {
|
map_t &value_t::map() {
|
||||||
if (is_map()) return *val.map;
|
if (is_map()) return *val.map;
|
||||||
else throw (std::string)"The value isn't a map.";
|
else throw "The value isn't a map."s;
|
||||||
}
|
}
|
||||||
number_t &value_t::number() {
|
number_t &value_t::number() {
|
||||||
if (is_number()) return val.num;
|
if (is_number()) return val.num;
|
||||||
else throw (std::string)"The value isn't a number.";
|
else throw "The value isn't a number."s;
|
||||||
}
|
}
|
||||||
string_t &value_t::string() {
|
string_t &value_t::string() {
|
||||||
if (is_string()) return *val.str;
|
if (is_string()) return *val.str;
|
||||||
else throw (std::string)"The value isn't a string.";
|
else throw "The value isn't a string."s;
|
||||||
}
|
}
|
||||||
bool_t &value_t::boolean() {
|
bool_t &value_t::boolean() {
|
||||||
if (is_bool()) return val.bl;
|
if (is_bool()) return val.bl;
|
||||||
else throw (std::string)"The value isn't a bool.";
|
else throw "The value isn't a bool."s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const array_t &value_t::array() const {
|
const array_t &value_t::array() const {
|
||||||
if (is_array()) return *val.arr;
|
if (is_array()) return *val.arr;
|
||||||
else throw (std::string)"The value isn't an array.";
|
else throw "The value isn't an array."s;
|
||||||
}
|
}
|
||||||
const map_t &value_t::map() const {
|
const map_t &value_t::map() const {
|
||||||
if (is_map()) return *val.map;
|
if (is_map()) return *val.map;
|
||||||
else throw (std::string)"The value isn't a map.";
|
else throw "The value isn't a map."s;
|
||||||
}
|
}
|
||||||
number_t value_t::number() const {
|
number_t value_t::number() const {
|
||||||
if (is_number()) return val.num;
|
if (is_number()) return val.num;
|
||||||
else throw (std::string)"The value isn't a number.";
|
else throw "The value isn't a number."s;
|
||||||
}
|
}
|
||||||
const string_t &value_t::string() const {
|
const string_t &value_t::string() const {
|
||||||
if (is_string()) return *val.str;
|
if (is_string()) return *val.str;
|
||||||
else throw (std::string)"The value isn't a string.";
|
else throw "The value isn't a string."s;
|
||||||
}
|
}
|
||||||
bool_t value_t::boolean() const {
|
bool_t value_t::boolean() const {
|
||||||
if (is_bool()) return val.bl;
|
if (is_bool()) return val.bl;
|
||||||
else throw (std::string)"The value isn't a bool.";
|
else throw "The value isn't a bool."s;
|
||||||
}
|
}
|
||||||
|
|
||||||
value_t::value_t() {
|
value_t::value_t() {
|
||||||
|
@ -39,7 +39,7 @@ location_t location_t::intersect(location_t other) const {
|
|||||||
location_t a = *this;
|
location_t a = *this;
|
||||||
location_t b = other;
|
location_t b = other;
|
||||||
|
|
||||||
if (a.start == -1u || b.start == -1u) return { };
|
if (a.start == -1u || b.start == -1u) return {};
|
||||||
|
|
||||||
if (a.start > b.start) return other.intersect(*this);
|
if (a.start > b.start) return other.intersect(*this);
|
||||||
|
|
||||||
@ -67,7 +67,6 @@ bool location_t::operator==(const location_t &other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string empty = "";
|
std::string empty = "";
|
||||||
|
|
||||||
location_t::location_t():
|
location_t::location_t():
|
||||||
@ -84,11 +83,12 @@ location_t::location_t(const std::string &filename, std::size_t line, std::size_
|
|||||||
location_t(filename, line, start, code_start, -1) { }
|
location_t(filename, line, start, code_start, -1) { }
|
||||||
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start, std::size_t length):
|
location_t::location_t(std::size_t line, std::size_t start, std::size_t code_start, std::size_t length):
|
||||||
location_t(empty, line, start, code_start, length) { }
|
location_t(empty, line, start, code_start, length) { }
|
||||||
location_t::location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length): filename(filename) {
|
location_t::location_t(const std::string &filename, std::size_t line, std::size_t start, std::size_t code_start, std::size_t length):
|
||||||
|
filename(filename) {
|
||||||
this->length = length;
|
this->length = length;
|
||||||
this->code_start = code_start;
|
this->code_start = code_start;
|
||||||
this->line = line;
|
this->line = line;
|
||||||
this->start = start;
|
this->start = start;
|
||||||
}
|
}
|
||||||
|
|
||||||
const location_t location_t::NONE = { };
|
const location_t location_t::NONE = {};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
#include "utils/message.hh"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "utils/message.hh"
|
|
||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
|
|
||||||
@ -10,15 +10,27 @@ namespace ppc::messages {
|
|||||||
std::string level_readable;
|
std::string level_readable;
|
||||||
|
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case message_t::DEBUG: level_readable = "debug"; break;
|
case message_t::DEBUG:
|
||||||
case message_t::SUGGESTION: level_readable = "suggestion"; break;
|
level_readable = "debug";
|
||||||
case message_t::INFO: level_readable = "info"; break;
|
break;
|
||||||
case message_t::WARNING: level_readable = "warning"; break;
|
case message_t::SUGGESTION:
|
||||||
case message_t::ERROR: level_readable = "error"; break;
|
level_readable = "suggestion";
|
||||||
default: level_readable = "what?"; break;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream res { };
|
std::stringstream res {};
|
||||||
|
|
||||||
if (loc_readable.length()) res << loc_readable << ": ";
|
if (loc_readable.length()) res << loc_readable << ": ";
|
||||||
res << level_readable << ": " << content;
|
res << level_readable << ": " << content;
|
||||||
@ -42,7 +54,7 @@ namespace ppc::messages {
|
|||||||
if (msg.level < threshold) continue;
|
if (msg.level < threshold) continue;
|
||||||
|
|
||||||
std::string loc_readable = msg.location.to_string();
|
std::string loc_readable = msg.location.to_string();
|
||||||
|
|
||||||
switch (msg.level) {
|
switch (msg.level) {
|
||||||
case message_t::DEBUG:
|
case message_t::DEBUG:
|
||||||
output << (color_output ? "\e[38;5;8mdebug: " : "debug: ");
|
output << (color_output ? "\e[38;5;8mdebug: " : "debug: ");
|
||||||
@ -51,7 +63,7 @@ namespace ppc::messages {
|
|||||||
output << (color_output ? "\e[38;5;45msuggestion: " : "suggestion: ");
|
output << (color_output ? "\e[38;5;45msuggestion: " : "suggestion: ");
|
||||||
break;
|
break;
|
||||||
case message_t::INFO:
|
case message_t::INFO:
|
||||||
output << (color_output ? "\e[38;5;33minfo: ": "info: ");
|
output << (color_output ? "\e[38;5;33minfo: " : "info: ");
|
||||||
break;
|
break;
|
||||||
case message_t::WARNING:
|
case message_t::WARNING:
|
||||||
output << (color_output ? "\e[38;5;214mwarning: " : "warning: ");
|
output << (color_output ? "\e[38;5;214mwarning: " : "warning: ");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <sstream>
|
|
||||||
#include "utils/strings.hh"
|
#include "utils/strings.hh"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
using namespace ppc;
|
using namespace ppc;
|
||||||
|
|
||||||
@ -11,10 +11,10 @@ std::vector<std::string> str::split(const std::string &splittable, std::initiali
|
|||||||
if (std::string { splitters }.find(c) == std::string::npos) {
|
if (std::string { splitters }.find(c) == std::string::npos) {
|
||||||
buff << c;
|
buff << c;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!buff.str().empty() || !remove_empty_entries) {
|
if (!buff.str().empty() || !remove_empty_entries) {
|
||||||
res.push_back(buff.str());
|
res.push_back(buff.str());
|
||||||
buff = { };
|
buff = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using namespace std::string_literals;
|
|||||||
|
|
||||||
threading::thread_t threading::thread_t::start_impl(void *func, void *args) {
|
threading::thread_t threading::thread_t::start_impl(void *func, void *args) {
|
||||||
DWORD id;
|
DWORD id;
|
||||||
HANDLE hnd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, args, 0, &id);
|
HANDLE hnd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, args, 0, &id);
|
||||||
|
|
||||||
if (!hnd) throw "Couldn't create thread."s;
|
if (!hnd) throw "Couldn't create thread."s;
|
||||||
return { hnd };
|
return { hnd };
|
||||||
@ -31,14 +31,14 @@ threading::thread_t::~thread_t() {
|
|||||||
|
|
||||||
threading::thread_t threading::thread_t::start_impl(void *func, void *args) {
|
threading::thread_t threading::thread_t::start_impl(void *func, void *args) {
|
||||||
pthread_t *handle = new pthread_t;
|
pthread_t *handle = new pthread_t;
|
||||||
pthread_create(handle, nullptr, (void* (*)(void *))func, args);
|
pthread_create(handle, nullptr, (void *(*) (void *) ) func, args);
|
||||||
return { handle };
|
return { handle };
|
||||||
}
|
}
|
||||||
int threading::thread_t::join() const {
|
int threading::thread_t::join() const {
|
||||||
return pthread_join(*(pthread_t*)handle, nullptr);
|
return pthread_join(*(pthread_t *) handle, nullptr);
|
||||||
}
|
}
|
||||||
threading::thread_t::~thread_t() {
|
threading::thread_t::~thread_t() {
|
||||||
delete (pthread_t*)handle;
|
delete (pthread_t *) handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user