Compare commits

...

3 Commits

Author SHA1 Message Date
bog 66283e23bb ADD: assert and assert_static_fail instructions. 2023-08-31 14:41:43 +02:00
bog 50f66409b2 ADD: comparisons operators. 2023-08-31 11:37:13 +02:00
bog 08fc0d5d19 ADD: booleans. 2023-08-31 11:07:03 +02:00
22 changed files with 786 additions and 75 deletions

View File

@ -1,11 +1,22 @@
PROG ::= (INSTR (EOI INSTR)*)? PROG ::= (INSTR (EOI+ INSTR)*)?
INSTR ::= EXPR INSTR ::= EXPR
EXPR ::= TERM | assert EXPR
| assert_static_fail EXPR
EXPR ::= IMP
IMP ::= OR (imp OR)?
OR ::= AND (or AND)*
AND ::= EQ (and EQ)*
EQ ::= CMP ((eq | ne) CMP)?
CMP ::= TERM ((lt | le | gt | ge) TERM)?
TERM ::= FACTOR ((add | sub) FACTOR)* TERM ::= FACTOR ((add | sub) FACTOR)*
FACTOR ::= UNOP ((mul | div | mod) UNOP)* FACTOR ::= UNOP ((mul | div | mod) UNOP)*
UNOP ::= (add | sub)? POW UNOP ::= (add | sub | not)? POW
POW ::= GROUP (pow GROUP)? POW ::= GROUP (pow GROUP)?
GROUP ::= BASE | opar EXPR cpar GROUP ::= BASE | opar EXPR cpar
BASE ::= int BASE ::= int | bool

View File

@ -1,5 +1,7 @@
#include "Compiler.hpp" #include "Compiler.hpp"
#include "lib/Node.hpp"
#include "lib/opcodes.hpp" #include "lib/opcodes.hpp"
#include "StaticPass.hpp"
namespace roza namespace roza
{ {
@ -23,11 +25,96 @@ namespace roza
{ {
switch (root->type()) switch (root->type())
{ {
case NODE_ASSERT: {
compile_children(root, prog);
prog->push_instr(OP_ASSERT);
} break;
case NODE_ASSERT_STATIC_FAIL: {
bool failed = false;
try
{
StaticPass static_pass {m_log};
static_pass.check_children(root);
compile_children(root, prog);
failed = true;
}
catch(...)
{
}
if (failed)
{
m_log.fatal(root->loc(), "static assertion failed");
}
} break;
case NODE_INT: { case NODE_INT: {
auto value = std::make_shared<Value>(std::stoi(root->repr()), root->loc()); auto value = std::make_shared<Value>(std::stoi(root->repr()), root->loc());
prog->push_instr(OP_PUSH_CONST, prog->push_value(value)); prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
} break; } break;
case NODE_BOOL: {
auto value = std::make_shared<Value>(root->repr() == "true", root->loc());
prog->push_instr(OP_PUSH_CONST, prog->push_value(value));
} break;
case NODE_EQ: {
compile_children(root, prog);
prog->push_instr(OP_EQ);
} break;
case NODE_NE: {
compile_children(root, prog);
prog->push_instr(OP_EQ);
prog->push_instr(OP_NOT);
} break;
case NODE_LT: {
compile_children(root, prog);
prog->push_instr(OP_ILT);
} break;
case NODE_GT: {
compile_children(root, prog);
prog->push_instr(OP_IGT);
} break;
case NODE_LE: {
compile_children(root, prog);
prog->push_instr(OP_IGT);
prog->push_instr(OP_NOT);
} break;
case NODE_GE: {
compile_children(root, prog);
prog->push_instr(OP_ILT);
prog->push_instr(OP_NOT);
} break;
case NODE_IMP: {
compile_children(root, prog);
prog->push_instr(OP_IMP);
} break;
case NODE_AND: {
compile_children(root, prog);
prog->push_instr(OP_AND);
} break;
case NODE_OR: {
compile_children(root, prog);
prog->push_instr(OP_OR);
} break;
case NODE_NOT: {
compile_children(root, prog);
prog->push_instr(OP_NOT);
} break;
case NODE_ADD: { case NODE_ADD: {
compile_children(root, prog); compile_children(root, prog);
prog->push_instr(OP_IADD); prog->push_instr(OP_IADD);

View File

@ -7,15 +7,52 @@ namespace roza
: m_log { log } : m_log { log }
, m_loc { loc } , m_loc { loc }
{ {
std::vector<std::tuple<std::string, NodeType, bool>> texts = {
{"==", NODE_EQ, false},
{"!=", NODE_NE, false},
{"<=", NODE_LE, false},
{">=", NODE_GE, false},
{"<", NODE_LT, false},
{">", NODE_GT, false},
{"=>", NODE_IMP, false},
{"+", NODE_ADD, false},
{"-", NODE_SUB, false},
{"*", NODE_MUL, false},
{"/", NODE_DIV, false},
{"%", NODE_MOD, false},
{"^", NODE_POW, false},
{"(", NODE_OPAR, false},
{")", NODE_CPAR, false},
};
std::vector<std::tuple<std::string, NodeType, bool>> keywords = {
{"true", NODE_BOOL, true},
{"false", NODE_BOOL, true},
{"and", NODE_AND, false},
{"or", NODE_OR, false},
{"not", NODE_NOT, false},
{"assert_static_fail", NODE_ASSERT_STATIC_FAIL, false},
{"assert", NODE_ASSERT, false},
};
m_scanners.push_back(std::bind(&Lexer::scan_int, this)); m_scanners.push_back(std::bind(&Lexer::scan_int, this));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "+", NODE_ADD, false));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "-", NODE_SUB, false)); for (auto const& entry: keywords)
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "*", NODE_MUL, false)); {
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "/", NODE_DIV, false)); m_scanners.push_back(std::bind(&Lexer::scan_keyword, this,
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "%", NODE_MOD, false)); std::get<0>(entry),
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "^", NODE_POW, false)); std::get<1>(entry),
m_scanners.push_back(std::bind(&Lexer::scan_text, this, "(", NODE_OPAR, false)); std::get<2>(entry)));
m_scanners.push_back(std::bind(&Lexer::scan_text, this, ")", NODE_CPAR, false)); }
for (auto const& entry: texts)
{
m_scanners.push_back(std::bind(&Lexer::scan_text, this,
std::get<0>(entry),
std::get<1>(entry),
std::get<2>(entry)));
}
} }
@ -118,6 +155,18 @@ namespace roza
return m_nodes.at(index); return m_nodes.at(index);
} }
bool Lexer::is_sep(size_t index) const
{
if (index >= m_source.size())
{
return true;
}
char c = m_source[index];
return !std::isalnum(c);
}
ScanInfo Lexer::scan_int() const ScanInfo Lexer::scan_int() const
{ {
size_t cursor = m_cursor; size_t cursor = m_cursor;
@ -160,4 +209,20 @@ namespace roza
m_cursor + text.size() m_cursor + text.size()
}; };
} }
ScanInfo Lexer::scan_keyword(std::string const& keyword,
NodeType type,
bool value) const
{
auto info = scan_text(keyword, type, value);
if (is_sep(info.cursor))
{
return info;
}
return ScanInfo {
};
}
} }

View File

@ -38,10 +38,16 @@ namespace roza
std::vector<std::shared_ptr<Node>> m_nodes; std::vector<std::shared_ptr<Node>> m_nodes;
std::vector<scanner> m_scanners; std::vector<scanner> m_scanners;
bool is_sep(size_t index) const;
ScanInfo scan_int() const; ScanInfo scan_int() const;
ScanInfo scan_text(std::string const& text, ScanInfo scan_text(std::string const& text,
NodeType type, NodeType type,
bool value=false) const; bool value=false) const;
ScanInfo scan_keyword(std::string const& keyword,
NodeType type,
bool value=false) const;
}; };
} }

View File

@ -8,7 +8,10 @@
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_CPAR), G(NODE_UADD), G(NODE_USUB), G(NODE_BOOL), \
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_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL)
namespace roza namespace roza
{ {

View File

@ -1,5 +1,6 @@
#include "Parser.hpp" #include "Parser.hpp"
#include "lib/Node.hpp" #include "lib/Node.hpp"
#include <memory>
namespace roza namespace roza
{ {
@ -67,6 +68,7 @@ namespace roza
+ "', got '" + "', got '"
+ NodeTypeStr[type()] + NodeTypeStr[type()]
+ "'"); + "'");
return nullptr; return nullptr;
} }
@ -117,7 +119,22 @@ namespace roza
std::shared_ptr<Node> Parser::parse_instr() std::shared_ptr<Node> Parser::parse_instr()
{ {
auto root = parse_expr(); consume_all(NODE_EOI);
std::shared_ptr<Node> root;
if (type_is(NODE_ASSERT)
|| type_is(NODE_ASSERT_STATIC_FAIL))
{
root = consume();
root->add_child(parse_expr());
}
else
{
root = parse_expr();
}
consume_or_nullptr(NODE_EOI); consume_or_nullptr(NODE_EOI);
consume_all(NODE_EOI); consume_all(NODE_EOI);
@ -126,7 +143,86 @@ namespace roza
std::shared_ptr<Node> Parser::parse_expr() std::shared_ptr<Node> Parser::parse_expr()
{ {
return parse_term(); return parse_imp();
}
std::shared_ptr<Node> Parser::parse_imp()
{
auto lhs = parse_or();
if (type_is(NODE_IMP))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_or());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_or()
{
auto lhs = parse_and();
while (type_is(NODE_OR))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_and());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_and()
{
auto lhs = parse_eq();
while (type_is(NODE_AND))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_eq());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_eq()
{
auto lhs = parse_cmp();
if (type_is(NODE_EQ)
|| type_is(NODE_NE))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_cmp());
lhs = root;
}
return lhs;
}
std::shared_ptr<Node> Parser::parse_cmp()
{
auto lhs = parse_term();
if (type_is(NODE_LT)
|| type_is(NODE_LE)
|| type_is(NODE_GT)
|| type_is(NODE_GE))
{
auto root = consume();
root->add_child(lhs);
root->add_child(parse_term());
lhs = root;
}
return lhs;
} }
std::shared_ptr<Node> Parser::parse_term() std::shared_ptr<Node> Parser::parse_term()
@ -181,6 +277,15 @@ namespace roza
return root; return root;
} }
if (type_is(NODE_NOT))
{
auto root = std::make_shared<Node>(NODE_NOT, "", m_lexer.loc());
next();
root->add_child(parse_pow());
return root;
}
return parse_pow(); return parse_pow();
} }
@ -214,7 +319,18 @@ namespace roza
std::shared_ptr<Node> Parser::parse_base() std::shared_ptr<Node> Parser::parse_base()
{ {
return parse_int(); if (type_is(NODE_INT)
|| type_is(NODE_BOOL))
{
return consume();
}
m_log.fatal(node()->loc(),
"unknown node '"
+ node()->string()
+ "'");
return nullptr;
} }
std::shared_ptr<Node> Parser::parse_int() std::shared_ptr<Node> Parser::parse_int()

View File

@ -32,6 +32,11 @@ namespace roza
std::shared_ptr<Node> parse_prog(); std::shared_ptr<Node> parse_prog();
std::shared_ptr<Node> parse_instr(); std::shared_ptr<Node> parse_instr();
std::shared_ptr<Node> parse_expr(); std::shared_ptr<Node> parse_expr();
std::shared_ptr<Node> parse_imp();
std::shared_ptr<Node> parse_or();
std::shared_ptr<Node> parse_and();
std::shared_ptr<Node> parse_eq();
std::shared_ptr<Node> parse_cmp();
std::shared_ptr<Node> parse_term(); std::shared_ptr<Node> parse_term();
std::shared_ptr<Node> parse_factor(); std::shared_ptr<Node> parse_factor();
std::shared_ptr<Node> parse_unop(); std::shared_ptr<Node> parse_unop();

View File

@ -19,17 +19,81 @@ namespace roza
switch (root->type()) switch (root->type())
{ {
case NODE_INT: break; case NODE_ASSERT_STATIC_FAIL:
case NODE_INT:
case NODE_BOOL:
break;
case NODE_EQ:
case NODE_NE: {
check_children(root);
auto lhs = resolver.find(root->child(0));
auto rhs = resolver.find(root->child(1));
check_types(root, lhs, rhs);
} break;
case NODE_IMP:
case NODE_OR:
case NODE_AND: {
check_children(root);
auto lhs = resolver.find(root->child(0));
auto rhs = resolver.find(root->child(1));
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
check_types(root, lhs, rhs);
} break;
case NODE_ASSERT:
case NODE_NOT: {
check_children(root);
auto lhs = resolver.find(root->child(0));
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
} break;
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:
case NODE_ADD: case NODE_ADD:
case NODE_SUB: case NODE_SUB:
case NODE_MUL: case NODE_MUL:
case NODE_DIV: case NODE_DIV:
case NODE_MOD: case NODE_MOD:
case NODE_POW: { case NODE_POW: {
check_children(root);
auto lhs = resolver.find(root->child(0)); auto lhs = resolver.find(root->child(0));
auto rhs = resolver.find(root->child(1)); auto rhs = resolver.find(root->child(1));
check_types(root, lhs, std::make_shared<Type>(TY_INT));
check_types(root, lhs, rhs);
} break;
case NODE_UADD:
case NODE_USUB: {
check_children(root);
auto lhs = resolver.find(root->child(0));
check_types(root, lhs, std::make_shared<Type>(TY_INT));
} break;
case NODE_PROG: {
check_children(root);
} break;
default:
m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'");
}
}
void StaticPass::check_children(std::shared_ptr<Node> root)
{
for (size_t i=0; i<root->size(); i++)
{
check(root->child(i));
}
}
void StaticPass::check_types(std::shared_ptr<Node> root,
std::shared_ptr<Type> lhs,
std::shared_ptr<Type> rhs)
{
if (!lhs->equals(*rhs)) if (!lhs->equals(*rhs))
{ {
m_log.fatal(root->loc(), m_log.fatal(root->loc(),
@ -40,22 +104,31 @@ namespace roza
+ rhs->string() + rhs->string()
+ "'"); + "'");
} }
}
} break; void StaticPass::check_types(std::shared_ptr<Node> root,
std::shared_ptr<Type> lhs,
case NODE_UADD: std::vector<std::shared_ptr<Type>> const& rhs)
case NODE_USUB: {
} break;
case NODE_PROG: {
for (size_t i=0; i<root->size(); i++)
{ {
check(root->child(i)); for (auto const& ty: rhs)
{
if (lhs->equals(*ty))
{
return;
}
} }
} break;
default: std::stringstream ss;
m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'");
ss << "type mismatch, got '" << lhs->string() << "'";
ss << "candidates are:" << std::endl;
for (auto ty: rhs)
{
ss << "\t-> " << ty->string() << std::endl;
} }
m_log.fatal(root->loc(), ss.str());
} }
} }

View File

@ -4,6 +4,7 @@
#include "commons.hpp" #include "commons.hpp"
#include "StatusLog.hpp" #include "StatusLog.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Type.hpp"
namespace roza namespace roza
{ {
@ -14,9 +15,18 @@ namespace roza
virtual ~StaticPass(); virtual ~StaticPass();
void check(std::shared_ptr<Node> root); void check(std::shared_ptr<Node> root);
void check_children(std::shared_ptr<Node> root);
private: private:
StatusLog& m_log; StatusLog& m_log;
void check_types(std::shared_ptr<Node> root,
std::shared_ptr<Type> lhs,
std::shared_ptr<Type> rhs);
void check_types(std::shared_ptr<Node> root,
std::shared_ptr<Type> lhs,
std::vector<std::shared_ptr<Type>> const& rhs);
}; };
} }

View File

@ -4,7 +4,7 @@
#include "commons.hpp" #include "commons.hpp"
#define BASE_TYPE(G) \ #define BASE_TYPE(G) \
G(TY_INT) G(TY_INT), G(TY_BOOL)
namespace roza namespace roza
{ {

View File

@ -23,6 +23,20 @@ namespace roza
return std::make_shared<Type>(BaseType::TY_INT); return std::make_shared<Type>(BaseType::TY_INT);
} break; } break;
case NODE_EQ:
case NODE_NE:
case NODE_LT:
case NODE_LE:
case NODE_GT:
case NODE_GE:
case NODE_IMP:
case NODE_AND:
case NODE_OR:
case NODE_NOT:
case NODE_BOOL: {
return std::make_shared<Type>(BaseType::TY_BOOL);
} break;
case NODE_ADD: case NODE_ADD:
case NODE_SUB: case NODE_SUB:
case NODE_MUL: case NODE_MUL:

