ADD: arrays.
parent
8b5b243cab
commit
d8025d967f
|
@ -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
|
||||
|
|
|
@ -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)))
|
94
lib/core.cpp
94
lib/core.cpp
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
29
src/VM.cpp
29
src/VM.cpp
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
G(TYPE_INT), \
|
||||
G(TYPE_FUNCTION), \
|
||||
G(TYPE_REF), \
|
||||
G(TYPE_PROGRAM)
|
||||
G(TYPE_PROGRAM), \
|
||||
G(TYPE_ARRAY)
|
||||
|
||||
|
||||
namespace grino
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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] )");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue