ADD: bool arithmetic and comparison operators.

main
bog 2023-09-11 17:54:59 +02:00
parent bae09ec2f3
commit 59af9d809e
15 changed files with 273 additions and 7 deletions

19
examples/bool.gri Normal file
View File

@ -0,0 +1,19 @@
(assert-eq? false (not true))
(assert-eq? true (not false))
(assert-eq? false (not (not false)))
(assert-eq? true (and true true))
(assert-eq? false (and true false))
(assert-eq? false (and false true))
(assert-eq? false (and false false))
(assert-eq? true (and true true true true true))
(assert-eq? false (and true true true true false))
(assert-eq? true (or true true))
(assert-eq? true (or true true))
(assert-eq? true (or true true))
(assert-eq? false (or false false))
(assert-eq? false (or false false false false false))
(assert-eq? true (or false false true false false))

View File

@ -26,3 +26,22 @@
(assert-eq? 2 (^ 2))
(assert-eq? 8 (^ 2 3))
(assert-eq? 64 (^ 2 3 2))
(assert-eq? true (< 5 10))
(assert-eq? false (< 5 5))
(assert-eq? false (< 5 3))
(assert-eq? true (<= 5 10))
(assert-eq? true (<= 5 5))
(assert-eq? false (<= 5 3))
(assert-eq? true (> 15 10))
(assert-eq? false (> 15 15))
(assert-eq? false (> 15 37))
(assert-eq? true (>= 15 10))
(assert-eq? true (>= 15 15))
(assert-eq? false (>= 15 37))
(assert-eq? true (ne? 5 8))
(assert-eq? false (ne? 5 5))

View File

