ADD: arrays.

main
bog 2023-09-13 07:46:33 +02:00
parent 8b5b243cab
commit d8025d967f
16 changed files with 243 additions and 3 deletions

View File

@ -8,6 +8,7 @@ EXPR ::=
| FUNCALL
| LAMBDA
| BLOCK
| ARRAY
VARDECL ::= opar decl ident EXPR cpar
FUNDECL ::= opar decl opar ident* cpar BODY cpar
FUNCALL ::= opar EXPR EXPR* cpar
@ -15,3 +16,4 @@ LAMBDA ::= opar lambda opar PARAMS cpar BODY cpar
PARAMS ::= ident*
BODY ::= EXPR*
BLOCK ::= opar colon EXPR* cpar
ARRAY ::= osquare EXPR* csquare

30
examples/array.gri Normal file
View File

@ -0,0 +1,30 @@
($ a [1 true 2])
(assert-eq? 1 (ref a 0))
(assert-eq? true (ref a 1))
(assert-eq? 2 (ref a 2))
($ b [[2 4 6] [8 10 12] [14 16 18]])
(assert-eq? 12 (ref b 1 2))
(assert-eq? true (empty? []))
(assert-eq? false (empty? [1]))
(assert-eq? 7 (head [7 3 1]))
(assert-eq? 3 (ref (tail [7 3 1]) 0))
(assert-eq? 1 (ref (tail [7 3 1]) 1))
($ (c arr)
(if (empty? arr)
0
(+ (head arr) (c (tail arr)))))
(assert-eq? 13 (c [2 4 6 1]))
($ d (cons 2 (cons 4 [6])))
(assert-eq? 2 (ref d 0))
(assert-eq? 4 (ref d 1))
(assert-eq? 6 (ref d 2))
(assert-eq? 3 (len d))
(assert-eq? 4 (len (cons 18 d)))

View File

