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