@ -1,5 +1,6 @@
#include "../src/Loader.hpp"
#include "src/Logger.hpp"
#include "src/Value.hpp"
GRINO_ERROR(assertion_error);
@ -150,6 +151,108 @@ extern "C" void lib_int(grino::Loader& loader)
});
}
extern "C" void lib_cmp(grino::Loader& loader)
{
loader.add_native("<", [](auto args){
int lhs = args[0]->as_int();
int rhs = args[1]->as_int();
return grino::Value::make_bool(args[0]->loc(), lhs < rhs);
});
loader.add_native("<=", [](auto args){
int lhs = args[0]->as_int();
int rhs = args[1]->as_int();
return grino::Value::make_bool(args[0]->loc(), lhs <= rhs);
});
loader.add_native(">", [](auto args){
int lhs = args[0]->as_int();
int rhs = args[1]->as_int();
return grino::Value::make_bool(args[0]->loc(), lhs > rhs);
});
loader.add_native(">=", [](auto args){
int lhs = args[0]->as_int();
int rhs = args[1]->as_int();
return grino::Value::make_bool(args[0]->loc(), lhs >= rhs);
});
loader.add_native("ne?", [](auto args){
int lhs = args[0]->as_int();
int rhs = args[1]->as_int();
return grino::Value::make_bool(args[0]->loc(), lhs != rhs);
});
}
extern "C" void lib_bool(grino::Loader& loader)
{
loader.add_native("not", [](auto args){
return grino::Value::make_bool(args[0]->loc(), !args[0]->as_bool());
});
loader.add_static("and", [](auto& compiler, auto node, auto& program){
std::vector<size_t> to_false;
for (size_t i=1; i<node->size(); i++)
{
compiler.compile(node->child(i).lock(), program);
to_false.push_back(program.size());
program.push_instr(grino::OPCODE_BRF, 0 /* to false */);
}
size_t addr = program
.push_constant(grino::Value::make_bool(node->loc(), true));
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
size_t to_end = program.size();
program.push_instr(grino::OPCODE_BR, 0 /* to end */);
for (auto a: to_false)
{
program.set_param(a, program.size());
}
addr = program
.push_constant(grino::Value::make_bool(node->loc(), false));
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
program.set_param(to_end, program.size());
});
loader.add_static("or", [](auto& compiler, auto node, auto& program){
std::vector<size_t> to_true;
for (size_t i=1; i<node->size(); i++)
{
compiler.compile(node->child(i).lock(), program);
program.push_instr(grino::OPCODE_NOT);
to_true.push_back(program.size());
program.push_instr(grino::OPCODE_BRF, 0 /* to true */);
}
size_t addr = program
.push_constant(grino::Value::make_bool(node->loc(), false));
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
size_t to_end = program.size();
program.push_instr(grino::OPCODE_BR, 0 /* to end */);
for (auto a: to_true)
{
program.set_param(a, program.size());
}
addr = program
.push_constant(grino::Value::make_bool(node->loc(), true));
program.push_instr(grino::OPCODE_LOAD_CONST, addr);
program.set_param(to_end, program.size());
});
}
extern "C" void lib_assert(grino::Loader& loader)
{
loader.add_native("assert", [](auto args){
@ -198,6 +301,8 @@ extern "C" void lib(grino::Loader& loader)
{
lib_assert(loader);
lib_int(loader);
lib_cmp(loader);
lib_bool(loader);
loader.add_native("dump", [](auto args){
std::string sep;

View File

@ -28,6 +28,7 @@ grino_src = static_library('grino',
'src/VM.cpp',
'src/Value.cpp',
'src/Function.cpp',
'src/StaticFunction.cpp',
'src/SymTable.cpp',
'src/Loader.cpp',
])

View File

@ -2,6 +2,7 @@
#include "Program.hpp"
#include "SymTable.hpp"
#include "src/opcodes.hpp"
#include "StaticFunction.hpp"
namespace grino
{
@ -29,13 +30,24 @@ namespace grino
} break;
case NODE_FUNCALL: {
std::string ident = node->child(0).lock()->repr();
for (size_t i=0; i<node->size(); i++)
if (auto itr = m_statics.find(ident);
itr != std::end(m_statics))
{
compile(node->child(i).lock(), program);
auto fun = itr->second;
fun->call(*this, node, program);
}
else
{
for (size_t i=0; i<node->size(); i++)
{
compile(node->child(i).lock(), program);
}
program.push_instr(OPCODE_CALL, node->size() - 1);
}
program.push_instr(OPCODE_CALL, node->size() - 1);
} break;
case NODE_BOOL: {
@ -94,6 +106,12 @@ namespace grino
}
}
void Compiler::add_static_func(std::string const& name,
std::shared_ptr<StaticFunction> fun)
{
m_statics[name] = fun;
}
size_t Compiler::get_local_address()
{
static size_t addr = 0;

View File

@ -10,6 +10,7 @@ namespace grino
{
class Program;
class SymTable;
class StaticFunction;
GRINO_ERROR(compile_error);
@ -22,9 +23,14 @@ namespace grino
void compile(std::shared_ptr<Node> node,
Program& program);
void add_static_func(std::string const& name,
std::shared_ptr<StaticFunction> fun);
private:
Logger& m_logger;
SymTable& m_sym;
std::unordered_map<std::string,
std::shared_ptr<StaticFunction>> m_statics;
size_t get_local_address();
};

View File

@ -5,8 +5,9 @@
namespace grino
{
/*explicit*/ Loader::Loader(VM& vm, SymTable& sym_table)
/*explicit*/ Loader::Loader(VM& vm, Compiler& compiler, SymTable& sym_table)
: m_vm { vm }
, m_compiler { compiler }
, m_sym_table { sym_table }
{
}
@ -44,4 +45,9 @@ namespace grino
m_vm.set_heap(addr, grino::Value::make_native_function(loc, native));
m_sym_table.declare_object(loc, name, addr);
}
void Loader::add_static(std::string const& name, static_fun_t fun)
{
m_compiler.add_static_func(name, std::make_shared<StaticFunction>(fun));
}
}

View File

@ -4,21 +4,26 @@
#include "commons.hpp"
#include "VM.hpp"
#include "SymTable.hpp"
#include "Compiler.hpp"
#include "StaticFunction.hpp"
namespace grino
{
class Loader
{
public:
explicit Loader(VM& vm, SymTable& sym_table);
explicit Loader(VM& vm, Compiler& compiler, SymTable& sym_table);
virtual ~Loader();
void load_libraries();
void load_library(std::filesystem::path path);
void add_native(std::string const& name, native_t native);
void add_static(std::string const& name, static_fun_t fun);
private:
VM& m_vm;
Compiler& m_compiler;
SymTable& m_sym_table;
};
}

View File

@ -17,6 +17,12 @@ namespace grino
return m_instrs[index];
}
void Program::set_param(size_t addr, size_t param)
{
assert(addr < size());
m_instrs[addr].param = param;
}
size_t Program::push_instr(OpcodeType opcode,
std::optional<size_t> param /*=std::nullopt*/)
{
@ -63,6 +69,7 @@ namespace grino
}
ss << "\n";
addr++;
}
addr = 0;

View File

@ -23,6 +23,8 @@ namespace grino
Instr get(size_t index) const;
void set_param(size_t addr, size_t param);
size_t push_instr(OpcodeType opcode,
std::optional<size_t> param=std::nullopt);

21
src/StaticFunction.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "StaticFunction.hpp"
#include "Compiler.hpp"
namespace grino
{
/*explicit*/ StaticFunction::StaticFunction(static_fun_t fun)
: m_fun { fun }
{
}
/*virtual*/ StaticFunction::~StaticFunction()
{
}
void StaticFunction::call(Compiler& compiler,
node_t node,
prog_t prog)
{
m_fun(compiler, node, prog);
}
}

29
src/StaticFunction.hpp Normal file
View File

@ -0,0 +1,29 @@
#ifndef grino_STATICFUNCTION_HPP
#define grino_STATICFUNCTION_HPP
#include "commons.hpp"
#include "Function.hpp"
#include "Node.hpp"
#include "Program.hpp"
namespace grino
{
class Compiler;
using node_t = std::shared_ptr<Node>;
using prog_t = Program&;
using static_fun_t = std::function<void (Compiler&, node_t, prog_t)>;
class StaticFunction
{
public:
explicit StaticFunction(static_fun_t fun);
virtual ~StaticFunction();
void call(Compiler& compiler, node_t node, prog_t prog);
private:
static_fun_t m_fun;
};
}
#endif

View File

@ -25,6 +25,31 @@ namespace grino
switch (instr.opcode)
{
case OPCODE_NOT: {
auto val = program.constant(pop());
push(program.push_constant(Value::make_bool(val->loc(),
!val->as_bool())));
m_pc++;
} break;
case OPCODE_BR: {
m_pc = *instr.param;
} break;
case OPCODE_BRF: {
auto val = program.constant(pop())->as_bool();
size_t addr = *instr.param;
if (!val)
{
m_pc = addr;
}
else
{
m_pc++;
}
} break;
case OPCODE_LOAD_CONST: {
push(*instr.param);
m_pc++;

View File

@ -37,11 +37,11 @@ void run(char** argv, bool debug_mode)
grino::SymTable sym_table {logger};
grino::VM vm {logger};
grino::Compiler compiler {logger, sym_table};
grino::Loader loader {vm, sym_table};
grino::Loader loader {vm, compiler, sym_table};
loader.load_libraries();
grino::Compiler compiler {logger, sym_table};
grino::Program program;
compiler.compile(ast, program);

View File

@ -12,6 +12,9 @@
G(OPCODE_LOAD_OBJ), \
G(OPCODE_STORE_OBJ), \
G(OPCODE_CALL), \
G(OPCODE_BRF), \
G(OPCODE_BR), \
G(OPCODE_NOT), \
G(OPCODE_RET),
namespace grino