Skip to content

Commit

Permalink
fix: Prevent reassignment of base value when retrieving None.
Browse files Browse the repository at this point in the history
  • Loading branch information
heinezen committed Sep 15, 2024
1 parent f77960b commit 03d0268
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 67 deletions.
134 changes: 74 additions & 60 deletions nyan/nyan_tool.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-2024 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "nyan_tool.h"

Expand All @@ -20,24 +20,23 @@ int test_parser(const std::string &base_path, const std::string &filename) {

db->load(
filename,
[&base_path] (const std::string &filename) {
[&base_path](const std::string &filename) {
return std::make_shared<File>(base_path + "/" + filename);
}
);
});

std::shared_ptr<View> root = db->new_view();

Object test = root->get_object("test.Test");
Object second = root->get_object("test.Second");
Object first = root->get_object("test.First");

std::cout << "before change: First.member == "
<< *root->get_object("test.First").get<Int>("member")
<< std::endl;

std::optional<std::shared_ptr<Object>> optional_wat3 = first.get_optional<Object>("wat3", 0);
<< *root->get_object("test.First").get<Int>("member")
<< std::endl;

if (optional_wat3.has_value()) {
if ((*optional_wat3)->get_name() != "test.Second") {
std::optional<std::shared_ptr<Object>> wat3_first = first.get_optional<Object>("wat3", 0);
if (wat3_first.has_value()) {
if ((*wat3_first)->get_name() != "test.Second") {
std::cout << "First.wat3 has wrong value at t=0" << std::endl;
return 1;
}
Expand All @@ -47,6 +46,18 @@ int test_parser(const std::string &base_path, const std::string &filename) {
return 1;
}

std::optional<std::shared_ptr<Object>> wat3_second = second.get_optional<Object, true>("wat3", 0);
if (wat3_second.has_value()) {
std::cout << "Second.wat3 should be None" << std::endl;
return 1;
}

std::optional<std::shared_ptr<Object>> wat3_test = test.get_optional<Object, true>("wat3", 0);
if (wat3_test.has_value()) {
std::cout << "Test.wat3 should be None" << std::endl;
return 1;
}

Object patch = root->get_object("test.FirstPatch");
for (int i = 0; i < 3; i++) {
Transaction tx = root->new_transaction();
Expand All @@ -56,17 +67,17 @@ int test_parser(const std::string &base_path, const std::string &filename) {
}
}

optional_wat3 = first.get_optional<Object>("wat3");
if (optional_wat3.has_value()) {
wat3_first = first.get_optional<Object>("wat3");
if (wat3_first.has_value()) {
std::cout << "First.wat3 should be None by patch" << std::endl;
return 1;
}

auto value = *root->get_object("test.First").get<Int>("member");

std::cout << "after change: First.member == "
<< value.str()
<< std::endl;
<< value.str()
<< std::endl;

if (value != 24) {
std::cout << "patch result is wrong" << std::endl;
Expand Down Expand Up @@ -113,32 +124,35 @@ int test_parser(const std::string &base_path, const std::string &filename) {
}

std::cout << "after change: Second.member == "
<< *second.get<Int>("member", 1)
<< std::endl;
<< *second.get<Int>("member", 1)
<< std::endl;

std::cout << "SetTest.member = "
<< root->get_object("test.SetTest").get_value("member")->str()
<< std::endl
<< "SetTest.orderedmember = "
<< root->get_object("test.SetTest").get_value("orderedmember")->str()
<< std::endl
<< "Fifth.truth = "
<< root->get_object("test.Fifth").get_value("truth")->str()
<< std::endl
<< "PATCH"
<< std::endl
<< "SetTest.member = "
<< root->get_object("test.SetTest").get_value("member", 1)->str()
<< std::endl
<< "SetTest.orderedmember = "
<< root->get_object("test.SetTest").get_value("orderedmember", 1)->str()
<< std::endl << std::endl;
<< root->get_object("test.SetTest").get_value("member")->str()
<< std::endl
<< "SetTest.orderedmember = "
<< root->get_object("test.SetTest").get_value("orderedmember")->str()
<< std::endl
<< "Fifth.truth = "
<< root->get_object("test.Fifth").get_value("truth")->str()
<< std::endl
<< "PATCH"
<< std::endl
<< "SetTest.member = "
<< root->get_object("test.SetTest").get_value("member", 1)->str()
<< std::endl
<< "SetTest.orderedmember = "
<< root->get_object("test.SetTest").get_value("orderedmember", 1)->str()
<< std::endl
<< std::endl;

std::cout << "test.gschicht parents = " << util::strjoin(", ", root->get_object("test.Test").get_parents())
<< std::endl << "PATCH" << std::endl
<< "test.gschicht parents = " << util::strjoin(", ", root->get_object("test.Test").get_parents(1))
<< std::endl << "newvalue = " << root->get_object("test.Test").get_value("new_value", 1)->str()
<< std::endl;
<< std::endl
<< "PATCH" << std::endl
<< "test.gschicht parents = " << util::strjoin(", ", root->get_object("test.Test").get_parents(1))
<< std::endl
<< "newvalue = " << root->get_object("test.Test").get_value("new_value", 1)->str()
<< std::endl;

return ret;
}
Expand Down Expand Up @@ -167,20 +181,22 @@ int run(flags_t flags, params_t params) {
}
catch (LangError &err) {
std::cout << "\x1b[33;1mfile error:\x1b[m\n"
<< err << std::endl
<< err.show_problem_origin()
<< std::endl << std::endl;
<< err << std::endl
<< err.show_problem_origin()
<< std::endl
<< std::endl;
return 1;
}
}
else {
std::cout << "no action selected" << std::endl << std::endl;
std::cout << "no action selected" << std::endl
<< std::endl;
help();
}
}
catch (Error &err) {
std::cout << "\x1b[31;1merror:\x1b[m\n"
<< err << std::endl;
<< err << std::endl;
return 1;
}
return 0;
Expand All @@ -189,30 +205,29 @@ int run(flags_t flags, params_t params) {

void help() {
std::cout << "\x1b[32;1mnyan\x1b[m - "
"\x1b[32;1my\x1b[met "
"\x1b[32;1ma\x1b[mnother "
"\x1b[32;1mn\x1b[motation "
"-- tool" << std::endl
<< std::endl
<< "usage:" << std::endl
<< "-h --help -- show this" << std::endl
<< "-f --file <filename> -- file to load" << std::endl
<< "-b --break -- debug-break on error" << std::endl
<< " --test-parser -- test the parser" << std::endl
<< " --echo -- print the ast" << std::endl
<< "" << std::endl;
"\x1b[32;1my\x1b[met "
"\x1b[32;1ma\x1b[mnother "
"\x1b[32;1mn\x1b[motation "
"-- tool"
<< std::endl
<< std::endl
<< "usage:" << std::endl
<< "-h --help -- show this" << std::endl
<< "-f --file <filename> -- file to load" << std::endl
<< "-b --break -- debug-break on error" << std::endl
<< " --test-parser -- test the parser" << std::endl
<< " --echo -- print the ast" << std::endl
<< "" << std::endl;
}


std::pair<flags_t, params_t> argparse(int argc, char** argv) {
std::pair<flags_t, params_t> argparse(int argc, char **argv) {
flags_t flags{
{option_flag::ECHO, false},
{option_flag::TEST_PARSER, false}
};
{option_flag::TEST_PARSER, false}};

params_t params{
{option_param::FILE, ""}
};
{option_param::FILE, ""}};

for (int option_index = 1; option_index < argc; ++option_index) {
std::string arg = argv[option_index];
Expand Down Expand Up @@ -250,7 +265,6 @@ std::pair<flags_t, params_t> argparse(int argc, char** argv) {


int main(int argc, char **argv) {

auto args = nyan::argparse(argc, argv);
nyan::flags_t flags = args.first;
nyan::params_t params = args.second;
Expand All @@ -265,7 +279,7 @@ int main(int argc, char **argv) {
}
catch (std::exception &exc) {
std::cout << "\x1b[31;1mfatal error:\x1b[m "
<< exc.what() << std::endl;
<< exc.what() << std::endl;
return 1;
}
#endif
Expand Down
15 changes: 8 additions & 7 deletions nyan/object.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2023 the nyan authors, LGPLv3+. See copying.md for legal info.
// Copyright 2016-2024 the nyan authors, LGPLv3+. See copying.md for legal info.

#include "object.h"

Expand Down Expand Up @@ -170,15 +170,16 @@ ValueHolder Object::calculate_value(const memberid_t &member, order_t t) const {
ValueHolder result = base_value->copy();

// walk back and apply the value changes
while (true) {
const Member *change = parents[defined_by]->get(member);

// skip the parent that assigns the value
// this prevents reassignment errors e.g. from assigning None
int parent_idx = defined_by - 1;
while (parent_idx >= 0) {
const Member *change = parents[parent_idx]->get(member);
if (change != nullptr) {
result->apply(*change);
}
if (defined_by == 0) {
break;
}
defined_by -= 1;
parent_idx -= 1;
}

return result;
Expand Down
1 change: 1 addition & 0 deletions test/test.nyan
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Second(First):
member *= 5.5
First.nice_member = False
# nap : int
wat3 = None

NestingBase(First):

Expand Down

0 comments on commit 03d0268

Please sign in to comment.