ADD: if-then-else statement.
parent
b9072c580f
commit
d72660e6de
|
@ -6,10 +6,14 @@ INSTR ::= EXPR
|
||||||
| VARDECL
|
| VARDECL
|
||||||
| CONSTDECL
|
| CONSTDECL
|
||||||
| ASSIGN
|
| ASSIGN
|
||||||
|
| IF
|
||||||
|
|
||||||
VARDECL ::= let_mut ident assign EXPR
|
VARDECL ::= let_mut ident assign EXPR
|
||||||
CONSTDECL ::= let ident assign EXPR
|
CONSTDECL ::= let ident assign EXPR
|
||||||
ASSIGN ::= ident assign EXPR
|
ASSIGN ::= ident assign EXPR
|
||||||
|
IF ::= if EXPR THEN (else (IF | ELSE))?
|
||||||
|
THEN ::= INSTR*
|
||||||
|
ELSE ::= INSTR*
|
||||||
|
|
||||||
EXPR ::= IMP
|
EXPR ::= IMP
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,51 @@ namespace roza
|
||||||
{
|
{
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
|
|
||||||
|
case NODE_IF: {
|
||||||
|
m_sym.enter_scope();
|
||||||
|
|
||||||
|
std::vector<size_t> to_end;
|
||||||
|
|
||||||
|
std::function<void(std::shared_ptr<Node>)>
|
||||||
|
f = [&](std::shared_ptr<Node> n){
|
||||||
|
auto cond = n->child(0);
|
||||||
|
auto then = n->child(1);
|
||||||
|
|
||||||
|
compile_node(cond, prog);
|
||||||
|
size_t cond_addr = prog->size();
|
||||||
|
prog->push_instr(OP_BRF, 0);
|
||||||
|
|
||||||
|
compile_node(then, prog);
|
||||||
|
|
||||||
|
to_end.push_back(prog->size());
|
||||||
|
prog->push_instr(OP_BR, 0);
|
||||||
|
|
||||||
|
prog->set_param(cond_addr, prog->size());
|
||||||
|
|
||||||
|
if (n->size() > 2)
|
||||||
|
{
|
||||||
|
auto next = n->child(2);
|
||||||
|
compile_node(next, prog);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
f(root);
|
||||||
|
|
||||||
|
for (auto addr: to_end)
|
||||||
|
{
|
||||||
|
prog->set_param(addr, prog->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sym.leave_scope();
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_ELSE:
|
||||||
|
case NODE_THEN: {
|
||||||
|
compile_children(root, prog);
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_ASSERT: {
|
case NODE_ASSERT: {
|
||||||
compile_children(root, prog);
|
compile_children(root, prog);
|
||||||
prog->push_instr(OP_ASSERT);
|
prog->push_instr(OP_ASSERT);
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace roza
|
||||||
, m_loc { loc }
|
, m_loc { loc }
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
|
||||||
|
{";", NODE_EOI, false},
|
||||||
{"==", NODE_EQ, false},
|
{"==", NODE_EQ, false},
|
||||||
{"!=", NODE_NE, false},
|
{"!=", NODE_NE, false},
|
||||||
{"<=", NODE_LE, false},
|
{"<=", NODE_LE, false},
|
||||||
|
@ -27,6 +28,9 @@ namespace roza
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
|
||||||
|
{"if", NODE_IF, false},
|
||||||
|
{"else", NODE_ELSE, false},
|
||||||
|
{"end", NODE_END, false},
|
||||||
{"let!", NODE_LET_MUT, false},
|
{"let!", NODE_LET_MUT, false},
|
||||||
{"let", NODE_LET, false},
|
{"let", NODE_LET, false},
|
||||||
{"true", NODE_BOOL, true},
|
{"true", NODE_BOOL, true},
|
||||||
|
|
21
lib/Node.hpp
21
lib/Node.hpp
|
@ -4,16 +4,17 @@
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
#include "SrcLoc.hpp"
|
#include "SrcLoc.hpp"
|
||||||
|
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \
|
G(NODE_PROG), G(NODE_INSTR), G(NODE_EOI), \
|
||||||
G(NODE_INT), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
|
G(NODE_INT), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), \
|
||||||
G(NODE_DIV), G(NODE_MOD), G(NODE_POW), G(NODE_OPAR), \
|
G(NODE_DIV), G(NODE_MOD), G(NODE_POW), G(NODE_OPAR), \
|
||||||
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
|
G(NODE_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
|
||||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IMP), \
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IMP), \
|
||||||
G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
G(NODE_EQ), G(NODE_NE), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
||||||
G(NODE_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL), \
|
G(NODE_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL), \
|
||||||
G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_LET), G(NODE_LET_MUT), \
|
G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_LET), G(NODE_LET_MUT), \
|
||||||
G(NODE_VARDECL), G(NODE_CONSTDECL)
|
G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_IF), G(NODE_ELSE), \
|
||||||
|
G(NODE_THEN), G(NODE_END)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -159,6 +159,12 @@ namespace roza
|
||||||
ensure(NODE_EOI);
|
ensure(NODE_EOI);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
else if (type_is(NODE_IF))
|
||||||
|
{
|
||||||
|
auto root = parse_if();
|
||||||
|
consume_all(NODE_EOI);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto root = parse_expr();
|
auto root = parse_expr();
|
||||||
|
@ -213,6 +219,55 @@ namespace roza
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_if()
|
||||||
|
{
|
||||||
|
auto root = consume(NODE_IF);
|
||||||
|
root->add_child(parse_expr());
|
||||||
|
root->add_child(parse_then());
|
||||||
|
|
||||||
|
if (type_is(NODE_ELSE)
|
||||||
|
&& type_is(NODE_IF, 1))
|
||||||
|
{
|
||||||
|
consume(NODE_ELSE);
|
||||||
|
root->add_child(parse_if());
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_is(NODE_ELSE))
|
||||||
|
{
|
||||||
|
root->add_child(parse_else());
|
||||||
|
}
|
||||||
|
|
||||||
|
consume(NODE_END);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_then()
|
||||||
|
{
|
||||||
|
auto root = std::make_shared<Node>(NODE_THEN, "", node()->loc());
|
||||||
|
|
||||||
|
while (!type_is(NODE_ELSE)
|
||||||
|
&& !type_is(NODE_END))
|
||||||
|
{
|
||||||
|
root->add_child(parse_instr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_else()
|
||||||
|
{
|
||||||
|
auto root = consume(NODE_ELSE);
|
||||||
|
|
||||||
|
while (!type_is(NODE_END))
|
||||||
|
{
|
||||||
|
root->add_child(parse_instr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_expr()
|
std::shared_ptr<Node> Parser::parse_expr()
|
||||||
{
|
{
|
||||||
return parse_imp();
|
return parse_imp();
|
||||||
|
|
|
@ -36,6 +36,9 @@ namespace roza
|
||||||
std::shared_ptr<Node> parse_vardecl();
|
std::shared_ptr<Node> parse_vardecl();
|
||||||
std::shared_ptr<Node> parse_constdecl();
|
std::shared_ptr<Node> parse_constdecl();
|
||||||
std::shared_ptr<Node> parse_assign();
|
std::shared_ptr<Node> parse_assign();
|
||||||
|
std::shared_ptr<Node> parse_if();
|
||||||
|
std::shared_ptr<Node> parse_then();
|
||||||
|
std::shared_ptr<Node> parse_else();
|
||||||
|
|
||||||
std::shared_ptr<Node> parse_expr();
|
std::shared_ptr<Node> parse_expr();
|
||||||
std::shared_ptr<Node> parse_imp();
|
std::shared_ptr<Node> parse_imp();
|
||||||
|
|
|
@ -45,6 +45,12 @@ namespace roza
|
||||||
return index < m_values.size();
|
return index < m_values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Program::set_param(size_t index, param_t param)
|
||||||
|
{
|
||||||
|
assert(index < m_instrs.size());
|
||||||
|
m_instrs[index].param = param;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Program::string() const
|
std::string Program::string() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
@ -30,6 +30,8 @@ namespace roza
|
||||||
std::shared_ptr<Value> value(size_t index) const;
|
std::shared_ptr<Value> value(size_t index) const;
|
||||||
bool has_value(size_t index) const;
|
bool has_value(size_t index) const;
|
||||||
|
|
||||||
|
void set_param(size_t index, param_t param);
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -26,6 +26,20 @@ namespace roza
|
||||||
|
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
|
case NODE_IF: {
|
||||||
|
m_sym.enter_scope();
|
||||||
|
auto cond_type = resolver.find(root->child(0), m_sym);
|
||||||
|
check_types(root, std::make_shared<Type>(TY_BOOL), cond_type);
|
||||||
|
check_children(root);
|
||||||
|
m_sym.leave_scope();
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_THEN:
|
||||||
|
case NODE_ELSE: {
|
||||||
|
check_children(root);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
|
||||||
case NODE_CONSTDECL: {
|
case NODE_CONSTDECL: {
|
||||||
check(root->child(1));
|
check(root->child(1));
|
||||||
m_sym.declare(root->child(0)->repr(), root->child(1));
|
m_sym.declare(root->child(0)->repr(), root->child(1));
|
||||||
|
|
119
lib/SymTable.cpp
119
lib/SymTable.cpp
|
@ -11,59 +11,130 @@ namespace roza
|
||||||
/*explicit*/ SymTable::SymTable(SymTable const& sym_table)
|
/*explicit*/ SymTable::SymTable(SymTable const& sym_table)
|
||||||
{
|
{
|
||||||
m_scope = sym_table.m_scope;
|
m_scope = sym_table.m_scope;
|
||||||
|
m_entries = sym_table.m_entries;
|
||||||
for (auto const& entry: sym_table.m_entries)
|
|
||||||
{
|
|
||||||
m_entries[entry.first] = entry.second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ SymTable::~SymTable()
|
/*virtual*/ SymTable::~SymTable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymTable::enter_scope()
|
||||||
|
{
|
||||||
|
m_scope++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymTable::leave_scope()
|
||||||
|
{
|
||||||
|
auto iter = std::begin(m_entries);
|
||||||
|
|
||||||
|
while (iter != std::end(m_entries))
|
||||||
|
{
|
||||||
|
if (iter->scope >= m_scope)
|
||||||
|
{
|
||||||
|
iter = m_entries.erase(iter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scope--;
|
||||||
|
}
|
||||||
|
|
||||||
int SymTable::declare(std::string const& name, std::shared_ptr<Node> node)
|
int SymTable::declare(std::string const& name, std::shared_ptr<Node> node)
|
||||||
{
|
{
|
||||||
assert(!exists(name));
|
assert(!exists_in_scope(name));
|
||||||
|
|
||||||
m_entries.insert({name, SymEntry {
|
m_entries.push_back(SymEntry {
|
||||||
SymTable::addr++,
|
name,
|
||||||
m_scope,
|
SymTable::addr++,
|
||||||
node,
|
m_scope,
|
||||||
false
|
node,
|
||||||
}});
|
false
|
||||||
|
});
|
||||||
|
|
||||||
return SymTable::addr - 1;
|
return SymTable::addr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
int SymTable::declare_mut(std::string const& name, std::shared_ptr<Node> node)
|
||||||
{
|
{
|
||||||
assert(!exists(name));
|
int addr = declare(name, node);
|
||||||
|
m_entries.back().is_mut = true;
|
||||||
|
|
||||||
m_entries.insert({name, SymEntry {
|
return addr;
|
||||||
SymTable::addr++,
|
|
||||||
m_scope,
|
|
||||||
node,
|
|
||||||
true
|
|
||||||
}});
|
|
||||||
|
|
||||||
return SymTable::addr - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SymEntry& SymTable::find(std::string const& name)
|
SymEntry& SymTable::find(std::string const& name)
|
||||||
{
|
{
|
||||||
assert(exists(name));
|
assert(exists(name));
|
||||||
return m_entries[name];
|
|
||||||
|
size_t idx = 0;
|
||||||
|
int scope = -1;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto const& entry: m_entries)
|
||||||
|
{
|
||||||
|
if (entry.name == name && entry.scope > scope)
|
||||||
|
{
|
||||||
|
idx = i;
|
||||||
|
scope = entry.scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(scope >= 0);
|
||||||
|
|
||||||
|
return m_entries[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
SymEntry const& SymTable::find(std::string const& name) const
|
SymEntry const& SymTable::find(std::string const& name) const
|
||||||
{
|
{
|
||||||
assert(exists(name));
|
assert(exists(name));
|
||||||
return m_entries.at(name);
|
|
||||||
|
size_t idx = 0;
|
||||||
|
int scope = -1;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (auto const& entry: m_entries)
|
||||||
|
{
|
||||||
|
if (entry.name == name && entry.scope > scope)
|
||||||
|
{
|
||||||
|
idx = i;
|
||||||
|
scope = entry.scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(scope >= 0);
|
||||||
|
|
||||||
|
return m_entries[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SymTable::exists(std::string const& name) const
|
bool SymTable::exists(std::string const& name) const
|
||||||
{
|
{
|
||||||
return m_entries.find(name) != std::end(m_entries);
|
for (auto const& entry: m_entries)
|
||||||
|
{
|
||||||
|
if (entry.name == name) { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SymTable::exists_in_scope(std::string const& name) const
|
||||||
|
{
|
||||||
|
for (auto const& entry: m_entries)
|
||||||
|
{
|
||||||
|
if (entry.name == name && entry.scope >= m_scope)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
struct SymEntry {
|
struct SymEntry {
|
||||||
|
std::string name;
|
||||||
int addr;
|
int addr;
|
||||||
int scope;
|
int scope;
|
||||||
std::shared_ptr<Node> node;
|
std::shared_ptr<Node> node;
|
||||||
|
@ -21,6 +22,9 @@ namespace roza
|
||||||
|
|
||||||
virtual ~SymTable();
|
virtual ~SymTable();
|
||||||
|
|
||||||
|
void enter_scope();
|
||||||
|
void leave_scope();
|
||||||
|
|
||||||
int declare(std::string const& name, std::shared_ptr<Node> node);
|
int declare(std::string const& name, std::shared_ptr<Node> node);
|
||||||
int declare_mut(std::string const& name, std::shared_ptr<Node> node);
|
int declare_mut(std::string const& name, std::shared_ptr<Node> node);
|
||||||
|
|
||||||
|
@ -28,10 +32,11 @@ namespace roza
|
||||||
SymEntry const& find(std::string const& name) const;
|
SymEntry const& find(std::string const& name) const;
|
||||||
|
|
||||||
bool exists(std::string const& name) const;
|
bool exists(std::string const& name) const;
|
||||||
|
bool exists_in_scope(std::string const& name) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int addr;
|
static int addr;
|
||||||
std::unordered_map<std::string, SymEntry> m_entries;
|
std::vector<SymEntry> m_entries;
|
||||||
int m_scope = 0;
|
int m_scope = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
18
lib/VM.cpp
18
lib/VM.cpp
|
@ -19,6 +19,24 @@ namespace roza
|
||||||
{
|
{
|
||||||
switch (program->opcode(m_pc))
|
switch (program->opcode(m_pc))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
case OP_BRF: {
|
||||||
|
auto value = program->value(pop());
|
||||||
|
|
||||||
|
if (!value->as_bool())
|
||||||
|
{
|
||||||
|
m_pc = *program->param(m_pc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pc++;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_BR: {
|
||||||
|
m_pc = *program->param(m_pc);
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_LOAD_GLOBAL: {
|
case OP_LOAD_GLOBAL: {
|
||||||
int addr = *program->param(m_pc);
|
int addr = *program->param(m_pc);
|
||||||
auto value = m_globals[addr];
|
auto value = m_globals[addr];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef roza_COMMONS_HPP
|
#ifndef roza_COMMONS_HPP
|
||||||
#define roza_COMMONS_HPP
|
#define roza_COMMONS_HPP
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
G(OP_IADD), G(OP_ISUB), G(OP_IMUL), G(OP_IDIV), G(OP_IMOD), G(OP_IPOW), \
|
G(OP_IADD), G(OP_ISUB), G(OP_IMUL), G(OP_IDIV), G(OP_IMOD), G(OP_IPOW), \
|
||||||
G(OP_MOD), G(OP_IUADD), G(OP_IUSUB), G(OP_AND), G(OP_OR), G(OP_NOT), \
|
G(OP_MOD), G(OP_IUADD), G(OP_IUSUB), G(OP_AND), G(OP_OR), G(OP_NOT), \
|
||||||
G(OP_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT), G(OP_STORE_GLOBAL), \
|
G(OP_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT), G(OP_STORE_GLOBAL), \
|
||||||
G(OP_LOAD_GLOBAL)
|
G(OP_LOAD_GLOBAL), G(OP_BRF), G(OP_BR)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
let! a = 0
|
||||||
|
|
||||||
|
if true
|
||||||
|
a = 7
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 7 == a
|
||||||
|
|
||||||
|
if false
|
||||||
|
a = 9
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 7 == a
|
||||||
|
|
||||||
|
if true
|
||||||
|
a = 0
|
||||||
|
else
|
||||||
|
a = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 0 == a
|
||||||
|
|
||||||
|
if false
|
||||||
|
a = 0
|
||||||
|
else
|
||||||
|
a = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 1 == a
|
||||||
|
|
||||||
|
if true
|
||||||
|
a = 1
|
||||||
|
else if true
|
||||||
|
a = 2
|
||||||
|
else if true
|
||||||
|
a = 3
|
||||||
|
else
|
||||||
|
a = 4
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 1 == a
|
||||||
|
|
||||||
|
if false
|
||||||
|
a = 1
|
||||||
|
else if true
|
||||||
|
a = 2
|
||||||
|
else if true
|
||||||
|
a = 3
|
||||||
|
else
|
||||||
|
a = 4
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 2 == a
|
||||||
|
|
||||||
|
if false
|
||||||
|
a = 1
|
||||||
|
else if false
|
||||||
|
a = 2
|
||||||
|
else if true
|
||||||
|
a = 3
|
||||||
|
else
|
||||||
|
a = 4
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 3 == a
|
||||||
|
|
||||||
|
if false
|
||||||
|
a = 1
|
||||||
|
else if false
|
||||||
|
a = 2
|
||||||
|
else if false
|
||||||
|
a = 3
|
||||||
|
else
|
||||||
|
a = 4
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 4 == a
|
||||||
|
|
||||||
|
let! b = 54
|
||||||
|
let! c = 33
|
||||||
|
|
||||||
|
if true
|
||||||
|
let! b = 18
|
||||||
|
c = 7
|
||||||
|
assert 18 == b
|
||||||
|
end
|
||||||
|
|
||||||
|
assert 54 == b
|
||||||
|
assert 7 == c
|
||||||
|
|
||||||
|
|
||||||
|
assert_static_fail if 4 0; end
|
|
@ -103,3 +103,12 @@ TEST_CASE_METHOD(LexerTest, "Lexer_declarations")
|
||||||
REQUIRE("ASSIGN" == get_str(3));
|
REQUIRE("ASSIGN" == get_str(3));
|
||||||
REQUIRE("" == get_str(4));
|
REQUIRE("" == get_str(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_if")
|
||||||
|
{
|
||||||
|
m_lexer.scan(" if else end ");
|
||||||
|
REQUIRE("IF" == get_str(0));
|
||||||
|
REQUIRE("ELSE" == get_str(1));
|
||||||
|
REQUIRE("END" == get_str(2));
|
||||||
|
REQUIRE("" == get_str(3));
|
||||||
|
}
|
||||||
|
|
|
@ -122,3 +122,18 @@ TEST_CASE_METHOD(ParserTest, "Parser_vardecl")
|
||||||
test_node("PROG(CONSTDECL(IDENT[_coucou],MUL(INT[6],INT[7])))",
|
test_node("PROG(CONSTDECL(IDENT[_coucou],MUL(INT[6],INT[7])))",
|
||||||
"let _coucou = 6 * 7");
|
"let _coucou = 6 * 7");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_if")
|
||||||
|
{
|
||||||
|
test_node("PROG(IF(BOOL[true],THEN(ASSIGN(IDENT[x],INT[4]))))",
|
||||||
|
"if true x = 4; end");
|
||||||
|
|
||||||
|
test_node("PROG(IF(BOOL[true],THEN(INT[1]),ELSE(INT[4])))",
|
||||||
|
"if true 1; else 4; end");
|
||||||
|
|
||||||
|
test_node("PROG(IF(BOOL[true],THEN(INT[0]),"
|
||||||
|
"IF(BOOL[false],THEN(INT[1]),"
|
||||||
|
"IF(BOOL[true],THEN(INT[2]),"
|
||||||
|
"ELSE(INT[3])))))",
|
||||||
|
"if true 0; else if false 1; else if true 2; else 3; end");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue