From 35996484b2eb2cce769172f10f1102ad091e86e1 Mon Sep 17 00:00:00 2001 From: bog Date: Sat, 14 Oct 2023 22:07:36 +0200 Subject: [PATCH] :sparkles: extension selector. --- doc/grammar.bnf | 3 +- src/Interpreter.cpp | 95 +++++++++++++++++++++++++++++-------------- src/Interpreter.hpp | 2 +- src/Parser.cpp | 7 ++++ tests/Interpreter.cpp | 44 +++++++++++++++++++- tests/Parser.cpp | 29 +++++++++++++ 6 files changed, 146 insertions(+), 34 deletions(-) diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 978a4bc..78ec232 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -9,4 +9,5 @@ LITERAL ::= ident | var | ARRAY | INDEX VAR_DECL ::= var assign (LITERAL | ARRAY | INDEX) ARRAY ::= opar LITERAL* cpar -INDEX ::= (var|ARRAY) osquare ident csquare +INDEX ::= +| (var|ARRAY) osquare ident (assign ident)? csquare diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index ff97963..c533cfa 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -135,7 +135,7 @@ namespace sn } std::vector - Interpreter::get_value(std::shared_ptr node) + Interpreter::get_value(std::shared_ptr node) const { if (node->type() == NODE_IDENT) { @@ -167,20 +167,67 @@ namespace sn auto var = *node->get(0); auto val = *node->get(1); - auto values = get_value(var); - ssize_t index = std::stoi(val->repr()); - - if (index < 0) + if (node->size() > 2) + // Extension replacement { - index = values.size() + index; - } + auto old_values = get_value(var); + std::vector values; + std::string src_extension = val->repr(); + std::string dest_extension = (*node->get(2))->repr(); - if (index >= static_cast(values.size())) + std::transform(std::begin(old_values), std::end(old_values), + std::back_inserter(values), + [src_extension, dest_extension] + (auto const& val){ + auto val_p = std::filesystem::path(val); + + if (val_p.has_extension() + && val_p.extension() == src_extension) + { + return val_p.replace_extension(dest_extension); + } + else + { + return val_p; + } + }); + + return values; + } + else if (val->repr().size() > 0 && val->repr()[0] == '.') + // Extension modifier { - throw run_error {"invalid index '" + std::to_string(index) + "'"}; - } + auto old_values = get_value(var); + std::vector values; + std::string extension = val->repr(); - return { values[index] }; + std::transform(std::begin(old_values), std::end(old_values), + std::back_inserter(values), + [extension](auto const& val){ + auto val_p = std::filesystem::path(val); + return val_p.replace_extension(extension); + }); + + return values; + } + else + // Index selector + { + auto values = get_value(var); + ssize_t index = std::stoi(val->repr()); + + if (index < 0) + { + index = values.size() + index; + } + + if (index >= static_cast(values.size())) + { + throw run_error {"invalid index '" + std::to_string(index) + "'"}; + } + + return { values[index] }; + } } throw run_error {"cannot find value for '" @@ -289,33 +336,19 @@ namespace sn auto cmd = *block->get(i); std::string script; - std::string sep; for (size_t j=0; jsize(); j++) { auto c = *cmd->get(j); - if (c->type() == NODE_IDENT) - { - script += sep + c->repr(); - } - else - { - auto var = *m_sym.get(c->repr()); - std::string vsep; + auto values = get_value(c); + std::string vsep = (j > 0) ? " " : ""; - if (j > 0) - { - vsep = " "; - } - for (auto const& v: var.values) - { - script += vsep + v; - vsep = " "; - } + for (auto val: values) + { + script += vsep + val; + vsep = " "; } - - sep = " "; } result.push_back(script); diff --git a/src/Interpreter.hpp b/src/Interpreter.hpp index 3a5468c..aa85392 100644 --- a/src/Interpreter.hpp +++ b/src/Interpreter.hpp @@ -41,7 +41,7 @@ namespace sn std::vector> m_scripts; SymTable m_sym; - std::vector get_value(std::shared_ptr node); + std::vector get_value(std::shared_ptr node) const; std::vector targets(std::filesystem::path path) const; diff --git a/src/Parser.cpp b/src/Parser.cpp index 5d82570..7d4b144 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -262,6 +262,13 @@ namespace sn consume(NODE_OSQUARE); node->add_child(*consume(NODE_IDENT)); + + if (type_is(NODE_ASSIGN)) + { + consume(); + node->add_child(*consume(NODE_IDENT)); + } + consume(NODE_CSQUARE); return node; diff --git a/tests/Interpreter.cpp b/tests/Interpreter.cpp index b37c62b..095adda 100644 --- a/tests/Interpreter.cpp +++ b/tests/Interpreter.cpp @@ -227,7 +227,7 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_index") } } -TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_literal_index", "[.]") +TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_literal_index") { SECTION("get second: ok") { @@ -277,3 +277,45 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_literal_index", "[.]") test_not_contains("executed", res); } } + +TEST_CASE_METHOD(InterpreterTest, "Interpreter_select_ext") +{ + SECTION("on var") + { + std::stringstream ss; + ss << "$Y = g.h" << std::endl; + ss << "d -> a {" << std::endl; + ss << "$Y $Y[.hpp] $Y[.cpp]" << std::endl; + ss << "}" << std::endl; + + auto res = TEST_RUN(ss.str(), std::filesystem::path("a")); + test_contains("g.h g.hpp g.cpp", res); + } + + SECTION("on array") + { + std::stringstream ss; + ss << "$Y = (x.c y.c z.d)" << std::endl; + ss << "d -> a {" << std::endl; + ss << "$Y[.cpp]" << std::endl; + ss << "}" << std::endl; + + auto res = TEST_RUN(ss.str(), std::filesystem::path("a")); + test_contains("x.cpp y.cpp z.cpp", res); + } +} + +TEST_CASE_METHOD(InterpreterTest, "Interpreter_replace_ext") +{ + SECTION("on array") + { + std::stringstream ss; + ss << "$Y = (x.c y.c z.d w t.h)" << std::endl; + ss << "d -> a {" << std::endl; + ss << "$Y[.c=.h]" << std::endl; + ss << "}" << std::endl; + + auto res = TEST_RUN(ss.str(), std::filesystem::path("a")); + test_contains("x.h y.h z.d w t.h", res); + } +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index 5238c65..f0e3a10 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -187,3 +187,32 @@ TEST_CASE_METHOD(ParserTest, "Parser_array_index_literal") ")))", ss.str()); } + +TEST_CASE_METHOD(ParserTest, "Parser_replace_ext_index") +{ + std::stringstream ss; + ss << "$BIM = hello.cpp" << std::endl; + ss << "$BAM = (world.hpp world.cpp)[14]" << std::endl; + ss << " $BIM -> (hello.cpp world.cpp) {" << std::endl; + ss << " g++ $BIM[.c=.o] -o hello.elf, " << std::endl; + ss << " ls " << std::endl; + ss << " }" << std::endl; + + test_parse("DOC(" + "VAR_DECL(VAR[BIM],IDENT[hello.cpp])," + "VAR_DECL(VAR[BAM]," + "INDEX(ARRAY(IDENT[world.hpp],IDENT[world.cpp]),IDENT[14]))," + "RULE(" + "TARGET(" + "VAR[BIM]" + "),DEPS(" + "ARRAY(IDENT[hello.cpp],IDENT[world.cpp])" + "),BLOCK(" + "CMD(" + "IDENT[g++],INDEX(VAR[BIM],IDENT[.c],IDENT[.o]),IDENT[-o],IDENT[hello.elf]" + "),CMD(" + "IDENT[ls]" + ")" + ")))", + ss.str()); +}