array index selector.

main
bog 2023-10-14 21:20:39 +02:00
parent af7f6768fd
commit c0aecff8b3
9 changed files with 235 additions and 6 deletions

View File

@ -5,7 +5,8 @@ DEPS ::= LITERAL*
BLOCK ::= obrace CMD_LST cbrace
CMD_LST ::= (CMD (comma CMD)* comma?)?
CMD ::= LITERAL*
LITERAL ::= ident | var | ARRAY
LITERAL ::= ident | var | ARRAY | INDEX
VAR_DECL ::= var assign (LITERAL | ARRAY)
VAR_DECL ::= var assign (LITERAL | ARRAY | INDEX)
ARRAY ::= opar LITERAL* cpar
INDEX ::= (var|ARRAY) osquare ident csquare

View File

@ -162,6 +162,26 @@ namespace sn
return values;
}
else if (node->type() == NODE_INDEX)
{
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)
{
index = values.size() + index;
}
if (index >= static_cast<ssize_t>(values.size()))
{
throw run_error {"invalid index '" + std::to_string(index) + "'"};
}
return { values[index] };
}
throw run_error {"cannot find value for '"
+ SN_GET(NodeTypeStr, node->type(), "NODE_")

View File

@ -9,6 +9,9 @@ namespace sn
m_separators.push_back('\n');
m_separators.push_back(' ');
add_text("[", NODE_OSQUARE);
add_text("]", NODE_CSQUARE);
add_text("(", NODE_OPAR);
add_text(")", NODE_CPAR);
add_text("=", NODE_ASSIGN);

View File

@ -8,7 +8,8 @@
G(NODE_CBRACE), G(NODE_CMD), G(NODE_CMD_LST), G(NODE_COMMA), \
G(NODE_BLOCK), G(NODE_TARGET), G(NODE_DEPS), G(NODE_RULE), \
G(NODE_VAR), G(NODE_ASSIGN), G(NODE_VAR_DECL), G(NODE_OPAR), \
G(NODE_CPAR), G(NODE_ARRAY)
G(NODE_CPAR), G(NODE_ARRAY), G(NODE_INDEX), G(NODE_OSQUARE), \
G(NODE_CSQUARE)
namespace sn
{

View File

@ -180,6 +180,12 @@ namespace sn
std::shared_ptr<Node> Parser::parse_literal()
{
if (type_is(NODE_VAR)
&& type_is(NODE_OSQUARE, 1))
{
return parse_index(*consume(NODE_VAR));
}
if (type_is(NODE_IDENT)
|| type_is(NODE_VAR))
{
@ -188,7 +194,14 @@ namespace sn
if (type_is(NODE_OPAR))
{
return parse_array();
auto array = parse_array();
if (type_is(NODE_OSQUARE))
{
return parse_index(array);
}
return array;
}
throw syntax_error {"unknown token '"
@ -206,7 +219,16 @@ namespace sn
if (type_is(NODE_OPAR))
{
node->add_child(parse_array());
auto array = parse_array();
if (type_is(NODE_OSQUARE))
{
node->add_child(parse_index(array));
}
else
{
node->add_child(array);
}
}
else
{
@ -231,4 +253,17 @@ namespace sn
return node;
}
std::shared_ptr<Node> Parser::parse_index(std::shared_ptr<Node> lhs)
{
auto node = std::make_shared<Node>(NODE_INDEX);
node->add_child(lhs);
consume(NODE_OSQUARE);
node->add_child(*consume(NODE_IDENT));
consume(NODE_CSQUARE);
return node;
}
}

View File

@ -41,6 +41,7 @@ namespace sn
std::shared_ptr<Node> parse_literal();
std::shared_ptr<Node> parse_var_decl();
std::shared_ptr<Node> parse_array();
std::shared_ptr<Node> parse_index(std::shared_ptr<Node> lhs);
};
}

View File

@ -84,6 +84,13 @@ public:
!= std::end(vec));
}
void test_not_contains(std::string const& str, std::vector<std::string> vec)
{
INFO("'" << str << "' found");
REQUIRE(std::find(std::begin(vec), std::end(vec), str)
== std::end(vec));
}
protected:
};
@ -168,3 +175,105 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_var")
}
}
TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_index")
{
SECTION("get second: ok")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "d -> $X[1] {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_contains("executed", res);
}
SECTION("get second: not ok")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "d -> $X[1] {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_not_contains("executed", res);
}
SECTION("get last: ok")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "d -> $X[-1] {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("c"));
test_contains("executed", res);
}
SECTION("get last: not ok")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "d -> $X[-1] {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_not_contains("executed", res);
}
}
TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_literal_index", "[.]")
{
SECTION("get second: ok")
{
std::stringstream ss;
ss << "$X = (a b c)[1]" << std::endl;
ss << "d -> $X {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_contains("executed", res);
}
SECTION("get second: not ok")
{
std::stringstream ss;
ss << "$X = (a b c)[1]" << std::endl;
ss << "d -> $X {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_not_contains("executed", res);
}
SECTION("get last: ok")
{
std::stringstream ss;
ss << "$X = (a b c)[-1]" << std::endl;
ss << "d -> $X {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("c"));
test_contains("executed", res);
}
SECTION("get last: not ok")
{
std::stringstream ss;
ss << "$X = (a b c)[-1]" << std::endl;
ss << "d -> $X {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_not_contains("executed", res);
}
}

View File

@ -54,9 +54,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_vars")
TEST_CASE_METHOD(LexerTest, "Lexer_arrays")
{
m_lexer.scan(" () ");
m_lexer.scan(" ()[] ");
test_next("OPAR");
test_next("CPAR");
test_next("OSQUARE");
test_next("CSQUARE");
test_end();
}

View File

@ -130,3 +130,60 @@ TEST_CASE_METHOD(ParserTest, "Parser_array")
")))",
ss.str());
}
TEST_CASE_METHOD(ParserTest, "Parser_array_index")
{
std::stringstream ss;
ss << "$BIM = hello.cpp" << std::endl;
ss << "$BAM = (world.hpp world.cpp)" << std::endl;
ss << " $BIM -> (hello.cpp world.cpp) {" << std::endl;
ss << " g++ $BIM[4] -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],ARRAY(IDENT[world.hpp],IDENT[world.cpp])),"
"RULE("
"TARGET("
"VAR[BIM]"
"),DEPS("
"ARRAY(IDENT[hello.cpp],IDENT[world.cpp])"
"),BLOCK("
"CMD("
"IDENT[g++],INDEX(VAR[BIM],IDENT[4]),IDENT[-o],IDENT[hello.elf]"
"),CMD("
"IDENT[ls]"
")"
")))",
ss.str());
}
TEST_CASE_METHOD(ParserTest, "Parser_array_index_literal")
{
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[4] -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[4]),IDENT[-o],IDENT[hello.elf]"
"),CMD("
"IDENT[ls]"
")"
")))",
ss.str());
}