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? 2 (^ 2))
|
||||||
(assert-eq? 8 (^ 2 3))
|
(assert-eq? 8 (^ 2 3))
|
||||||
(assert-eq? 64 (^ 2 3 2))
|
(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/Loader.hpp"
|
||||||
#include "src/Logger.hpp"
|
#include "src/Logger.hpp"
|
||||||
|
#include "src/Value.hpp"
|
||||||
|
|
||||||
GRINO_ERROR(assertion_error);
|
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)
|
extern "C" void lib_assert(grino::Loader& loader)
|
||||||
{
|
{
|
||||||
loader.add_native("assert", [](auto args){
|
loader.add_native("assert", [](auto args){
|
||||||
|
@ -198,6 +301,8 @@ extern "C" void lib(grino::Loader& loader)
|
||||||
{
|
{
|
||||||
lib_assert(loader);
|
lib_assert(loader);
|
||||||
lib_int(loader);
|
lib_int(loader);
|
||||||
|
lib_cmp(loader);
|
||||||
|
lib_bool(loader);
|
||||||
|
|
||||||
loader.add_native("dump", [](auto args){
|
loader.add_native("dump", [](auto args){
|
||||||
std::string sep;
|
std::string sep;
|
||||||
|
|
|
@ -28,6 +28,7 @@ grino_src = static_library('grino',
|
||||||
'src/VM.cpp',
|
'src/VM.cpp',
|
||||||
'src/Value.cpp',
|
'src/Value.cpp',
|
||||||
'src/Function.cpp',
|
'src/Function.cpp',
|
||||||
|
'src/StaticFunction.cpp',
|
||||||
'src/SymTable.cpp',
|
'src/SymTable.cpp',
|
||||||
'src/Loader.cpp',
|
'src/Loader.cpp',
|
||||||
])
|
])
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "src/opcodes.hpp"
|
||||||
|
#include "StaticFunction.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
|
@ -29,13 +30,24 @@ namespace grino
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_FUNCALL: {
|
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;
|
} break;
|
||||||
|
|
||||||
case NODE_BOOL: {
|
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()
|
size_t Compiler::get_local_address()
|
||||||
{
|
{
|
||||||
static size_t addr = 0;
|
static size_t addr = 0;
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace grino
|
||||||
{
|
{
|
||||||
class Program;
|
class Program;
|
||||||
class SymTable;
|
class SymTable;
|
||||||
|
class StaticFunction;
|
||||||
|
|
||||||
GRINO_ERROR(compile_error);
|
GRINO_ERROR(compile_error);
|
||||||
|
|
||||||
|
@ -22,9 +23,14 @@ namespace grino
|
||||||
void compile(std::shared_ptr<Node> node,
|
void compile(std::shared_ptr<Node> node,
|
||||||
Program& program);
|
Program& program);
|
||||||
|
|
||||||
|
void add_static_func(std::string const& name,
|
||||||
|
std::shared_ptr<StaticFunction> fun);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
SymTable& m_sym;
|
SymTable& m_sym;
|
||||||
|
std::unordered_map<std::string,
|
||||||
|
std::shared_ptr<StaticFunction>> m_statics;
|
||||||
|
|
||||||
size_t get_local_address();
|
size_t get_local_address();
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
/*explicit*/ Loader::Loader(VM& vm, SymTable& sym_table)
|
/*explicit*/ Loader::Loader(VM& vm, Compiler& compiler, SymTable& sym_table)
|
||||||
: m_vm { vm }
|
: m_vm { vm }
|
||||||
|
, m_compiler { compiler }
|
||||||
, m_sym_table { sym_table }
|
, m_sym_table { sym_table }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -44,4 +45,9 @@ namespace grino
|
||||||
m_vm.set_heap(addr, grino::Value::make_native_function(loc, native));
|
m_vm.set_heap(addr, grino::Value::make_native_function(loc, native));
|
||||||
m_sym_table.declare_object(loc, name, addr);
|
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 "commons.hpp"
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
|
#include "Compiler.hpp"
|
||||||
|
#include "StaticFunction.hpp"
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
{
|
{
|
||||||
class Loader
|
class Loader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Loader(VM& vm, SymTable& sym_table);
|
explicit Loader(VM& vm, Compiler& compiler, SymTable& sym_table);
|
||||||
virtual ~Loader();
|
virtual ~Loader();
|
||||||
|
|
||||||
void load_libraries();
|
void load_libraries();
|
||||||
void load_library(std::filesystem::path path);
|
void load_library(std::filesystem::path path);
|
||||||
|
|
||||||
void add_native(std::string const& name, native_t native);
|
void add_native(std::string const& name, native_t native);
|
||||||
|
void add_static(std::string const& name, static_fun_t fun);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VM& m_vm;
|
VM& m_vm;
|
||||||
|
Compiler& m_compiler;
|
||||||
SymTable& m_sym_table;
|
SymTable& m_sym_table;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ namespace grino
|
||||||
return m_instrs[index];
|
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,
|
size_t Program::push_instr(OpcodeType opcode,
|
||||||
std::optional<size_t> param /*=std::nullopt*/)
|
std::optional<size_t> param /*=std::nullopt*/)
|
||||||
{
|
{
|
||||||
|
@ -63,6 +69,7 @@ namespace grino
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << "\n";
|
ss << "\n";
|
||||||
|
addr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = 0;
|
addr = 0;
|
||||||
|
|
|
@ -23,6 +23,8 @@ namespace grino
|
||||||
|
|
||||||
Instr get(size_t index) const;
|
Instr get(size_t index) const;
|
||||||
|
|
||||||
|
void set_param(size_t addr, size_t param);
|
||||||
|
|
||||||
size_t push_instr(OpcodeType opcode,
|
size_t push_instr(OpcodeType opcode,
|
||||||
std::optional<size_t> param=std::nullopt);
|
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)
|
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: {
|
case OPCODE_LOAD_CONST: {
|
||||||
push(*instr.param);
|
push(*instr.param);
|
||||||
m_pc++;
|
m_pc++;
|
||||||
|
|
|
@ -37,11 +37,11 @@ void run(char** argv, bool debug_mode)
|
||||||
|
|
||||||
grino::SymTable sym_table {logger};
|
grino::SymTable sym_table {logger};
|
||||||
grino::VM vm {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();
|
loader.load_libraries();
|
||||||
|
|
||||||
grino::Compiler compiler {logger, sym_table};
|
|
||||||
grino::Program program;
|
grino::Program program;
|
||||||
compiler.compile(ast, program);
|
compiler.compile(ast, program);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
G(OPCODE_LOAD_OBJ), \
|
G(OPCODE_LOAD_OBJ), \
|
||||||
G(OPCODE_STORE_OBJ), \
|
G(OPCODE_STORE_OBJ), \
|
||||||
G(OPCODE_CALL), \
|
G(OPCODE_CALL), \
|
||||||
|
G(OPCODE_BRF), \
|
||||||
|
G(OPCODE_BR), \
|
||||||
|
G(OPCODE_NOT), \
|
||||||
G(OPCODE_RET),
|
G(OPCODE_RET),
|
||||||
|
|
||||||
namespace grino
|
namespace grino
|
||||||
|
|
Loading…
Reference in New Issue