✨ simple variable declaration.
parent
e862da9000
commit
c450c89add
|
@ -1,7 +1,10 @@
|
|||
DOC ::= RULE*
|
||||
DOC ::= (VAR_DECL | RULE)*
|
||||
RULE ::= TARGET rarrow DEPS BLOCK
|
||||
TARGET ::= ident+
|
||||
DEPS ::= ident*
|
||||
TARGET ::= LITERAL+
|
||||
DEPS ::= LITERAL*
|
||||
BLOCK ::= obrace CMD_LST cbrace
|
||||
CMD_LST ::= (CMD (comma CMD)* comma?)?
|
||||
CMD ::= ident*
|
||||
CMD ::= LITERAL*
|
||||
LITERAL ::= ident | var
|
||||
|
||||
VAR_DECL ::= var assign ident
|
||||
|
|
|
@ -22,6 +22,7 @@ snake_lib = static_library('snake',
|
|||
'src/Interpreter.cpp',
|
||||
'src/State.cpp',
|
||||
'src/DAG.cpp',
|
||||
'src/SymTable.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
dependency('sqlite3')
|
||||
|
|
|
@ -161,6 +161,23 @@ namespace sn
|
|||
return node;
|
||||
}
|
||||
|
||||
std::string Interpreter::get_value(std::shared_ptr<Node> node)
|
||||
{
|
||||
if (node->type() == NODE_IDENT)
|
||||
{
|
||||
return node->repr();
|
||||
}
|
||||
else if (node->type() == NODE_VAR)
|
||||
{
|
||||
auto var = *m_sym.get(node->repr());
|
||||
return var.value;
|
||||
}
|
||||
|
||||
throw run_error {"cannot find value for '"
|
||||
+ SN_GET(NodeTypeStr, node->type(), "NODE_")
|
||||
+ "'"};
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path>
|
||||
Interpreter::targets(std::filesystem::path path) const
|
||||
{
|
||||
|
@ -191,6 +208,12 @@ namespace sn
|
|||
}
|
||||
} break;
|
||||
|
||||
case NODE_VAR_DECL: {
|
||||
std::string name = (*node->get(0))->repr();
|
||||
auto n = *node->get(1);
|
||||
m_sym.declare(name, get_value(n));
|
||||
} break;
|
||||
|
||||
case NODE_RULE: {
|
||||
auto all_targets = *node->get(0);
|
||||
auto deps = *node->get(1);
|
||||
|
@ -203,11 +226,11 @@ namespace sn
|
|||
for (size_t j=0; j<deps->size(); j++)
|
||||
{
|
||||
auto dep = *deps->get(j);
|
||||
auto path = format_path(dep->repr());
|
||||
auto path = format_path(get_value(dep));
|
||||
|
||||
m_dependencies[format_path(target->repr())].push_back(path);
|
||||
m_dependencies[format_path(get_value(target))].push_back(path);
|
||||
|
||||
auto target_path = format_path(target->repr());
|
||||
auto target_path = format_path(get_value(target));
|
||||
|
||||
m_scripts[target_path] = scripts(block);
|
||||
}
|
||||
|
@ -237,7 +260,18 @@ namespace sn
|
|||
|
||||
for (size_t j=0; j<cmd->size(); j++)
|
||||
{
|
||||
script += sep + (*cmd->get(j))->repr();
|
||||
auto c = *cmd->get(j);
|
||||
|
||||
if (c->type() == NODE_IDENT)
|
||||
{
|
||||
script += sep + c->repr();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto var = *m_sym.get(c->repr());
|
||||
script += sep + var.value;
|
||||
}
|
||||
|
||||
sep = " ";
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "Node.hpp"
|
||||
#include "State.hpp"
|
||||
#include "DAG.hpp"
|
||||
#include "SymTable.hpp"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
|
@ -33,6 +34,9 @@ namespace sn
|
|||
|
||||
std::unordered_map<std::filesystem::path,
|
||||
std::vector<std::string>> m_scripts;
|
||||
SymTable m_sym;
|
||||
|
||||
std::string get_value(std::shared_ptr<Node> node);
|
||||
|
||||
std::vector<std::filesystem::path>
|
||||
targets(std::filesystem::path path) const;
|
||||
|
@ -45,7 +49,6 @@ namespace sn
|
|||
|
||||
std::filesystem::path
|
||||
format_path(std::filesystem::path path) const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -9,11 +9,13 @@ namespace sn
|
|||
m_separators.push_back('\n');
|
||||
m_separators.push_back(' ');
|
||||
|
||||
add_text("=", NODE_ASSIGN);
|
||||
add_text("->", NODE_RARROW);
|
||||
add_text("{", NODE_OBRACE);
|
||||
add_text("}", NODE_CBRACE);
|
||||
add_text(",", NODE_COMMA);
|
||||
|
||||
m_scanners.push_back(std::bind(&Lexer::scan_var, this));
|
||||
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||
}
|
||||
|
||||
|
@ -151,4 +153,39 @@ namespace sn
|
|||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<ScanInfo> Lexer::scan_var()
|
||||
{
|
||||
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_VAR,
|
||||
repr.substr(1)
|
||||
};
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace sn
|
|||
bool has_repr=false);
|
||||
|
||||
std::optional<ScanInfo> scan_ident();
|
||||
std::optional<ScanInfo> scan_var();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#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_BLOCK), G(NODE_TARGET), G(NODE_DEPS), G(NODE_RULE), \
|
||||
G(NODE_VAR), G(NODE_ASSIGN), G(NODE_VAR_DECL)
|
||||
|
||||
namespace sn
|
||||
{
|
||||
|
|
|
@ -65,10 +65,19 @@ namespace sn
|
|||
auto node = std::make_shared<Node>(NODE_DOC);
|
||||
|
||||
while (m_cursor < m_tokens.size())
|
||||
{
|
||||
if (type_is(NODE_VAR)
|
||||
&& type_is(NODE_ASSIGN, 1))
|
||||
{
|
||||
node->add_child(parse_var_decl());
|
||||
}
|
||||
else
|
||||
{
|
||||
node->add_child(parse_rule());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -91,11 +100,11 @@ namespace sn
|
|||
{
|
||||
auto node = std::make_shared<Node>(NODE_TARGET);
|
||||
|
||||
node->add_child(*consume(NODE_IDENT));
|
||||
node->add_child(parse_literal());
|
||||
|
||||
while (!type_is(NODE_RARROW))
|
||||
{
|
||||
node->add_child(*consume(NODE_IDENT));
|
||||
node->add_child(parse_literal());
|
||||
}
|
||||
|
||||
consume();
|
||||
|
@ -109,7 +118,7 @@ namespace sn
|
|||
|
||||
while (!type_is(NODE_OBRACE))
|
||||
{
|
||||
node->add_child(*consume(NODE_IDENT));
|
||||
node->add_child(parse_literal());
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -163,9 +172,34 @@ namespace sn
|
|||
|
||||
while (!type_is(NODE_CBRACE) && !type_is(NODE_COMMA))
|
||||
{
|
||||
node->add_child(*consume(NODE_IDENT));
|
||||
node->add_child(parse_literal());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_literal()
|
||||
{
|
||||
if (type_is(NODE_IDENT)
|
||||
|| type_is(NODE_VAR))
|
||||
{
|
||||
return *consume();
|
||||
}
|
||||
|
||||
throw syntax_error {"unknown token '"
|
||||
+ SN_GET(NodeTypeStr,
|
||||
m_tokens[m_cursor]->type(),
|
||||
"NODE_")
|
||||
+ "'"};
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_var_decl()
|
||||
{
|
||||
auto node = std::make_shared<Node>(NODE_VAR_DECL);
|
||||
node->add_child(*consume(NODE_VAR));
|
||||
consume(NODE_ASSIGN);
|
||||
node->add_child(*consume(NODE_IDENT));
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ namespace sn
|
|||
std::shared_ptr<Node> parse_block();
|
||||
std::shared_ptr<Node> parse_cmd_lst();
|
||||
std::shared_ptr<Node> parse_cmd();
|
||||
|
||||
std::shared_ptr<Node> parse_literal();
|
||||
std::shared_ptr<Node> parse_var_decl();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include "SymTable.hpp"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
/*explicit*/ SymTable::SymTable()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ SymTable::~SymTable()
|
||||
{
|
||||
}
|
||||
|
||||
void SymTable::declare(std::string const& name, std::string const& value)
|
||||
{
|
||||
m_vars[name] = Var { value };
|
||||
}
|
||||
|
||||
std::optional<Var> SymTable::get(std::string const& name) const
|
||||
{
|
||||
if (auto var=m_vars.find(name);
|
||||
var != std::end(m_vars))
|
||||
{
|
||||
return var->second;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef sn_SYMTABLE_HPP
|
||||
#define sn_SYMTABLE_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
/**
|
||||
* A variable of the snakefile.
|
||||
**/
|
||||
struct Var {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
/**
|
||||
* A repository to declare and get variables.
|
||||
* @see Var
|
||||
**/
|
||||
class SymTable
|
||||
{
|
||||
public:
|
||||
explicit SymTable();
|
||||
virtual ~SymTable();
|
||||
|
||||
void declare(std::string const& name, std::string const& value);
|
||||
std::optional<Var> get(std::string const& name) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Var> m_vars;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -41,3 +41,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_rule")
|
|||
test_next("CBRACE");
|
||||
test_end();
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_vars")
|
||||
{
|
||||
m_lexer.scan("$hello $WORLD = ");
|
||||
|
||||
test_next("VAR[hello]");
|
||||
test_next("VAR[WORLD]");
|
||||
test_next("ASSIGN");
|
||||
test_end();
|
||||
}
|
||||
|
|
|
@ -46,3 +46,31 @@ TEST_CASE_METHOD(ParserTest, "Parser_rule")
|
|||
")))",
|
||||
ss.str());
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_var_decl_and_use")
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "$BIM = hello.cpp" << std::endl;
|
||||
ss << "$BAM = world.hpp" << 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],IDENT[world.hpp]),"
|
||||
"RULE("
|
||||
"TARGET("
|
||||
"VAR[BIM]"
|
||||
"),DEPS("
|
||||
"IDENT[hello.cpp]"
|
||||
"),BLOCK("
|
||||
"CMD("
|
||||
"IDENT[g++],VAR[BIM],IDENT[-o],IDENT[hello.elf]"
|
||||
"),CMD("
|
||||
"IDENT[ls]"
|
||||
")"
|
||||
")))",
|
||||
ss.str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue