feat: add basic lang structure
This commit is contained in:
parent
4d622c9570
commit
1cbd176929
@ -1,5 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ppc::lang {
|
||||
struct namespace_name_t : public std::vector<std::string> {
|
||||
using base = std::vector<std::string>;
|
||||
|
||||
int compare(const namespace_name_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; }
|
||||
|
||||
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()) { }
|
||||
};
|
||||
}
|
||||
|
||||
template <>
|
||||
struct std::hash<ppc::lang::namespace_name_t> {
|
||||
std::size_t operator()(const ppc::lang::namespace_name_t& k) const {
|
||||
size_t res = 0;
|
||||
|
||||
for (auto &el : k) {
|
||||
res ^= std::hash<std::string>()(el);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#include "utils/message.hh"
|
||||
#include "utils/location.hh"
|
||||
|
||||
@ -29,25 +65,6 @@ namespace ppc::lang {
|
||||
slocated_t() { }
|
||||
};
|
||||
|
||||
struct namespace_name_t : public std::vector<std::string> {
|
||||
using base = std::vector<std::string>;
|
||||
|
||||
int compare(const namespace_name_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; }
|
||||
|
||||
operator std::string() const { return to_string(); }
|
||||
std::string to_string() const;
|
||||
|
||||
namespace_name_t() { }
|
||||
namespace_name_t(std::initializer_list<std::string> segments): base(segments.begin(), segments.end()) { }
|
||||
};
|
||||
|
||||
struct loc_namespace_name_t : public std::vector<located_t<std::string>> {
|
||||
using base = std::vector<located_t<std::string>>;
|
||||
|
||||
@ -74,4 +91,4 @@ namespace ppc::lang {
|
||||
messages::msg_stack_t ms;
|
||||
return is_identifier_valid(ms, { }, name);
|
||||
}
|
||||
}
|
||||
}
|
162
include/lang/module.hh
Normal file
162
include/lang/module.hh
Normal file
@ -0,0 +1,162 @@
|
||||
#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,3 +1,4 @@
|
||||
#include "lang/module.hh"
|
||||
#include "compiler/treeifier/ast.hh"
|
||||
#include "compiler/treeifier/tokenizer.hh"
|
||||
#include "compiler/treeifier/ast/helper.hh"
|
||||
@ -18,28 +19,7 @@ static bool read_nmsp(ast_ctx_t &ctx, size_t &i, lang::loc_namespace_name_t &nam
|
||||
name = conv::map_to_nmsp(res);
|
||||
return h.submit(false);
|
||||
}
|
||||
template <class T>
|
||||
static bool resolve_nmsp(ast_ctx_t &ctx, const lang::namespace_name_t &name, T begin, T end, lang::namespace_name_t &actual_name) {
|
||||
for (auto it = begin; it != end; it++) {
|
||||
const namespace_name_t &curr = it->first;
|
||||
if (curr == name) {
|
||||
actual_name = name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const auto &import : ctx.imports) {
|
||||
auto new_name = name;
|
||||
new_name.insert(new_name.begin(), import.begin(), import.end());
|
||||
for (auto it = begin; it != end; it++) {
|
||||
const namespace_name_t &curr = it->first;
|
||||
if (curr == new_name) {
|
||||
actual_name = name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
group_t &group_t::insert(const std::string &name, parser_t parser, const std::string &relative_to, bool after) {
|
||||
if (parsers.find(name) != parsers.end()) {
|
||||
@ -94,10 +74,18 @@ bool group_t::operator()(ast_ctx_t &ctx, size_t &i, data::map_t &out) const {
|
||||
|
||||
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_nmsp(ctx, name.strip_location(), named_parsers.begin(), named_parsers.end(), actual)) {
|
||||
|
||||
if (resolve_name_map(
|
||||
named_parsers, names,
|
||||
name.strip_location(), actual
|
||||
)) {
|
||||
auto parser = parsers.find(this->named_parsers.find(actual)->second);
|
||||
out["$_name"] = parser->first;
|
||||
if (h.parse(parser->second, out)) return h.submit(false);
|
||||
|
88
src/lang/module.cc
Normal file
88
src/lang/module.cc
Normal file
@ -0,0 +1,88 @@
|
||||
#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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user