View File

@ -19,12 +19,76 @@ namespace roza
{ {
switch (program->opcode(m_pc)) switch (program->opcode(m_pc))
{ {
case OP_ASSERT: {
auto value = program->value(pop());
if (!value->as_bool())
{
m_log.fatal(value->loc(), "assertion failed");
}
m_pc++;
} break;
case OP_PUSH_CONST: { case OP_PUSH_CONST: {
param_t param = *program->param(m_pc); param_t param = *program->param(m_pc);
push(param); push(param);
m_pc++; m_pc++;
} break; } break;
case OP_EQ: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->equals(*rhs),
lhs->loc());
});
} break;
case OP_ILT: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() < rhs->as_int(),
lhs->loc());
});
} break;
case OP_IGT: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() > rhs->as_int(),
lhs->loc());
});
} break;
case OP_IMP: {
apply_binop(program, [](auto lhs, auto rhs){
bool a = lhs->as_bool();
bool b = rhs->as_bool();
return std::make_shared<Value>(!a || b,
lhs->loc());
});
} break;
case OP_AND: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_bool() && rhs->as_bool(),
lhs->loc());
});
} break;
case OP_OR: {
apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_bool() || rhs->as_bool(),
lhs->loc());
});
} break;
case OP_NOT: {
apply_unop(program, [](auto lhs){
return std::make_shared<Value>(!lhs->as_bool(),
lhs->loc());
});
} break;
case OP_IADD: { case OP_IADD: {
apply_binop(program, [](auto lhs, auto rhs){ apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(lhs->as_int() + rhs->as_int(), return std::make_shared<Value>(lhs->as_int() + rhs->as_int(),
@ -62,7 +126,8 @@ namespace roza
case OP_IPOW: { case OP_IPOW: {
apply_binop(program, [](auto lhs, auto rhs){ apply_binop(program, [](auto lhs, auto rhs){
return std::make_shared<Value>(std::pow(lhs->as_int(), rhs->as_int()), return std::make_shared<Value>(static_cast<int>(std::pow(lhs->as_int(),
rhs->as_int())),
lhs->loc()); lhs->loc());
}); });
} break; } break;

View File

@ -9,6 +9,13 @@ namespace roza
{ {
} }
/*explicit*/ Value::Value(bool value, SrcLoc loc)
: m_type { std::make_shared<Type>(BaseType::TY_BOOL) }
, m_bool_val { value }
, m_loc { loc }
{
}
/*virtual*/ Value::~Value() /*virtual*/ Value::~Value()
{ {
} }
@ -20,6 +27,33 @@ namespace roza
return std::to_string(m_int_val); return std::to_string(m_int_val);
} }
if (m_type->equals(TY_BOOL))
{
return m_bool_val ? "true" : "false";
}
assert("cannot stringify unknown value " && 0); assert("cannot stringify unknown value " && 0);
} }
bool Value::equals(Value const& rhs) const
{
if (!m_type->equals(*rhs.m_type))
{
return false;
}
switch (m_type->base())
{
case TY_BOOL: {
return as_bool() == rhs.as_bool();
} break;
case TY_INT: {
return as_int() == rhs.as_int();
} break;
default:
assert("value equals: base type not found" && 0);
}
}
} }

View File

@ -11,16 +11,22 @@ namespace roza
{ {
public: public:
explicit Value(int value, SrcLoc loc); explicit Value(int value, SrcLoc loc);
explicit Value(bool value, SrcLoc loc);
virtual ~Value(); virtual ~Value();
SrcLoc loc() const { return m_loc; } SrcLoc loc() const { return m_loc; }
int as_int() const { return m_int_val; } int as_int() const { return m_int_val; }
bool as_bool() const { return m_bool_val; }
std::shared_ptr<Type> type() const { return m_type; } std::shared_ptr<Type> type() const { return m_type; }
std::string string() const; std::string string() const;
bool equals(Value const& rhs) const;
private: private:
std::shared_ptr<Type> m_type; std::shared_ptr<Type> m_type;
int m_int_val; int m_int_val;
bool m_bool_val;
SrcLoc m_loc; SrcLoc m_loc;
}; };
} }

View File

@ -7,7 +7,8 @@
G(OP_PUSH_CONST), \ G(OP_PUSH_CONST), \
G(OP_POP), \ G(OP_POP), \
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_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)
namespace roza namespace roza
{ {

34
roza_tests/run.sh Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
OK=0
KO=0
TOTAL=0
for file in $(find . -name "test_*.roza" | sort)
do
roza $file
RET="$?"
NAME=$(basename "$file" | cut -d '.' -f1)
echo -en "\e[34m$NAME...\e[0m"
if [ "$RET" == 0 ]
then
echo -e " \e[32mok\e[0m"
OK=$(($OK + 1))
else
echo -e " \e[31mko\e[0m"
KO=$(($KO + 1))
fi
TOTAL=$(($TOTAL + 1))
done
if [ $OK -eq $TOTAL ]
then
echo -e "\e[32m=== all tests passed ($OK) ===\e[0m"
exit 0
else
echo -e "\e[31m=== some tests failed ($KO) ===\e[0m"
exit -1
fi

30
roza_tests/test_bool.roza Normal file
View File

@ -0,0 +1,30 @@
assert true == true
assert false == false
assert true == (true and true)
assert false == (true and false)
assert false == (false and true)
assert false == (false and false)
assert true == (true or true)
assert true == (true or false)
assert true == (false or true)
assert false == (false or false)
assert false == not true
assert true == not false
assert true == (true => true)
assert false == (true => false)
assert true == (false => true)
assert true == (false => false)
assert (false or true) == (not (true and false))
assert_static_fail 1 and true
assert_static_fail false and 7
assert_static_fail 1 or true
assert_static_fail false or 7
assert_static_fail not 9
assert_static_fail 3 => true
assert_static_fail true => 7

54
roza_tests/test_int.roza Normal file
View File

@ -0,0 +1,54 @@
assert 5 == 5
assert 3 != 5
assert -9 == -10 + 1
assert -4 == 3 - 7
assert 4 == 7 - 3
assert 21 == 3 * 7
assert 3 == 21 / 7
assert 2 == 21 / 8
assert 3 == 7 % 4
assert 128 == 2 ^ 7
assert -128 == -2 ^ 7
assert 3 == +3
assert 0 - 7 == -7
assert 7 == 1 + 2 * 3
assert 9 == (1 + 2) * 3
assert true == 5 < 6
assert false == 5 < 5
assert false == 5 < 4
assert true == 5 <= 6
assert true == 5 <= 5
assert false == 5 <= 4
assert false == 5 > 6
assert false == 5 > 5
assert true == 5 > 4
assert false == 5 >= 6
assert true == 5 >= 5
assert true == 5 >= 4
assert_static_fail 5 + true
assert_static_fail 5 - true
assert_static_fail 5 * true
assert_static_fail 5 / true
assert_static_fail 5 % true
assert_static_fail 5 ^ true
assert_static_fail -true
assert_static_fail +true
assert_static_fail true + 9
assert_static_fail true - (4 + 1)
assert_static_fail true * 7
assert_static_fail true / 3
assert_static_fail true % 15
assert_static_fail true ^ 2
assert_static_fail true > 1
assert_static_fail 2 > false
assert_static_fail true < 1
assert_static_fail 2 < false
assert_static_fail true >= 1
assert_static_fail 2 >= false
assert_static_fail true <= 1
assert_static_fail 2 <= false

View File

@ -32,6 +32,8 @@ int main(int argc, char** argv)
Loader loader; Loader loader;
if (args.inputs().size() > 0) if (args.inputs().size() > 0)
{
try
{ {
auto source = loader.load(args.inputs()[0]); auto source = loader.load(args.inputs()[0]);
roza::SrcLoc loc {args.inputs()[0]}; roza::SrcLoc loc {args.inputs()[0]};
@ -77,7 +79,15 @@ int main(int argc, char** argv)
{ {
std::cout << vm->string() << std::endl; std::cout << vm->string() << std::endl;
} }
return 0;
}
catch(std::exception const& err)
{
std::cerr << err.what() << std::endl;
return -1;
} }
return 0; return 0;
}
} }

