diff --git a/nyan/nyan_tool.cpp b/nyan/nyan_tool.cpp index 4d0ecee..6aaf976 100644 --- a/nyan/nyan_tool.cpp +++ b/nyan/nyan_tool.cpp @@ -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" @@ -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(base_path + "/" + filename); - } - ); + }); std::shared_ptr 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("member") - << std::endl; - - std::optional> optional_wat3 = first.get_optional("wat3", 0); + << *root->get_object("test.First").get("member") + << std::endl; - if (optional_wat3.has_value()) { - if ((*optional_wat3)->get_name() != "test.Second") { + std::optional> wat3_first = first.get_optional("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; } @@ -47,6 +46,18 @@ int test_parser(const std::string &base_path, const std::string &filename) { return 1; } + std::optional> wat3_second = second.get_optional("wat3", 0); + if (wat3_second.has_value()) { + std::cout << "Second.wat3 should be None" << std::endl; + return 1; + } + + std::optional> wat3_test = test.get_optional("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(); @@ -56,8 +67,8 @@ int test_parser(const std::string &base_path, const std::string &filename) { } } - optional_wat3 = first.get_optional("wat3"); - if (optional_wat3.has_value()) { + wat3_first = first.get_optional("wat3"); + if (wat3_first.has_value()) { std::cout << "First.wat3 should be None by patch" << std::endl; return 1; } @@ -65,8 +76,8 @@ int test_parser(const std::string &base_path, const std::string &filename) { auto value = *root->get_object("test.First").get("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; @@ -113,32 +124,35 @@ int test_parser(const std::string &base_path, const std::string &filename) { } std::cout << "after change: Second.member == " - << *second.get("member", 1) - << std::endl; + << *second.get("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; } @@ -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; @@ -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 -- 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 -- 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 argparse(int argc, char** argv) { +std::pair 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]; @@ -250,7 +265,6 @@ std::pair 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; @@ -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 diff --git a/nyan/object.cpp b/nyan/object.cpp index b73bdd1..f0d102e 100644 --- a/nyan/object.cpp +++ b/nyan/object.cpp @@ -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" @@ -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; diff --git a/test/test.nyan b/test/test.nyan index 2f5793b..c92e32a 100644 --- a/test/test.nyan +++ b/test/test.nyan @@ -28,6 +28,7 @@ Second(First): member *= 5.5 First.nice_member = False # nap : int + wat3 = None NestingBase(First):