🚧 define notion of variable in snakefile.
parent
1ef177bfc8
commit
21cb7db86f
|
@ -5,7 +5,13 @@ DEPS ::= LITERAL*
|
||||||
BLOCK ::= obrace CMD_LST cbrace
|
BLOCK ::= obrace CMD_LST cbrace
|
||||||
CMD_LST ::= (CMD (comma CMD)* comma?)?
|
CMD_LST ::= (CMD (comma CMD)* comma?)?
|
||||||
CMD ::= LITERAL*
|
CMD ::= LITERAL*
|
||||||
LITERAL ::= ident | var | ARRAY | INDEX
|
LITERAL ::=
|
||||||
|
| ident
|
||||||
|
| var
|
||||||
|
| generic
|
||||||
|
| ARRAY
|
||||||
|
| INDEX
|
||||||
|
|
||||||
|
|
||||||
VAR_DECL ::= var assign (LITERAL | ARRAY | INDEX)
|
VAR_DECL ::= var assign (LITERAL | ARRAY | INDEX)
|
||||||
ARRAY ::= opar LITERAL* cpar
|
ARRAY ::= opar LITERAL* cpar
|
||||||
|
|
|
@ -129,6 +129,11 @@ namespace sn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO TRY GENERICS
|
||||||
|
std::cout << "-> " << file << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
m_state->update(file);
|
m_state->update(file);
|
||||||
}
|
}
|
||||||
|
@ -407,12 +412,20 @@ namespace sn
|
||||||
auto deps = *node->get(1);
|
auto deps = *node->get(1);
|
||||||
auto block = *node->get(2);
|
auto block = *node->get(2);
|
||||||
|
|
||||||
|
if (!target_node->collect(NODE_GENERIC).empty()
|
||||||
|
|| !deps->collect(NODE_GENERIC).empty())
|
||||||
|
// Generic rule here
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> target_values;
|
std::vector<std::string> target_values;
|
||||||
std::vector<std::string> target_values_verbatim;
|
std::vector<std::string> target_values_verbatim;
|
||||||
|
|
||||||
for (size_t i=0; i<target_node->size(); i++)
|
for (size_t i=0; i<target_node->size(); i++)
|
||||||
{
|
{
|
||||||
auto t = *target_node->get(i);
|
auto t = *target_node->get(i);
|
||||||
|
|
||||||
auto values = get_value(t);
|
auto values = get_value(t);
|
||||||
|
|
||||||
std::copy(std::begin(values), std::end(values),
|
std::copy(std::begin(values), std::end(values),
|
||||||
|
|
|
@ -14,6 +14,25 @@ namespace sn
|
||||||
{
|
{
|
||||||
SN_ERROR(run_error);
|
SN_ERROR(run_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a snakefile value.
|
||||||
|
* (e.g a file, an array of files ...)
|
||||||
|
**/
|
||||||
|
struct Value {
|
||||||
|
Value(std::filesystem::path p_file)
|
||||||
|
: file { p_file }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Value(std::vector<std::filesystem::path> p_array)
|
||||||
|
: array { p_array }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::filesystem::path> file;
|
||||||
|
std::optional<std::vector<std::filesystem::path>> array;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process a snakefile AST and run build commands.
|
* Process a snakefile AST and run build commands.
|
||||||
* @see Node
|
* @see Node
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace sn
|
||||||
add_text("}", NODE_CBRACE);
|
add_text("}", NODE_CBRACE);
|
||||||
add_text(",", NODE_COMMA);
|
add_text(",", NODE_COMMA);
|
||||||
|
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_generic, this));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_var, this));
|
m_scanners.push_back(std::bind(&Lexer::scan_var, this));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||||
}
|
}
|
||||||
|
@ -193,4 +194,39 @@ namespace sn
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> Lexer::scan_generic()
|
||||||
|
{
|
||||||
|
size_t cursor = m_cursor;
|
||||||
|
std::string repr;
|
||||||
|
|
||||||
|
if (cursor < m_source.size()
|
||||||
|
&& m_source[cursor] == '^')
|
||||||
|
{
|
||||||
|
repr += '^';
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cursor < m_source.size()
|
||||||
|
&& !is_separator(m_source[cursor]))
|
||||||
|
{
|
||||||
|
repr += m_source[cursor];
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repr.empty() == false)
|
||||||
|
{
|
||||||
|
return ScanInfo {
|
||||||
|
cursor,
|
||||||
|
NODE_GENERIC,
|
||||||
|
repr.substr(1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace sn
|
||||||
|
|
||||||
std::optional<ScanInfo> scan_ident();
|
std::optional<ScanInfo> scan_ident();
|
||||||
std::optional<ScanInfo> scan_var();
|
std::optional<ScanInfo> scan_var();
|
||||||
|
std::optional<ScanInfo> scan_generic();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/Node.cpp
20
src/Node.cpp
|
@ -53,4 +53,24 @@ namespace sn
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Node>> Node::collect(NodeType type)
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<Node>> results;
|
||||||
|
|
||||||
|
if (m_type == type)
|
||||||
|
{
|
||||||
|
return {shared_from_this()};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto child: m_children)
|
||||||
|
{
|
||||||
|
auto collected = child->collect(type);
|
||||||
|
|
||||||
|
std::copy(std::begin(collected), std::end(collected),
|
||||||
|
std::back_inserter(results));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define sn_NODE_HPP
|
#define sn_NODE_HPP
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define NODE_TYPES(G) \
|
#define NODE_TYPES(G) \
|
||||||
G(NODE_DOC), G(NODE_IDENT), G(NODE_RARROW), G(NODE_OBRACE), \
|
G(NODE_DOC), G(NODE_IDENT), G(NODE_RARROW), G(NODE_OBRACE), \
|
||||||
|
@ -9,7 +10,7 @@
|
||||||
G(NODE_BLOCK), G(NODE_TARGET), G(NODE_DEPS), G(NODE_RULE), \
|
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_VAR), G(NODE_ASSIGN), G(NODE_VAR_DECL), G(NODE_OPAR), \
|
||||||
G(NODE_CPAR), G(NODE_ARRAY), G(NODE_INDEX), G(NODE_OSQUARE), \
|
G(NODE_CPAR), G(NODE_ARRAY), G(NODE_INDEX), G(NODE_OSQUARE), \
|
||||||
G(NODE_CSQUARE)
|
G(NODE_CSQUARE), G(NODE_GENERIC)
|
||||||
|
|
||||||
namespace sn
|
namespace sn
|
||||||
{
|
{
|
||||||
|
@ -18,7 +19,7 @@ namespace sn
|
||||||
/**
|
/**
|
||||||
* A node is an element of the snake AST.
|
* A node is an element of the snake AST.
|
||||||
**/
|
**/
|
||||||
class Node
|
class Node: public std::enable_shared_from_this<Node>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Node(NodeType type, std::string const& repr="");
|
explicit Node(NodeType type, std::string const& repr="");
|
||||||
|
@ -33,6 +34,7 @@ namespace sn
|
||||||
std::optional<std::shared_ptr<Node>> get(size_t index);
|
std::optional<std::shared_ptr<Node>> get(size_t index);
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
std::vector<std::shared_ptr<Node>> collect(NodeType type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NodeType m_type;
|
NodeType m_type;
|
||||||
|
|
|
@ -187,7 +187,8 @@ namespace sn
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_is(NODE_IDENT)
|
if (type_is(NODE_IDENT)
|
||||||
|| type_is(NODE_VAR))
|
|| type_is(NODE_VAR)
|
||||||
|
|| type_is(NODE_GENERIC))
|
||||||
{
|
{
|
||||||
return *consume();
|
return *consume();
|
||||||
}
|
}
|
||||||
|
|
|
@ -452,3 +452,39 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_constructor")
|
||||||
test_contains(result, res);
|
test_contains(result, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(InterpreterTest, "Interpreter_generics", "[.]")
|
||||||
|
{
|
||||||
|
SECTION("no rule to apply")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "^.o -> ^.cpp {" << std::endl;
|
||||||
|
ss << "$IN $OUT" << std::endl;
|
||||||
|
ss << "}" << std::endl;
|
||||||
|
|
||||||
|
auto res = TEST_RUN(ss.str(), std::filesystem::path("a"));
|
||||||
|
REQUIRE(res.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("call left")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "^.o -> ^.cpp ^.el {" << std::endl;
|
||||||
|
ss << "$IN $OUT" << std::endl;
|
||||||
|
ss << "}" << std::endl;
|
||||||
|
|
||||||
|
auto res = TEST_RUN(ss.str(), std::filesystem::path("a.cpp"));
|
||||||
|
test_contains("a.o a.cpp", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("call right")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "^.o -> ^.cpp ^.el {" << std::endl;
|
||||||
|
ss << "$IN $OUT" << std::endl;
|
||||||
|
ss << "}" << std::endl;
|
||||||
|
|
||||||
|
auto res = TEST_RUN(ss.str(), std::filesystem::path("a.el"));
|
||||||
|
test_contains("a.o a.el", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -62,3 +62,14 @@ TEST_CASE_METHOD(LexerTest, "Lexer_arrays")
|
||||||
test_next("CSQUARE");
|
test_next("CSQUARE");
|
||||||
test_end();
|
test_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_generic")
|
||||||
|
{
|
||||||
|
m_lexer.scan(" ^.o ^.cpp ^.tar.gz ");
|
||||||
|
|
||||||
|
test_next("GENERIC[.o]");
|
||||||
|
test_next("GENERIC[.cpp]");
|
||||||
|
test_next("GENERIC[.tar.gz]");
|
||||||
|
|
||||||
|
test_end();
|
||||||
|
}
|
||||||
|
|
|
@ -216,3 +216,20 @@ TEST_CASE_METHOD(ParserTest, "Parser_replace_ext_index")
|
||||||
")))",
|
")))",
|
||||||
ss.str());
|
ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_generic")
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << " ^.o -> ^.c {" << std::endl;
|
||||||
|
ss << " g++ $IN -o $OUT " << std::endl;
|
||||||
|
ss << " }" << std::endl;
|
||||||
|
|
||||||
|
test_parse("DOC("
|
||||||
|
"RULE("
|
||||||
|
"TARGET(GENERIC[.o])"
|
||||||
|
",DEPS(GENERIC[.c])"
|
||||||
|
",BLOCK("
|
||||||
|
"CMD(IDENT[g++],VAR[IN],IDENT[-o],VAR[OUT])"
|
||||||
|
")))",
|
||||||
|
ss.str());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue