Compare commits

..

15 Commits

62 changed files with 833 additions and 1707 deletions

11
.gitignore vendored
View File

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

View File

@ -4,13 +4,36 @@ Well, first of all, thank you! It means a lot that you find this project worh yo
## Code of Conduct ## Code of Conduct
- Don't harass or bully anybody In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in this project and this community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
- Don't dox anyone
- Try to not be an asshole
- Don't go into useless arguments over stuff that ultimately doesn't matter, twitter is a better place for such stuff
- Mind your language, this is github, not 4chan
If you're being a jerk and don't contribute much to the project, you will be banned from discussions. ### Our Standards
**Examples of behavior that contributes to creating a positive environment include:**
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
- Examples of unacceptable behavior by participants include:
**Examples of unacceptable behavior by participants include:**
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
### Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting me at 36534413+TopchetoEU@users.noreply.github.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Confidentiality with regard to the reporter of an incident will be maintained. Further details of specific enforcement policies may be posted separately.
TLDR: Keep all interactions civil and constructive, don't be a jerk.
## Code style ## Code style

View File

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

View File

@ -47,7 +47,7 @@ Check out the [documentation](./doc/index.md) of this project, I've tried to mak
## How to contribute? ## How to contribute?
Any help is entirely voluntary, yet very much appreciated. If you see any bugs, please don't hesitate to report them (as issue logs) and if you feel like you could add to this project's worth, please do make a pull request. Just make sure to check the [contribuitng requirements](./CONTRIBUTING.md). Any help is entirely voluntary, yet very much appreciated. If you see any bugs, please don't hesitate to report them (as issue logs) and if you feel like you could add to this project's worth, please do make a pull request. Just make sure to check the [contribuitng requirements](./CONTRIBUTING.md)
## How to compile? ## How to compile?
@ -73,4 +73,4 @@ For now, there's no official support, but the build scripts should in theory wor
## Licensing ## Licensing
The project uses the Creative Commons Attributuins Non-Commersial license. This license was picked since I wanted to allow anyone to use my project for non-commersial purposes for free. If you're interested in using this project for commersial purposes, contact me at ppc.lang.contact@gmail.com. The project uses the Creative Commons Attributuins Non-Commersial license. This license was picked since I wanted to allow anyone to use my project for non-commersial purposes for free. If you're interested in using this project for commersial purposes, contact me at 36534413+TopchetoEU@users.noreply.github.com

View File

3
deps/main vendored Normal file
View File

@ -0,0 +1,3 @@
utils
treeifier
lang

2
deps/treeifier vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

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

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

View File

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

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

View File

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

View File

@ -116,5 +116,5 @@ namespace ppc::data {
} }
}; };
class array_t : public std::vector<value_t> { }; class array_t: public std::vector<value_t> { };
} }

View File

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

View File

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

View File

@ -1,3 +0,0 @@
$(lsproj): $(src)/lsproj.cc
$(call mkdir,$(dir $@))
$(CXX) $^ -o $@

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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: ");

View File

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

View File

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