@ -5,6 +5,99 @@
GRINO_ERROR(assertion_error);
extern "C" void lib_array(grino::Loader& loader)
{
loader.add_native("ref", [&loader](auto args){
std::vector<size_t> idxs;
for (size_t i=1; i<args.size(); i++)
{
idxs.push_back(args[i]->as_int());
}
std::function<std::shared_ptr<grino::Value>
(std::shared_ptr<grino::Value>, std::vector<size_t>)>
f = [&](std::shared_ptr<grino::Value> val, std::vector<size_t> indexes){
if (indexes.empty())
{
return val;
}
size_t index = indexes[0];
std::vector<size_t> next;
for (size_t i=1; i<indexes.size(); i++)
{
next.push_back(indexes[i]);
}
return f(loader.vm().heap(val->as_ref())->as_array()[index], next);
};
return f(args[0], idxs);
});
loader.add_native("empty?", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return grino::Value::make_bool(array_val->loc(), array.empty());
});
loader.add_native("head", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return array[0];
});
loader.add_native("tail", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
grino::val_array_t data;
for (size_t i=1; i<array.size(); i++)
{
data.push_back(array[i]);
}
auto res = grino::Value::make_array(array_val->loc(), data);
size_t addr = loader.vm().heap_size();
loader.vm().set_heap(addr, res);
return grino::Value::make_ref(array_val->loc(), addr);
});
loader.add_native("cons", [&loader](auto args){
auto ref_val = args[1];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
array.insert(std::begin(array), args[0]);
auto res = grino::Value::make_array(array_val->loc(), array);
size_t addr = loader.vm().heap_size();
loader.vm().set_heap(addr, res);
return grino::Value::make_ref(array_val->loc(), addr);
});
loader.add_native("len", [&loader](auto args){
auto ref_val = args[0];
size_t ref = ref_val->as_ref();
auto array_val = loader.vm().heap(ref);
auto& array = array_val->as_array();
return grino::Value::make_int(array_val->loc(), array.size());
});
}
extern "C" void lib_flow_control(grino::Loader& loader)
{
loader.add_static("if", [](auto& compiler, auto node, auto& prog, auto& sym) {
@ -330,6 +423,7 @@ extern "C" void lib(grino::Loader& loader)
lib_cmp(loader);
lib_bool(loader);
lib_flow_control(loader);
lib_array(loader);
loader.add_native("dump", [](auto args){
std::string sep;

View File

@ -128,6 +128,15 @@ namespace grino
program.push_constant(value));
} break;
case NODE_ARRAY: {
for (size_t i=0; i<node->size(); i++)
{
compile(node->child(i).lock(), program, sym);
}
program.push_instr(OPCODE_MK_ARRAY, node->size());
} break;
case NODE_INT: {
std::string repr = node->repr();
auto value = Value::make_int(node->loc(), std::stoi(repr));

View File

@ -8,6 +8,8 @@ namespace grino
, m_loc {source_path, 1}
{
add_text(NODE_COLON, ":", false);
add_text(NODE_OSQUARE, "[", false);
add_text(NODE_CSQUARE, "]", false);
add_text(NODE_OPAR, "(", false);
add_text(NODE_CPAR, ")", false);
add_text(NODE_DECL, "$", false);

View File

@ -15,6 +15,8 @@ namespace grino
explicit Loader(VM& vm, Compiler& compiler, SymTable& sym_table);
virtual ~Loader();
VM& vm() const { return m_vm; }
void load_libraries();
void load_library(std::filesystem::path path);

View File

@ -18,7 +18,10 @@
G(NODE_PARAMS), \
G(NODE_BODY), \
G(NODE_COLON), \
G(NODE_BLOCK)
G(NODE_OSQUARE), \
G(NODE_CSQUARE), \
G(NODE_BLOCK), \
G(NODE_ARRAY)
namespace grino
{

View File

@ -118,6 +118,11 @@ namespace grino
std::shared_ptr<Node> Parser::parse_expr()
{
if (type_is(NODE_OSQUARE))
{
return parse_array();
}
if (type_is({NODE_OPAR, NODE_COLON}))
{
return parse_block();
@ -272,4 +277,19 @@ namespace grino
return node;
}
std::shared_ptr<Node> Parser::parse_array()
{
auto node = make_node(NODE_ARRAY);
consume(NODE_OSQUARE);
while (!type_is(NODE_CSQUARE))
{
node->add_child(parse_expr());
}
consume(NODE_CSQUARE);
return node;
}
}

View File

@ -41,6 +41,7 @@ namespace grino
std::shared_ptr<Node> parse_params();
std::shared_ptr<Node> parse_body();
std::shared_ptr<Node> parse_block();
std::shared_ptr<Node> parse_array();
};
}

View File

@ -1,4 +1,5 @@
#include "VM.hpp"
#include "src/Value.hpp"
#include "src/opcodes.hpp"
#include <optional>
@ -31,6 +32,34 @@ namespace grino
switch (instr.opcode)
{
case OPCODE_MK_ARRAY: {
size_t const N = *instr.param;
val_array_t array;
for (size_t i=0; i<N; i++)
{
array.insert(std::begin(array), program().constant(pop()));
}
Loc loc {"???", 0};
if (N > 0)
{
loc = array[0]->loc();
}
auto array_val = Value::make_array(loc, array);
size_t addr = heap_size();
set_heap(addr, array_val);
auto ref = Value::make_ref(loc, addr);
push(program().push_constant(ref));
m_pc++;
} break;
case OPCODE_MK_FUN: {
auto prog_val = program().constant(pop());
auto prog = prog_val->as_program();

View File

@ -86,6 +86,15 @@ namespace grino
}
}
/*static*/
std::shared_ptr<Value> Value::make_array(Loc const& loc,
val_array_t val)
{
auto value = std::make_shared<Value>(loc);
value->m_type = TYPE_ARRAY;
value->m_array_val = val;
return value;
}
std::shared_ptr<Program> Value::as_program() const
{
@ -102,6 +111,19 @@ namespace grino
case TYPE_FUNCTION: return "<function>";
case TYPE_REF: return "&" + std::to_string(*m_ref_val);
case TYPE_PROGRAM: return "<program>";
case TYPE_ARRAY: {
std::stringstream ss;
ss << "[";
std::string sep;
for (auto child: *m_array_val)
{
ss << sep << child->string();
sep = " ";
}
ss << "]";
return ss.str();
} break;
default:
std::cerr << "cannot stringify value "
<< TypeTypeStr[m_type] << std::endl;

View File

@ -10,6 +10,8 @@ namespace grino
{
class Program;
using val_array_t = std::vector<std::shared_ptr<Value>>;
class Value
{
public:
@ -31,6 +33,9 @@ namespace grino
static std::shared_ptr<Value> make_copy(Loc const& loc,
std::shared_ptr<Value> val);
static std::shared_ptr<Value> make_array(Loc const& loc,
val_array_t val);
explicit Value(Loc const& loc);
virtual ~Value() = default;
@ -41,6 +46,8 @@ namespace grino
std::shared_ptr<Function> as_function() const { return m_function_val; }
size_t as_ref() const { return *m_ref_val; }
std::shared_ptr<Program> as_program() const;
val_array_t& as_array() { return *m_array_val; }
val_array_t const& as_array() const { return *m_array_val; }
std::string string() const;
bool equals(Value const& other) const;
@ -53,6 +60,7 @@ namespace grino
std::shared_ptr<Function> m_function_val;
std::shared_ptr<Program> m_program_val;
std::optional<size_t> m_ref_val;
std::optional<val_array_t> m_array_val;
};
}

View File

@ -16,7 +16,8 @@
G(OPCODE_BR), \
G(OPCODE_NOT), \
G(OPCODE_RET), \
G(OPCODE_MK_FUN),
G(OPCODE_MK_FUN), \
G(OPCODE_MK_ARRAY),
namespace grino
{

View File

@ -9,7 +9,8 @@
G(TYPE_INT), \
G(TYPE_FUNCTION), \
G(TYPE_REF), \
G(TYPE_PROGRAM)
G(TYPE_PROGRAM), \
G(TYPE_ARRAY)
namespace grino

View File

@ -108,3 +108,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_block")
test_next(lexer, "COLON");
test_end(lexer);
}
TEST_CASE_METHOD(LexerTest, "Lexer_array")
{
grino::Lexer lexer {m_logger, "tests/lexer"};
lexer.scan(" [] ");
test_next(lexer, "OSQUARE");
test_next(lexer, "CSQUARE");
test_end(lexer);
}

View File

@ -87,3 +87,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_block")
test_parse("MODULE(BLOCK(INT[1],BOOL[true],IDENT[salut]))",
"(: 1 true salut )");
}
TEST_CASE_METHOD(ParserTest, "Parser_array")
{
test_parse("MODULE(BLOCK(ARRAY(INT[1],BOOL[true],IDENT[salut])))",
"(: [1 true salut] )");
}