🚧 define notion of variable in snakefile.

main
bog 2023-10-15 15:18:28 +02:00
parent 1ef177bfc8
commit 21cb7db86f
11 changed files with 166 additions and 4 deletions

View File

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

View File

@ -129,6 +129,11 @@ namespace sn
}
}
}
else
{
// TODO TRY GENERICS
std::cout << "-> " << file << std::endl;
}
m_state->update(file);
}
@ -407,12 +412,20 @@ namespace sn
auto deps = *node->get(1);
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_verbatim;
for (size_t i=0; i<target_node->size(); i++)
{
auto t = *target_node->get(i);
auto values = get_value(t);
std::copy(std::begin(values), std::end(values),

View File

@ -14,6 +14,25 @@ namespace sn
{
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.
* @see Node

View File

@ -20,6 +20,7 @@ namespace sn
add_text("}", NODE_CBRACE);
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_ident, this));
}
@ -193,4 +194,39 @@ namespace sn
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;
}
}

View File

@ -57,6 +57,7 @@ namespace sn
std::optional<ScanInfo> scan_ident();
std::optional<ScanInfo> scan_var();
std::optional<ScanInfo> scan_generic();
};
}

View File

@ -53,4 +53,24 @@ namespace sn
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;
}
}

View File

@ -2,6 +2,7 @@
#define sn_NODE_HPP
#include "commons.hpp"
#include <memory>
#define NODE_TYPES(G) \
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_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_CSQUARE)
G(NODE_CSQUARE), G(NODE_GENERIC)
namespace sn
{
@ -18,7 +19,7 @@ namespace sn
/**
* A node is an element of the snake AST.
**/
class Node
class Node: public std::enable_shared_from_this<Node>
{
public:
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::string string() const;
std::vector<std::shared_ptr<Node>> collect(NodeType type);
private:
NodeType m_type;

View File

@ -187,7 +187,8 @@ namespace sn
}
if (type_is(NODE_IDENT)
|| type_is(NODE_VAR))
|| type_is(NODE_VAR)
|| type_is(NODE_GENERIC))
{
return *consume();
}

View File

@ -452,3 +452,39 @@ TEST_CASE_METHOD(InterpreterTest, "Interpreter_array_constructor")
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);
}
}

View File

@ -62,3 +62,14 @@ TEST_CASE_METHOD(LexerTest, "Lexer_arrays")
test_next("CSQUARE");
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();
}

View File

@ -216,3 +216,20 @@ TEST_CASE_METHOD(ParserTest, "Parser_replace_ext_index")
")))",
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());
}