✨ array variables.
parent
91a7f61c42
commit
acabfb8889
|
@ -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
|
||||
|
|
|
@ -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 = " ";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue