Skip to content

Commit

Permalink
nyan: Dict data type.
Browse files Browse the repository at this point in the history
  • Loading branch information
heinezen committed Nov 21, 2020
1 parent c1b62b5 commit 32df34b
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 5 deletions.
1 change: 1 addition & 0 deletions nyan/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ add_library(nyan SHARED
value_token.cpp
value/boolean.cpp
value/container.cpp
value/dict.cpp
value/file.cpp
value/number.cpp
value/object.cpp
Expand Down
199 changes: 199 additions & 0 deletions nyan/value/dict.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Copyright 2020-2020 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "dict.h"

#include "orderedset.h"
#include "set.h"
#include "../error.h"
#include "../util.h"


namespace nyan {

Dict::Dict() = default;

Dict::Dict(std::unordered_map<ValueHolder,ValueHolder> &&values) {
for (auto &value : values) {
this->values.insert(std::move(value));
}
}


ValueHolder Dict::copy() const {
// TODO
// return {std::make_shared<Dict>(*this)};
return ValueHolder();
}


std::string Dict::str() const {
// same as repr(), except we use str().

std::ostringstream builder;
builder << "{";
builder << util::strjoin(
", ", this->values,
[] (const auto &val) {
return val.first->str() + ": " + val.second->str();
}
);
builder << "}";

return builder.str();
}


std::string Dict::repr() const {
// same as str(), except we use repr().

std::ostringstream builder;
builder << "{";
builder << util::strjoin(
", ", this->values,
[] (const auto &val) {
return val.first->repr() + ": " + val.second->repr();
}
);
builder << "}";

return builder.str();
}


const BasicType &Dict::get_type() const {
constexpr static BasicType type{
primitive_t::CONTAINER,
container_t::DICT,
};

return type;
}

void Dict::apply_value(const Value &value, nyan_op operation) {
auto dict_applier = [](auto &member_value, auto operand, nyan_op operation) {
switch (operation) {
case nyan_op::ASSIGN:
member_value.clear();
// fall through

// TODO
case nyan_op::UNION_ASSIGN:
case nyan_op::ADD_ASSIGN: {
for (auto &val : operand) {
member_value.insert(val);
}
break;
}

case nyan_op::INTERSECT_ASSIGN:
// TODO
break;

default:
throw InternalError{"unknown dict value application"};
}
};

auto set_applier = [](auto &member_value, auto operand, nyan_op operation) {
switch (operation) {
case nyan_op::SUBTRACT_ASSIGN: {
for (auto &val : operand) {
member_value.erase(val);
}
break;
}

case nyan_op::INTERSECT_ASSIGN:
// TODO
break;

default:
throw InternalError{"unknown dict value application"};
}
};


if (typeid(Set&) == typeid(value)) {
const Set *change = dynamic_cast<const Set *>(&value);

if (unlikely(change == nullptr)) {
using namespace std::string_literals;
throw InternalError{
"set value application was not a container, it was: "s
+ util::demangle(typeid(value).name())
+ " and couldn't cast to "
+ util::demangle(typeid(change).name())};
}

set_applier(this->values, change->get(), operation);

}
else if (typeid(OrderedSet&) == typeid(value)) {
const OrderedSet *change = dynamic_cast<const OrderedSet *>(&value);

if (unlikely(change == nullptr)) {
using namespace std::string_literals;
throw InternalError{
"set value application was not a container, it was: "s
+ util::demangle(typeid(value).name())
+ " and couldn't cast to "
+ util::demangle(typeid(change).name())};
}

set_applier(this->values, change->get(), operation);

}
else if (typeid(Dict&) == typeid(value)) {
const Dict *change = dynamic_cast<const Dict *>(&value);

if (unlikely(change == nullptr)) {
using namespace std::string_literals;
throw InternalError{
"set value application was not a container, it was: "s
+ util::demangle(typeid(value).name())
+ " and couldn't cast to "
+ util::demangle(typeid(change).name())};
}

dict_applier(this->values, change->get(), operation);
}
else {
throw InternalError("expected Container instance for operation, but got"
+ std::string(typeid(value).name()));
}


}

const std::unordered_set<nyan_op> &Dict::allowed_operations(const Type &with_type) const {

if (not with_type.is_container()) {
return no_nyan_ops;
}

const static std::unordered_set<nyan_op> set_ops{
nyan_op::SUBTRACT_ASSIGN,
nyan_op::INTERSECT_ASSIGN,
};

const static std::unordered_set<nyan_op> dict_ops{
nyan_op::ASSIGN,
nyan_op::ADD_ASSIGN,
nyan_op::UNION_ASSIGN,
nyan_op::INTERSECT_ASSIGN,
};

switch (with_type.get_container_type()) {
case container_t::SET:
case container_t::ORDEREDSET:
return set_ops;

case container_t::DICT:
return dict_ops;

default:
return no_nyan_ops;
}
}

} // namespace nyan
123 changes: 123 additions & 0 deletions nyan/value/dict.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2020-2020 the nyan authors, LGPLv3+. See copying.md for legal info.
#pragma once


#include <unordered_map>

#include "../api_error.h"
#include "../compiler.h"
#include "../util.h"
#include "container.h"
#include "value.h"


namespace nyan {

/**
* Container iterator for the Set.
*
* Used for walking over the contained values,
* i.e. it unpacks the ValueHolders!
*
*/
template<typename iter_type, typename elem_type>
class DictIterator : public ContainerIterBase<elem_type> {
public:
using this_type = DictIterator<iter_type, elem_type>;
using base_type = ContainerIterBase<elem_type>;

explicit DictIterator(iter_type &&iter)
:
iterator{std::move(iter)} {}

/**
* Advance the iterator to the next element in the dict.
*/
base_type &operator ++() override {
++this->iterator;
return *this;
}

/**
* Get the element the iterator is currently pointing to.
*/
elem_type &operator *() const override {
// unpack the ValueHolder!
return *(*this->iterator);
}

protected:
/**
* compare two iterators
*/
bool equals(const base_type &other) const override {
auto other_me = dynamic_cast<const this_type &>(other);
return (this->iterator == other_me.iterator);
}

/**
* The wrapped std::iterator, from the Set std::unordered_set.
*/
iter_type iterator;
};


/**
* Nyan value to store a dict/map/assocated array of things.
*
* T is the underlying storage type to store the Values.
*/
class Dict : Value {
public:
using value_storage = std::unordered_map<ValueHolder,ValueHolder>;
using key_type = typename value_storage::key_type;
using element_type = typename value_storage::value_type;
using value_const_iterator = typename value_storage::const_iterator;

Dict();
Dict(std::unordered_map<ValueHolder,ValueHolder> &&values);


size_t hash() const override {
throw APIError{"Dicts are not hashable."};
}


size_t size() const {
return this->values.size();
}


void clear() {
this->values.clear();
}


const value_storage &get() const {
return this->values;
}

ValueHolder copy() const override;
std::string str() const override;
std::string repr() const override;

const std::unordered_set<nyan_op> &allowed_operations(const Type &with_type) const override;
const BasicType &get_type() const override;

protected:
void apply_value(const Value &value, nyan_op operation) override;


bool equals(const Value &other) const override {
auto &other_val = dynamic_cast<const Dict &>(other);

return values == other_val.values;
}

/**
* Dict value storage (this is an unordered map).
*/
value_storage values;
};

} // namespace nyan
3 changes: 0 additions & 3 deletions nyan/value/set.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@

namespace nyan {

/** datatype used for unordered set storage */
using set_t = std::unordered_set<ValueHolder>;


/**
* Nyan value to store a unordered set of things.
Expand Down
4 changes: 2 additions & 2 deletions nyan/value/set_types.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019-2019 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2019-2020 the nyan authors, LGPLv3+. See copying.md for legal info.
#pragma once

#include <unordered_set>
Expand All @@ -9,7 +9,7 @@

namespace nyan {

/** datatype used for ordered set storage */
/** datatype used for (unordered) set storage */
using set_t = std::unordered_set<ValueHolder>;


Expand Down
3 changes: 3 additions & 0 deletions nyan/value/value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ ValueHolder Value::from_ast(const Type &target_type,
case container_t::ORDEREDSET:
return {std::make_shared<OrderedSet>(std::move(values))};

case container_t::DICT:
// TODO

default:
throw InternalError{"value creation for unhandled container type"};
}
Expand Down

0 comments on commit 32df34b

Please sign in to comment.