array variables.

main
bog 2023-10-14 17:55:51 +02:00
parent 91a7f61c42
commit acabfb8889
12 changed files with 252 additions and 34 deletions

View File

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

View File

@ -132,16 +132,33 @@ namespace sn
}
}
std::string Interpreter::get_value(std::shared_ptr<Node> node)
std::vector<std::string>
Interpreter::get_value(std::shared_ptr<Node> node)
{
if (node->type() == NODE_IDENT)
{
return node->repr();
return { node->repr() };
}
else if (node->type() == NODE_VAR)
{
auto var = *m_sym.get(node->repr());
return var.value;
return var.values;
}
else if (node->type() == NODE_ARRAY)
{
std::vector<std::string> values;
for (size_t i=0; i<node->size(); i++)
{
auto vals = get_value(*node->get(i));
for (size_t j=0; j<vals.size(); j++)
{
values.push_back(vals[j]);
}
}
return values;
}
throw run_error {"cannot find value for '"
@ -181,30 +198,53 @@ namespace sn
case NODE_VAR_DECL: {
std::string name = (*node->get(0))->repr();
auto n = *node->get(1);
m_sym.declare(name, get_value(n));
auto val = *node->get(1);
m_sym.declare(name, get_value(val));
} break;
case NODE_RULE: {
auto all_targets = *node->get(0);
auto target_node = *node->get(0);
auto deps = *node->get(1);
auto block = *node->get(2);
for (size_t i=0; i<all_targets->size(); i++)
std::vector<std::string> target_values;
for (size_t i=0; i<target_node->size(); i++)
{
auto target = *all_targets->get(i);
auto t = *target_node->get(i);
auto values = get_value(t);
for (size_t j=0; j<deps->size(); j++)
std::transform(std::begin(values),
std::end(values),
std::back_inserter(target_values),
std::bind(&Interpreter::format_path, this,
std::placeholders::_1));
}
std::vector<std::string> dep_values;
for (size_t i=0; i<deps->size(); i++)
{
auto d = *deps->get(i);
auto values = get_value(d);
std::transform(std::begin(values), std::end(values),
std::back_inserter(dep_values),
std::bind(&Interpreter::format_path, this,
std::placeholders::_1));
}
for (auto target: target_values)
{
for (auto dep: dep_values)
{
auto dep = *deps->get(j);
auto path = format_path(get_value(dep));
m_dependencies[format_path(get_value(target))].push_back(path);
auto target_path = format_path(get_value(target));
m_scripts[target_path] = scripts(block);
m_dependencies[target].push_back(dep);
}
m_scripts[target] = scripts(block);
}
} break;
@ -240,7 +280,17 @@ namespace sn
else
{
auto var = *m_sym.get(c->repr());
script += sep + var.value;
std::string vsep;
if (j > 0)
{
vsep = " ";
}
for (auto const& v: var.values)
{
script += vsep + v;
vsep = " ";
}
}
sep = " ";

View File

@ -40,7 +40,7 @@ namespace sn
std::vector<std::string>> m_scripts;
SymTable m_sym;
std::string get_value(std::shared_ptr<Node> node);
std::vector<std::string> get_value(std::shared_ptr<Node> node);
std::vector<std::filesystem::path>
targets(std::filesystem::path path) const;

View File

@ -9,6 +9,8 @@ namespace sn
m_separators.push_back('\n');
m_separators.push_back(' ');
add_text("(", NODE_OPAR);
add_text(")", NODE_CPAR);
add_text("=", NODE_ASSIGN);
add_text("->", NODE_RARROW);
add_text("{", NODE_OBRACE);

View File

@ -6,8 +6,9 @@
#define NODE_TYPES(G) \
G(NODE_DOC), G(NODE_IDENT), G(NODE_RARROW), G(NODE_OBRACE), \
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_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)
namespace sn
{

View File

@ -186,6 +186,11 @@ namespace sn
return *consume();
}
if (type_is(NODE_OPAR))
{
return parse_array();
}
throw syntax_error {"unknown token '"
+ SN_GET(NodeTypeStr,
m_tokens[m_cursor]->type(),
@ -198,7 +203,31 @@ namespace sn
auto node = std::make_shared<Node>(NODE_VAR_DECL);
node->add_child(*consume(NODE_VAR));
consume(NODE_ASSIGN);
node->add_child(*consume(NODE_IDENT));
if (type_is(NODE_OPAR))
{
node->add_child(parse_array());
}
else
{
node->add_child(*consume(NODE_IDENT));
}
return node;
}
std::shared_ptr<Node> Parser::parse_array()
{
auto node = std::make_shared<Node>(NODE_ARRAY);
consume(NODE_OPAR);
while (!type_is(NODE_CPAR))
{
node->add_child(parse_literal());
}
consume(NODE_CPAR);
return node;
}

View File

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

View File

@ -10,9 +10,10 @@ namespace sn
{
}
void SymTable::declare(std::string const& name, std::string const& value)
void SymTable::declare(std::string const& name,
std::vector<std::string> const& values)
{
m_vars[name] = Var { value };
m_vars[name] = Var { values };
}
std::optional<Var> SymTable::get(std::string const& name) const

View File

@ -10,7 +10,7 @@ namespace sn
* A variable of the snakefile.
**/
struct Var {
std::string value;
std::vector<std::string> values;
};
/**
@ -23,7 +23,9 @@ namespace sn
explicit SymTable();
virtual ~SymTable();
void declare(std::string const& name, std::string const& value);
void declare(std::string const& name,
std::vector<std::string> const& values);
std::optional<Var> get(std::string const& name) const;
private:

View File

@ -9,7 +9,7 @@ using namespace sn;
struct StateMock: public State {
std::vector<std::filesystem::path> modified_files;
StateMock(std::vector<std::filesystem::path> const& p_modified_files)
explicit StateMock(std::vector<std::filesystem::path> const& p_modified_files)
: modified_files { p_modified_files }
{
}
@ -32,7 +32,7 @@ struct StateMock: public State {
struct LoaderMock: public Loader {
std::string snakefile;
LoaderMock(std::string const& p_snakefile)
explicit LoaderMock(std::string const& p_snakefile)
: snakefile { p_snakefile }
{
}
@ -88,10 +88,6 @@ protected:
TEST_CASE_METHOD(InterpreterTest, "Interpreter_simple_var")
{
auto modified = std::vector<std::filesystem::path> {
std::filesystem::path("a"),
};
std::stringstream ss;
ss << "$X = a" << std::endl;
ss << "b -> $X {" << std::endl;
@ -101,3 +97,73 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_simple_var")
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_contains("executed", res);
}
TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_var")
{
SECTION("value")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "res -> a {" << std::endl;
ss << "$X" << std::endl;
ss << "}" << std::endl;
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_contains("a b c", res);
}
SECTION("as dep")
{
std::stringstream ss;
ss << "$X = (a b c)" << std::endl;
ss << "z -> $X {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
SECTION("a")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_contains("executed", res);
}
SECTION("b")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_contains("executed", res);
}
SECTION("c")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("c"));
test_contains("executed", res);
}
}
SECTION("direct use of array")
{
std::stringstream ss;
ss << "z -> (a b c) {" << std::endl;
ss << "executed" << std::endl;
ss << "}" << std::endl;
SECTION("a")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
test_contains("executed", res);
}
SECTION("b")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("b"));
test_contains("executed", res);
}
SECTION("c")
{
auto res = TEST_RUN(ss.str(), std::filesystem::path("c"));
test_contains("executed", res);
}
}
}

View File

@ -51,3 +51,12 @@ TEST_CASE_METHOD(LexerTest, "Lexer_vars")
test_next("ASSIGN");
test_end();
}
TEST_CASE_METHOD(LexerTest, "Lexer_arrays")
{
m_lexer.scan(" () ");
test_next("OPAR");
test_next("CPAR");
test_end();
}

View File

@ -74,3 +74,59 @@ TEST_CASE_METHOD(ParserTest, "Parser_var_decl_and_use")
")))",
ss.str());
}
TEST_CASE_METHOD(ParserTest, "Parser_var_array")
{
std::stringstream ss;
ss << "$BIM = hello.cpp" << std::endl;
ss << "$BAM = (world.hpp world.cpp)" << std::endl;
ss << " $BIM -> hello.cpp {" << std::endl;
ss << " g++ $BIM -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("
"IDENT[hello.cpp]"
"),BLOCK("
"CMD("
"IDENT[g++],VAR[BIM],IDENT[-o],IDENT[hello.elf]"
"),CMD("
"IDENT[ls]"
")"
")))",
ss.str());
}
TEST_CASE_METHOD(ParserTest, "Parser_array")
{
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 -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++],VAR[BIM],IDENT[-o],IDENT[hello.elf]"
"),CMD("
"IDENT[ls]"
")"
")))",
ss.str());
}