View File

@ -55,3 +55,42 @@ TEST_CASE_METHOD(LexerTest, "Lexer_int_arith")
REQUIRE("CPAR" == get_str(7)); REQUIRE("CPAR" == get_str(7));
REQUIRE("" == get_str(8)); REQUIRE("" == get_str(8));
} }
TEST_CASE_METHOD(LexerTest, "Lexer_keywords")
{
REQUIRE_THROWS(m_lexer.scan(" andor "));
REQUIRE_NOTHROW(m_lexer.scan(" and+ "));
REQUIRE_NOTHROW(m_lexer.scan(" (and) "));
}
TEST_CASE_METHOD(LexerTest, "Lexer_bool")
{
m_lexer.scan("and or not true false =>");
REQUIRE("AND" == get_str(0));
REQUIRE("OR" == get_str(1));
REQUIRE("NOT" == get_str(2));
REQUIRE("BOOL[true]" == get_str(3));
REQUIRE("BOOL[false]" == get_str(4));
REQUIRE("IMP" == get_str(5));
REQUIRE("" == get_str(6));
}
TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
{
m_lexer.scan("== != < > <= >=");
REQUIRE("EQ" == get_str(0));
REQUIRE("NE" == get_str(1));
REQUIRE("LT" == get_str(2));
REQUIRE("GT" == get_str(3));
REQUIRE("LE" == get_str(4));
REQUIRE("GE" == get_str(5));
REQUIRE("" == get_str(6));
}
TEST_CASE_METHOD(LexerTest, "Lexer_asserts")
{
m_lexer.scan(" assert assert_static_fail ");
REQUIRE("ASSERT" == get_str(0));
REQUIRE("ASSERT_STATIC_FAIL" == get_str(1));
REQUIRE("" == get_str(2));
}

View File

@ -70,3 +70,43 @@ TEST_CASE_METHOD(ParserTest, "Parser_int_arith")
test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 "); test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 ");
} }
TEST_CASE_METHOD(ParserTest, "Parser_bool")
{
test_node("PROG(BOOL[true])",
"true");
test_node("PROG(AND(BOOL[true],BOOL[false]))",
"true and false");
test_node("PROG(OR(BOOL[true],BOOL[false]))",
"true or false");
test_node("PROG(NOT(BOOL[false]))",
"not false");
test_node("PROG(NOT(OR(BOOL[false],BOOL[true])))",
"not (false or true)");
test_node("PROG(IMP(BOOL[true],BOOL[false]))",
"true => false");
}
TEST_CASE_METHOD(ParserTest, "Parser_comparisons")
{
test_node("PROG(LT(INT[5],INT[3]))",
"5 < 3");
test_node("PROG(EQ(LE(INT[5],INT[3]),BOOL[false]))",
"5 <= 3 == false");
}
TEST_CASE_METHOD(ParserTest, "Parser_assertions")
{
test_node("PROG(ASSERT(EQ(ADD(INT[1],INT[1]),INT[2])))",
"assert 1 + 1 == 2");
test_node("PROG(ASSERT_STATIC_FAIL(EQ(ADD(INT[1],INT[1]),INT[2])))",
"assert_static_fail 1 + 1 == 2");
}

View File

@ -33,4 +33,12 @@ protected:
TEST_CASE_METHOD(StaticPassTest, "StaticPass_integer") TEST_CASE_METHOD(StaticPassTest, "StaticPass_integer")
{ {
test_ok(" 43 "); test_ok(" 43 ");
test_ko(" 43 + 7 * true");
}
TEST_CASE_METHOD(StaticPassTest, "StaticPass_cmp")
{
test_ok(" 43 < 12 ");
test_ko(" 3 == true");
test_ko(" 2 > false");
} }