ADD: assert and assert_static_fail instructions.
parent
50f66409b2
commit
66283e23bb
|
@ -1,5 +1,9 @@
|
||||||
PROG ::= (INSTR (EOI INSTR)*)?
|
PROG ::= (INSTR (EOI+ INSTR)*)?
|
||||||
|
|
||||||
INSTR ::= EXPR
|
INSTR ::= EXPR
|
||||||
|
| assert EXPR
|
||||||
|
| assert_static_fail EXPR
|
||||||
|
|
||||||
EXPR ::= IMP
|
EXPR ::= IMP
|
||||||
|
|
||||||
IMP ::= OR (imp OR)?
|
IMP ::= OR (imp OR)?
|
||||||
|
|
|
@ -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,6 +25,33 @@ 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));
|
||||||
|
|
|
@ -31,6 +31,8 @@ namespace roza
|
||||||
{"and", NODE_AND, false},
|
{"and", NODE_AND, false},
|
||||||
{"or", NODE_OR, false},
|
{"or", NODE_OR, false},
|
||||||
{"not", NODE_NOT, false},
|
{"not", NODE_NOT, false},
|
||||||
|
{"assert_static_fail", NODE_ASSERT_STATIC_FAIL, false},
|
||||||
|
{"assert", NODE_ASSERT, false},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
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_GE), G(NODE_ASSERT), G(NODE_ASSERT_STATIC_FAIL)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +120,21 @@ namespace roza
|
||||||
std::shared_ptr<Node> Parser::parse_instr()
|
std::shared_ptr<Node> Parser::parse_instr()
|
||||||
{
|
{
|
||||||
consume_all(NODE_EOI);
|
consume_all(NODE_EOI);
|
||||||
auto root = parse_expr();
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace roza
|
||||||
|
|
||||||
switch (root->type())
|
switch (root->type())
|
||||||
{
|
{
|
||||||
|
case NODE_ASSERT_STATIC_FAIL:
|
||||||
case NODE_INT:
|
case NODE_INT:
|
||||||
case NODE_BOOL:
|
case NODE_BOOL:
|
||||||
break;
|
break;
|
||||||
|
@ -41,6 +42,7 @@ namespace roza
|
||||||
check_types(root, lhs, rhs);
|
check_types(root, lhs, rhs);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_ASSERT:
|
||||||
case NODE_NOT: {
|
case NODE_NOT: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
auto lhs = resolver.find(root->child(0));
|
auto lhs = resolver.find(root->child(0));
|
||||||
|
@ -67,6 +69,8 @@ namespace roza
|
||||||
case NODE_UADD:
|
case NODE_UADD:
|
||||||
case NODE_USUB: {
|
case NODE_USUB: {
|
||||||
check_children(root);
|
check_children(root);
|
||||||
|
auto lhs = resolver.find(root->child(0));
|
||||||
|
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_PROG: {
|
case NODE_PROG: {
|
||||||
|
|
12
lib/VM.cpp
12
lib/VM.cpp
|
@ -19,6 +19,18 @@ 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);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
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_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_IMP), G(OP_EQ), G(OP_ILT), G(OP_IGT), G(OP_ASSERT)
|
||||||
|
|
||||||
namespace roza
|
namespace roza
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
10
src/main.cpp
10
src/main.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ TEST_CASE_METHOD(LexerTest, "Lexer_keywords")
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
||||||
{
|
|
||||||
SECTION("nominal cases")
|
|
||||||
{
|
{
|
||||||
m_lexer.scan("and or not true false =>");
|
m_lexer.scan("and or not true false =>");
|
||||||
REQUIRE("AND" == get_str(0));
|
REQUIRE("AND" == get_str(0));
|
||||||
|
@ -76,11 +74,8 @@ TEST_CASE_METHOD(LexerTest, "Lexer_bool")
|
||||||
REQUIRE("IMP" == get_str(5));
|
REQUIRE("IMP" == get_str(5));
|
||||||
REQUIRE("" == get_str(6));
|
REQUIRE("" == get_str(6));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
|
TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
|
||||||
{
|
|
||||||
SECTION("nominal cases")
|
|
||||||
{
|
{
|
||||||
m_lexer.scan("== != < > <= >=");
|
m_lexer.scan("== != < > <= >=");
|
||||||
REQUIRE("EQ" == get_str(0));
|
REQUIRE("EQ" == get_str(0));
|
||||||
|
@ -91,4 +86,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_comparisons")
|
||||||
REQUIRE("GE" == get_str(5));
|
REQUIRE("GE" == get_str(5));
|
||||||
REQUIRE("" == get_str(6));
|
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,3 +100,13 @@ TEST_CASE_METHOD(ParserTest, "Parser_comparisons")
|
||||||
test_node("PROG(EQ(LE(INT[5],INT[3]),BOOL[false]))",
|
test_node("PROG(EQ(LE(INT[5],INT[3]),BOOL[false]))",
|
||||||
"5 <= 3 == 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");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue