Skip to content

Fix Fiesta #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 12, 2023
10 changes: 8 additions & 2 deletions nyan/ast.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2016-2023 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "ast.h"

Expand Down Expand Up @@ -301,7 +301,9 @@ void ASTObject::ast_members(TokenStream &tokens) {
bool object_next = false;
auto lookahead = tokens.next();

if (lookahead->type == token_type::OPERATOR or lookahead->type == token_type::COLON) {
if (lookahead->type == token_type::OPERATOR // value assignment
or lookahead->type == token_type::COLON // type declaration
or lookahead->type == token_type::DOT) { // inherited member access (e.g. Parent.some_member)
object_next = false;
}
else if (lookahead->type == token_type::LANGLE or lookahead->type == token_type::LBRACKET or lookahead->type == token_type::LPAREN) {
Expand Down Expand Up @@ -340,6 +342,10 @@ void ASTObject::ast_members(TokenStream &tokens) {

token = tokens.next();
}

if (token->type == token_type::ENDFILE) {
tokens.reinsert_last();
}
}


Expand Down
3 changes: 3 additions & 0 deletions nyan/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ constexpr const order_t LATEST_T = std::numeric_limits<order_t>::max();
/** fully-qualified object name */
using fqon_t = std::string;

/** fully-qualified namespace name */
using fqnn_t = fqon_t;

/** member name identifier type */
using memberid_t = std::string;

Expand Down
93 changes: 72 additions & 21 deletions nyan/database.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2017-2023 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "database.h"

Expand Down Expand Up @@ -90,13 +90,16 @@ void Database::load(const std::string &filename,
// the location is the first request origin.
std::unordered_map<Namespace, Location> to_import;

// push the first namespace to import
to_import.insert(
{
Namespace::from_filename(filename),
Location{" -> requested by native call to Database::load()"}
}
);
auto file_ns = Namespace::from_filename(filename);
if (not this->meta_info.has_namespace(file_ns.to_fqon())) {
// push the first namespace to import
to_import.insert(
{
file_ns,
Location{" -> requested by native call to Database::load()"}
}
);
}

// descend to all imports and load the files
while (to_import.size() > 0) {
Expand Down Expand Up @@ -147,15 +150,16 @@ void Database::load(const std::string &filename,
}

// check if this import was already requested or is known.
// todo: also check if that ns is already fully loaded in the db
auto was_imported = imports.find(request);
auto import_requested = to_import.find(request);

if (was_imported == std::end(imports) and
import_requested == std::end(to_import)) {

// add the request to the pending imports
to_import.insert({std::move(request), import.get()});
if (not this->meta_info.has_namespace(request.to_fqon())) {
// add the request to the pending imports
to_import.insert({std::move(request), import.get()});
}
}
}

Expand Down Expand Up @@ -214,7 +218,11 @@ void Database::load(const std::string &filename,
throw InternalError{"object info could not be retrieved"};
}

info->set_children(std::move(children));
info->add_children(std::move(children));
}

for (auto loaded: imports) {
this->meta_info.add_namespace(loaded.first);
}

// TODO: check pending objectvalues (probably not needed as they're all loaded)
Expand Down Expand Up @@ -283,11 +291,14 @@ void Database::create_obj_content(std::vector<fqon_t> *new_objs,
fqon_t parent_id = scope.find(ns, parent, this->meta_info);

// this object is therefore a child of the parent one.
auto ins = child_assignments->emplace(
parent_id,
std::unordered_set<fqon_t>{}
);
ins.first->second.insert(obj_fqon);
auto ins = child_assignments->find(parent_id);
if (ins == std::end(*child_assignments)) {
ins = child_assignments->emplace(
parent_id,
std::unordered_set<fqon_t>{}
).first;
}
ins->second.insert(obj_fqon);

object_parents.push_back(std::move(parent_id));
}
Expand Down Expand Up @@ -367,6 +378,19 @@ void Database::find_member(bool skip_first,

bool finished = false;

// if the member is inherited, it can be prefixed with the ID
// of the object it's inherited from, e.g. ParentObj.some_member
memberid_t member_name = member_id;
std::optional<fqon_t> member_obj_id = std::nullopt;
std::vector<std::string> member_parts = util::split(member_id, '.');
if (member_parts.size() > 1) {
member_name = member_parts.back();
member_parts.pop_back();

// TODO: we might need to resolve aliases here
member_obj_id = util::strjoin(".", member_parts);
}

// member doesn't have type yet. find it.
for (auto &obj : search_objs) {

Expand All @@ -377,22 +401,35 @@ void Database::find_member(bool skip_first,
continue;
}

// TODO: if the obj fqon is prefixed, we can skip objects that don't match
// TODO: This requires that aliases and fqons are properly resolved
// if (member_obj_id and member_obj_id != obj) {
// continue;
// }

ObjectInfo *obj_info = this->meta_info.get_object(obj);
if (unlikely(obj_info == nullptr)) {
throw InternalError{"object information not retrieved"};
}
const MemberInfo *obj_member_info = obj_info->get_member(member_id);
const MemberInfo *obj_member_info = obj_info->get_member(member_name);

// obj doesn't have this member
if (not obj_member_info) {
// TODO: fail here if the member is prefixed with the parent fqon
// but the object doesn't have the member
// TODO: This requires that aliases and fqons are properly resolved
// if (unlikely(member_obj_id)) {
// throw InternalError{"specified parent object doesn't have the member"};
// }

continue;
}

const ObjectState *par_state = this->state->get(obj)->get();
if (unlikely(par_state == nullptr)) {
throw InternalError{"object state not retrieved"};
}
const Member *member = par_state->get(member_id);
const Member *member = par_state->get(member_name);

finished = member_found(obj, *obj_member_info, member);

Expand All @@ -412,7 +449,7 @@ void Database::find_member(bool skip_first,
// recurse into the target.
// check if the patch defines the member as well -> error.
// otherwise, infer type from patch.
this->find_member(false, member_id,
this->find_member(false, member_name,
obj_info->get_linearization(),
*obj_info, member_found);
}
Expand Down Expand Up @@ -782,12 +819,26 @@ void Database::check_hierarchy(const std::vector<fqon_t> &new_objs,

for (auto &it : state_members) {
const memberid_t &member_id = it.first;

// if the member is inherited, its ID can be prefixed with the ID
// of the object it's inherited from, e.g. ParentObj.some_member
memberid_t member_name = member_id;
std::optional<fqon_t> member_obj_id = std::nullopt;
std::vector<std::string> member_parts = util::split(member_id, '.');
if (member_parts.size() > 1) {
member_name = member_parts.back();
member_parts.pop_back();

// TODO: resolve aliases here
member_obj_id = util::strjoin(".", member_parts);
}

const Member &member = it.second;
nyan_op op = member.get_operation();

// member has = operation, so it's no longer pending.
if (op == nyan_op::ASSIGN) {
pending_members.erase(member_id);
pending_members.erase(member_name);
}
}
}
Expand Down
23 changes: 22 additions & 1 deletion nyan/meta_info.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2017-2023 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "meta_info.h"

Expand Down Expand Up @@ -50,6 +50,27 @@ bool MetaInfo::has_object(const fqon_t &name) const {
return this->object_info.count(name) == 1;
}

Namespace &MetaInfo::add_namespace(const Namespace &ns) {
auto ret = this->namespaces.insert({fqnn_t(ns.to_fqon()), ns});

return ret.first->second;
}

Namespace *MetaInfo::get_namespace(const fqnn_t &name) {
return const_cast<Namespace *>(std::as_const(*this).get_namespace(name));
}

const Namespace *MetaInfo::get_namespace(const fqnn_t &name) const {
auto it = this->namespaces.find(name);
if (it == std::end(this->namespaces)) {
return nullptr;
}
return &it->second;
}

bool MetaInfo::has_namespace(const fqnn_t &name) const {
return this->namespaces.contains(name);
}

std::string MetaInfo::str() const {
std::ostringstream builder;
Expand Down
45 changes: 44 additions & 1 deletion nyan/meta_info.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2017-2023 the nyan authors, LGPLv3+. See copying.md for legal info.
#pragma once

#include <memory>
Expand All @@ -7,6 +7,7 @@

#include "config.h"
#include "object_info.h"
#include "namespace.h"


namespace nyan {
Expand All @@ -18,6 +19,7 @@ namespace nyan {
class MetaInfo {
public:
using obj_info_t = std::unordered_map<fqon_t, ObjectInfo>;
using ns_info_t = std::unordered_map<fqnn_t, Namespace>;

MetaInfo() = default;
~MetaInfo() = default;
Expand Down Expand Up @@ -69,6 +71,42 @@ class MetaInfo {
*/
bool has_object(const fqon_t &name) const;

/**
* Add a namespace to the database.
*
* @param ns Namespace to add.
*
* @return The stored namespace.
*/
Namespace &add_namespace(const Namespace &ns);

/**
* Get a namespace from the database.
*
* @param name Identifier of the namespace.
*
* @return The stored namespace.
*/
Namespace *get_namespace(const fqnn_t &name);

/**
* Get a namespace from the database.
*
* @param name Identifier of the namespace.
*
* @return The stored namespace.
*/
const Namespace *get_namespace(const fqnn_t &name) const;

/**
* Check if a namespace is in the database.
*
* @param name Identifier of the namespace.
*
* @return true if the namespace is in the database, else false.
*/
bool has_namespace(const fqnn_t &name) const;

/**
* Get a string representation of all metadata information objects.
*
Expand All @@ -82,6 +120,11 @@ class MetaInfo {
* This is for displaying error messages and line information.
*/
obj_info_t object_info;

/**
* Namespaces loaded in the database.
*/
ns_info_t namespaces;
};

} // namespace nyan
29 changes: 25 additions & 4 deletions nyan/namespace.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2016-2023 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "namespace.h"

Expand Down Expand Up @@ -94,9 +94,30 @@ Namespace Namespace::from_filename(const std::string &filename) {
throw APIError{"there's too many dots in the path"};
}

// strip off the file extension
std::string namespace_name{filename, 0, filename.size() - extension.size()};
std::replace(namespace_name.begin(), namespace_name.end(), '/', '.');
// sanitize the filename
// TODO: Do this via a file API
std::string namespace_name;
char prev_char;
char cur_char;
// condition strips off file extension
for (size_t i = 0; i < filename.size() - extension.size(); ++i) {
cur_char = filename[i];

// slashes get replaced with dots
if (cur_char == '/') {
// strip multiple slashes
if (prev_char == '/') {
continue;
}
namespace_name += '.';
}
// normal chars get copied
else {
namespace_name += cur_char;
}

prev_char = cur_char;
}

// the fqon_t constructor.
return Namespace{namespace_name};
Expand Down
7 changes: 6 additions & 1 deletion nyan/object_info.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2021 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2017-2023 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "object_info.h"

Expand Down Expand Up @@ -104,6 +104,11 @@ const std::vector<fqon_t> &ObjectInfo::get_linearization() const {
}


void ObjectInfo::add_children(std::unordered_set<fqon_t> &&children) {
this->initial_children.insert(children.begin(), children.end());
}


void ObjectInfo::set_children(std::unordered_set<fqon_t> &&children) {
this->initial_children = std::move(children);
}
Expand Down
Loading