ADD: variable declaration.
parent
583c1351ba
commit
e5c388a38e
|
@ -1,2 +1,6 @@
|
||||||
MODULE ::= EXPR*
|
MODULE ::= EXPR*
|
||||||
EXPR ::= bool
|
EXPR ::=
|
||||||
|
bool
|
||||||
|
| ident
|
||||||
|
| VARDECL
|
||||||
|
VARDECL ::= opar decl ident EXPR cpar
|
||||||
|
|
|
@ -24,6 +24,7 @@ grino_src = static_library('grino',
|
||||||
'src/Program.cpp',
|
'src/Program.cpp',
|
||||||
'src/VM.cpp',
|
'src/VM.cpp',
|
||||||
'src/Value.cpp',
|
'src/Value.cpp',
|
||||||
|
'src/SymTable.cpp',
|
||||||
])
|
])
|
||||||
|
|
||||||
grino_dep = declare_dependency(link_with: grino_src)
|
grino_dep = declare_dependency(link_with: grino_src)
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
#include "src/opcodes.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
/*explicit*/ Compiler::Compiler(Logger& logger)
|
/*explicit*/ Compiler::Compiler(Logger& logger, SymTable& sym)
|
||||||
: m_logger { logger }
|
: m_logger { logger }
|
||||||
|
, m_sym { sym }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +24,7 @@ namespace grino
|
||||||
for (size_t i=0; i<node->size(); i++)
|
for (size_t i=0; i<node->size(); i++)
|
||||||
{
|
{
|
||||||
compile(node->child(i).lock(), program);
|
compile(node->child(i).lock(), program);
|
||||||
|
program.push_instr(OPCODE_POP);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -32,6 +36,31 @@ namespace grino
|
||||||
program.push_constant(value));
|
program.push_constant(value));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_VARDECL: {
|
||||||
|
std::string ident = node->child(0).lock()->repr();
|
||||||
|
auto expr = node->child(1).lock();
|
||||||
|
size_t address = get_local_address();
|
||||||
|
|
||||||
|
compile(expr, program);
|
||||||
|
|
||||||
|
m_sym.declare(node->loc(), ident, address);
|
||||||
|
program.push_instr(OPCODE_STORE_LOCAL, address);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_IDENT: {
|
||||||
|
std::string ident = node->repr();
|
||||||
|
auto entry = m_sym.find(ident);
|
||||||
|
|
||||||
|
if (entry == std::nullopt)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "undefined variable '" << ident << "'";
|
||||||
|
m_logger.log<compile_error>(LOG_ERROR, node->loc(), ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
program.push_instr(OPCODE_LOAD_LOCAL, entry->addr);
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "cannot compile node '"
|
std::cerr << "cannot compile node '"
|
||||||
<< GRINO_TRIM(NodeTypeStr[node->type()], "NODE_")
|
<< GRINO_TRIM(NodeTypeStr[node->type()], "NODE_")
|
||||||
|
@ -39,4 +68,11 @@ namespace grino
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Compiler::get_local_address()
|
||||||
|
{
|
||||||
|
static size_t addr = 0;
|
||||||
|
addr++;
|
||||||
|
return addr - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,19 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
|
#include "src/mutils.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
class Program;
|
class Program;
|
||||||
|
class SymTable;
|
||||||
|
|
||||||
|
GRINO_ERROR(compile_error);
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Compiler(Logger& logger);
|
explicit Compiler(Logger& logger, SymTable& sym);
|
||||||
virtual ~Compiler();
|
virtual ~Compiler();
|
||||||
|
|
||||||
void compile(std::shared_ptr<Node> node,
|
void compile(std::shared_ptr<Node> node,
|
||||||
|
@ -20,6 +24,9 @@ namespace grino
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
|
SymTable& m_sym;
|
||||||
|
|
||||||
|
size_t get_local_address();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,14 @@ namespace grino
|
||||||
: m_logger { logger }
|
: m_logger { logger }
|
||||||
, m_loc {source_path, 1}
|
, m_loc {source_path, 1}
|
||||||
{
|
{
|
||||||
|
add_text(NODE_OPAR, "(", false);
|
||||||
|
add_text(NODE_CPAR, ")", false);
|
||||||
|
add_text(NODE_DECL, "$", false);
|
||||||
|
|
||||||
add_keyword(NODE_BOOL, "true", true);
|
add_keyword(NODE_BOOL, "true", true);
|
||||||
add_keyword(NODE_BOOL, "false", true);
|
add_keyword(NODE_BOOL, "false", true);
|
||||||
|
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ Lexer::~Lexer()
|
/*virtual*/ Lexer::~Lexer()
|
||||||
|
@ -125,6 +131,7 @@ namespace grino
|
||||||
text, has_value));
|
text, has_value));
|
||||||
if (text.size() == 1)
|
if (text.size() == 1)
|
||||||
{
|
{
|
||||||
|
m_separators.push_back(text[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +148,7 @@ namespace grino
|
||||||
std::string const& text,
|
std::string const& text,
|
||||||
bool has_value)
|
bool has_value)
|
||||||
{
|
{
|
||||||
if (!has_more(m_cursor + text.size()))
|
if (m_cursor + text.size() > m_source.size())
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -191,4 +198,28 @@ namespace grino
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> Lexer::scan_ident()
|
||||||
|
{
|
||||||
|
size_t cursor = m_cursor;
|
||||||
|
|
||||||
|
std::string repr;
|
||||||
|
|
||||||
|
while (has_more(cursor)
|
||||||
|
&& !is_sep(cursor))
|
||||||
|
{
|
||||||
|
repr += at(cursor);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repr.empty() == false)
|
||||||
|
{
|
||||||
|
return ScanInfo {
|
||||||
|
cursor,
|
||||||
|
NODE_IDENT,
|
||||||
|
repr
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ namespace grino
|
||||||
std::string const& text,
|
std::string const& text,
|
||||||
bool has_value);
|
bool has_value);
|
||||||
|
|
||||||
|
std::optional<ScanInfo> scan_ident();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/Node.hpp
11
src/Node.hpp
|
@ -4,9 +4,14 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "Loc.hpp"
|
#include "Loc.hpp"
|
||||||
|
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_MODULE), \
|
G(NODE_MODULE), \
|
||||||
G(NODE_BOOL),
|
G(NODE_BOOL), \
|
||||||
|
G(NODE_VARDECL), \
|
||||||
|
G(NODE_IDENT), \
|
||||||
|
G(NODE_OPAR), \
|
||||||
|
G(NODE_CPAR), \
|
||||||
|
G(NODE_DECL),
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,9 +97,15 @@ namespace grino
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::make_node(NodeType type,
|
||||||
|
std::string const& repr)
|
||||||
|
{
|
||||||
|
return std::make_shared<Node>(type, repr, loc());
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_module()
|
std::shared_ptr<Node> Parser::parse_module()
|
||||||
{
|
{
|
||||||
auto node = std::make_shared<Node>(NODE_MODULE, "", loc());
|
auto node = make_node(NODE_MODULE);
|
||||||
|
|
||||||
while (m_cursor < m_tokens.size())
|
while (m_cursor < m_tokens.size())
|
||||||
{
|
{
|
||||||
|
@ -111,7 +117,13 @@ namespace grino
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_expr()
|
std::shared_ptr<Node> Parser::parse_expr()
|
||||||
{
|
{
|
||||||
if (type_is(NODE_BOOL))
|
if (type_is(NODE_OPAR))
|
||||||
|
{
|
||||||
|
return parse_vardecl();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_is(NODE_IDENT)
|
||||||
|
|| type_is(NODE_BOOL))
|
||||||
{
|
{
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
@ -126,4 +138,17 @@ namespace grino
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_vardecl()
|
||||||
|
{
|
||||||
|
auto node = make_node(NODE_VARDECL);
|
||||||
|
consume(NODE_OPAR);
|
||||||
|
consume(NODE_DECL);
|
||||||
|
|
||||||
|
node->add_child(consume(NODE_IDENT));
|
||||||
|
node->add_child(parse_expr());
|
||||||
|
|
||||||
|
consume(NODE_CPAR);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,12 @@ namespace grino
|
||||||
bool type_is(std::vector<NodeType> const& types) const;
|
bool type_is(std::vector<NodeType> const& types) const;
|
||||||
Loc loc() const;
|
Loc loc() const;
|
||||||
|
|
||||||
|
std::shared_ptr<Node> make_node(NodeType type,
|
||||||
|
std::string const& repr="");
|
||||||
|
|
||||||
std::shared_ptr<Node> parse_module();
|
std::shared_ptr<Node> parse_module();
|
||||||
std::shared_ptr<Node> parse_expr();
|
std::shared_ptr<Node> parse_expr();
|
||||||
|
std::shared_ptr<Node> parse_vardecl();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
#include "SymTable.hpp"
|
||||||
|
|
||||||
|
namespace grino
|
||||||
|
{
|
||||||
|
/*explicit*/ SymTable::SymTable(Logger& logger)
|
||||||
|
: m_logger { logger }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ SymTable::~SymTable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymTable::declare(Loc const& loc, std::string const& name, size_t addr)
|
||||||
|
{
|
||||||
|
if (find(name))
|
||||||
|
{
|
||||||
|
m_logger.log<symbolic_error>(LOG_ERROR, loc, "'"
|
||||||
|
+ name
|
||||||
|
+ "' already defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
SymEntry entry;
|
||||||
|
entry.addr = addr;
|
||||||
|
entry.name = name;
|
||||||
|
entry.is_global = false;
|
||||||
|
|
||||||
|
m_entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<SymEntry> SymTable::find(std::string const& name)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<m_entries.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_entries[i].name == name)
|
||||||
|
{
|
||||||
|
return m_entries[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SymTable::string() const
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
for (auto const& entry: m_entries)
|
||||||
|
{
|
||||||
|
ss << entry.addr << "\t" << entry.name << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef grino_SYMTABLE_HPP
|
||||||
|
#define grino_SYMTABLE_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
namespace grino
|
||||||
|
{
|
||||||
|
struct SymEntry {
|
||||||
|
std::string name;
|
||||||
|
bool is_global;
|
||||||
|
size_t addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
GRINO_ERROR(symbolic_error);
|
||||||
|
|
||||||
|
class SymTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SymTable(Logger& logger);
|
||||||
|
virtual ~SymTable();
|
||||||
|
|
||||||
|
void declare(Loc const& loc, std::string const& name, size_t addr);
|
||||||
|
std::optional<SymEntry> find(std::string const& name);
|
||||||
|
|
||||||
|
std::string string() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger& m_logger;
|
||||||
|
std::vector<SymEntry> m_entries;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
37
src/VM.cpp
37
src/VM.cpp
|
@ -6,6 +6,7 @@ namespace grino
|
||||||
/*explicit*/ VM::VM(Logger& logger)
|
/*explicit*/ VM::VM(Logger& logger)
|
||||||
: m_logger { logger }
|
: m_logger { logger }
|
||||||
{
|
{
|
||||||
|
m_frames.push_back(Frame {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ VM::~VM()
|
/*virtual*/ VM::~VM()
|
||||||
|
@ -29,6 +30,24 @@ namespace grino
|
||||||
m_pc++;
|
m_pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OPCODE_POP: {
|
||||||
|
pop();
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OPCODE_STORE_LOCAL: {
|
||||||
|
size_t addr = *instr.param;
|
||||||
|
auto value = program.constant(top());
|
||||||
|
set_local(addr, value);
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OPCODE_LOAD_LOCAL: {
|
||||||
|
size_t addr = *instr.param;
|
||||||
|
push(program.push_constant(local(addr)));
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "cannot execute unknown opcode "
|
std::cerr << "cannot execute unknown opcode "
|
||||||
<< OpcodeTypeStr[instr.opcode]
|
<< OpcodeTypeStr[instr.opcode]
|
||||||
|
@ -72,4 +91,22 @@ namespace grino
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t VM::top()
|
||||||
|
{
|
||||||
|
size_t addr = m_stack[m_sp - 1];
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Value> VM::local(size_t addr) const
|
||||||
|
{
|
||||||
|
return m_frames.back().locals.at(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM::set_local(size_t addr,
|
||||||
|
std::shared_ptr<Value> value)
|
||||||
|
{
|
||||||
|
m_frames.back().locals[addr] = value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ namespace grino
|
||||||
|
|
||||||
GRINO_ERROR(execution_error);
|
GRINO_ERROR(execution_error);
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
std::unordered_map<size_t, std::shared_ptr<Value>> locals;
|
||||||
|
};
|
||||||
|
|
||||||
class VM
|
class VM
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -23,6 +27,7 @@ namespace grino
|
||||||
private:
|
private:
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
std::array<size_t, STACK_SIZE> m_stack;
|
std::array<size_t, STACK_SIZE> m_stack;
|
||||||
|
std::vector<Frame> m_frames;
|
||||||
|
|
||||||
size_t m_sp; /* stack pointer */
|
size_t m_sp; /* stack pointer */
|
||||||
size_t m_bp; /* base pointer */
|
size_t m_bp; /* base pointer */
|
||||||
|
@ -30,6 +35,10 @@ namespace grino
|
||||||
|
|
||||||
void push(size_t addr);
|
void push(size_t addr);
|
||||||
size_t pop();
|
size_t pop();
|
||||||
|
size_t top();
|
||||||
|
std::shared_ptr<Value> local(size_t addr) const;
|
||||||
|
void set_local(size_t addr,
|
||||||
|
std::shared_ptr<Value> value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
|
#include "src/SymTable.hpp"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
@ -73,8 +74,9 @@ int main(int argc, char** argv)
|
||||||
std::cout << "--- ast ---" << std::endl;
|
std::cout << "--- ast ---" << std::endl;
|
||||||
std::cout << ast->string() << std::endl;
|
std::cout << ast->string() << std::endl;
|
||||||
}
|
}
|
||||||
|
grino::SymTable sym_table {logger};
|
||||||
|
|
||||||
grino::Compiler compiler {logger};
|
grino::Compiler compiler {logger, sym_table};
|
||||||
grino::Program program;
|
grino::Program program;
|
||||||
compiler.compile(ast, program);
|
compiler.compile(ast, program);
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "src/mutils.hpp"
|
#include "src/mutils.hpp"
|
||||||
|
|
||||||
#define OPCODES(G) \
|
#define OPCODES(G) \
|
||||||
G(OPCODE_LOAD_CONST)
|
G(OPCODE_LOAD_CONST), \
|
||||||
|
G(OPCODE_POP), \
|
||||||
|
G(OPCODE_LOAD_LOCAL), \
|
||||||
|
G(OPCODE_STORE_LOCAL)
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,13 +24,6 @@ protected:
|
||||||
grino::Logger m_logger;
|
grino::Logger m_logger;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_errors")
|
|
||||||
{
|
|
||||||
grino::Lexer lexer {m_logger, "tests/lexer"};
|
|
||||||
lexer.scan(" § ");
|
|
||||||
REQUIRE_THROWS_AS(lexer.next(), grino::lexical_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_booleans")
|
TEST_CASE_METHOD(LexerTest, "Lexer_booleans")
|
||||||
{
|
{
|
||||||
grino::Lexer lexer {m_logger, "tests/lexer"};
|
grino::Lexer lexer {m_logger, "tests/lexer"};
|
||||||
|
@ -62,3 +55,25 @@ TEST_CASE_METHOD(LexerTest, "Lexer_comments")
|
||||||
test_end(lexer);
|
test_end(lexer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_vardecl")
|
||||||
|
{
|
||||||
|
grino::Lexer lexer {m_logger, "tests/lexer"};
|
||||||
|
|
||||||
|
lexer.scan(" $ () coucou) ");
|
||||||
|
test_next(lexer, "DECL");
|
||||||
|
test_next(lexer, "OPAR");
|
||||||
|
test_next(lexer, "CPAR");
|
||||||
|
test_next(lexer, "IDENT[coucou]");
|
||||||
|
test_next(lexer, "CPAR");
|
||||||
|
test_end(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_no_end_space")
|
||||||
|
{
|
||||||
|
grino::Lexer lexer {m_logger, "tests/lexer"};
|
||||||
|
|
||||||
|
lexer.scan(")");
|
||||||
|
test_next(lexer, "CPAR");
|
||||||
|
test_end(lexer);
|
||||||
|
}
|
||||||
|
|
|
@ -10,14 +10,15 @@ public:
|
||||||
|
|
||||||
void test_parse(std::string const& oracle, std::string const& source)
|
void test_parse(std::string const& oracle, std::string const& source)
|
||||||
{
|
{
|
||||||
auto root = m_parser.parse(source);
|
grino::Logger logger;
|
||||||
|
grino::Lexer lexer {logger, "tests/parser"};
|
||||||
|
grino::Parser parser {logger, lexer};
|
||||||
|
|
||||||
|
auto root = parser.parse(source);
|
||||||
REQUIRE(oracle == root->string());
|
REQUIRE(oracle == root->string());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
grino::Logger m_logger;
|
|
||||||
grino::Lexer m_lexer {m_logger, "tests/parser"};
|
|
||||||
grino::Parser m_parser {m_logger, m_lexer};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_empty")
|
TEST_CASE_METHOD(ParserTest, "Parser_empty")
|
||||||
|
@ -29,3 +30,12 @@ TEST_CASE_METHOD(ParserTest, "Parser_booleans")
|
||||||
{
|
{
|
||||||
test_parse("MODULE(BOOL[true],BOOL[false])", "true false");
|
test_parse("MODULE(BOOL[true],BOOL[false])", "true false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_vardecl")
|
||||||
|
{
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[hello],BOOL[false]))",
|
||||||
|
"($ hello false)");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[hello],IDENT[world]))",
|
||||||
|
"($ hello world)");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue