ADD: bool arithmetic and comparison operators.
parent
bae09ec2f3
commit
59af9d809e
|
@ -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))
|
|
@ -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))
|
||||
|
|
105
lib/core.cpp
105
lib/core.cpp
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
])
|
||||
|
|
|
@ -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();
|
||||
|
||||
if (auto itr = m_statics.find(ident);
|
||||
itr != std::end(m_statics))
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
} 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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
25
src/VM.cpp
25
src/VM.cpp
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue