From d30e42b4e8566bcf72ad836f9ba57747b727d002 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 24 Sep 2023 00:40:08 +0200 Subject: [PATCH] ADD: simple arrays. --- doc/grammar.bnf | 2 ++ examples/array.fk | 17 +++++++++ meson.build | 2 ++ src/Array.cpp | 51 +++++++++++++++++++++++++++ src/Array.hpp | 29 +++++++++++++++ src/Compiler.cpp | 31 +++++++++++++--- src/Constant.cpp | 2 ++ src/Constant.hpp | 4 ++- src/Lexer.cpp | 2 ++ src/Node.hpp | 3 +- src/Parser.cpp | 20 +++++++++++ src/Parser.hpp | 1 + src/SymEntry.hpp | 7 ++++ src/VM.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++- src/VM.hpp | 3 +- src/opcodes.hpp | 2 +- src/types.hpp | 3 +- tests/Lexer.cpp | 8 +++++ tests/Parser.cpp | 12 +++++++ 19 files changed, 279 insertions(+), 10 deletions(-) create mode 100644 examples/array.fk create mode 100644 src/Array.cpp create mode 100644 src/Array.hpp diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 427346d..8a0c378 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -8,6 +8,7 @@ EXPR ::= | VARDECL | NS | IMPORT +| ARRAY CALL ::= opar EXPR EXPR* cpar LAMBDA ::= opar rarrow opar PARAMS cpar BODY cpar PARAMS ::= ident* @@ -18,3 +19,4 @@ VARDECL ::= opar decl ident EXPR cpar NS ::= ident ns ident IMPORT ::= opar import string cpar SHORT_IMPORT ::= opar decl import ident string? cpar +ARRAY ::= osquare EXPR* csquare diff --git a/examples/array.fk b/examples/array.fk new file mode 100644 index 0000000..2c319e4 --- /dev/null +++ b/examples/array.fk @@ -0,0 +1,17 @@ +(assert= 8 ([2 6 2 8 9] 3)) +(assert= 9 ([[3 6] [9 2]] 1 0)) + +($ a ['a' [[2 true] 2.3]]) + +(assert= 'a' (a 0)) +(assert= 2 (a 1 0 0)) + +($ (second arr) + (arr 1)) + +(assert= 6 (second [2 6])) + +($ (produce) + [2 4 6]) + +(assert= 4 (second (produce))) \ No newline at end of file diff --git a/meson.build b/meson.build index d18e891..3e05de8 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,7 @@ fakir_cpp = [ 'src/Constant.cpp', 'src/NativeFunction.cpp', 'src/Lambda.cpp', + 'src/Array.cpp', 'src/NativeMacro.cpp', 'src/SymTable.cpp', 'src/SymEntry.cpp', @@ -41,6 +42,7 @@ fakir_cpp = [ ] fakir_hpp = [ + 'src/Array.hpp', 'src/Node.hpp', 'src/Loc.hpp', 'src/Lexer.hpp', diff --git a/src/Array.cpp b/src/Array.cpp new file mode 100644 index 0000000..6f6cd03 --- /dev/null +++ b/src/Array.cpp @@ -0,0 +1,51 @@ +#include "Array.hpp" +#include "Constant.hpp" + +namespace fk +{ + /*explicit*/ Array::Array() + { + } + + /*virtual*/ Array::~Array() + { + } + + void Array::push(std::shared_ptr constant) + { + m_data.push_back(constant); + } + + std::shared_ptr Array::at(size_t index) const + { + assert(index < size()); + return m_data.at(index); + } + + std::shared_ptr Array::pop() + { + assert(size() > 0); + auto val = m_data.back(); + m_data.pop_back(); + return val; + } + + std::string Array::string() const + { + std::stringstream ss; + + ss << "["; + + std::string sep; + + for (auto d: m_data) + { + ss << sep << d->string(); + sep = " "; + } + + ss << "]"; + + return ss.str(); + } +} diff --git a/src/Array.hpp b/src/Array.hpp new file mode 100644 index 0000000..8a65797 --- /dev/null +++ b/src/Array.hpp @@ -0,0 +1,29 @@ +#ifndef fk_ARRAY_HPP +#define fk_ARRAY_HPP + +#include "commons.hpp" + +namespace fk +{ + class Constant; + + class Array + { + public: + explicit Array(); + virtual ~Array(); + + size_t size() const { return m_data.size(); } + + void push(std::shared_ptr constant); + std::shared_ptr at(size_t index) const; + std::shared_ptr pop(); + + std::string string() const; + + private: + std::vector> m_data; + }; +} + +#endif diff --git a/src/Compiler.cpp b/src/Compiler.cpp index df01bb5..a1dce74 100644 --- a/src/Compiler.cpp +++ b/src/Compiler.cpp @@ -2,6 +2,7 @@ #include "Module.hpp" #include "Lambda.hpp" #include "commons.hpp" +#include "src/Node.hpp" namespace fk { @@ -85,12 +86,22 @@ namespace fk auto entry = sym()->declare_local(ident, m_addr, node->loc()) + .set_is_array(rhs->type() == NODE_ARRAY) .set_node(rhs); prog->add(OP_STORE_LOCAL, m_addr); } break; + case NODE_ARRAY: { + for (size_t i=0; isize(); i++) + { + compile_prog(node->child(i), prog); + } + + prog->add(OP_MAKE_ARRAY, node->size()); + } break; + case NODE_NS: { auto mod = node->child(0); auto var = node->child(1); @@ -157,7 +168,8 @@ namespace fk m_sym->declare_local(ident, i, node->loc()); } - m_sym->declare_local(func_name, params->size(), node->loc()); + m_sym->declare_local(func_name, params->size(), + node->loc()); Compiler compiler {m_mod, m_sym}; for (auto e: m_macros) @@ -206,19 +218,25 @@ namespace fk compile_prog(node->child(i), prog); } - - if (node->child(0)->type() == NODE_LAMBDA + if (node->child(0)->type() == NODE_ARRAY) + { + prog->add(OP_CALL_REF, node->size() - 1); + break; + } + else if (node->child(0)->type() == NODE_LAMBDA || node->child(0)->type() == NODE_CALL || node->child(0)->type() == NODE_NS) { prog->add(OP_CALL_REF, node->size() - 1); + break; } else if (node->child(0)->type() == NODE_IDENT) { if (auto entry = m_sym->find(node->child(0)->repr()); entry && entry->is_global() == false) { - if (entry->node()) + if (entry->node() + && entry->node()->child(1)->type() != NODE_ARRAY) { size_t arity = entry->node()->child(0)->size(); if (arity != node->size() - 1) @@ -236,12 +254,17 @@ namespace fk } prog->add(OP_CALL_REF, node->size() - 1); + break; } else { prog->add(OP_CALL_REF, node->size() - 1); + break; } } + std::cerr << "cannot call node '" + << node->string() << "'" << std::endl; + abort(); } } break; diff --git a/src/Constant.cpp b/src/Constant.cpp index 21e7c50..a44f259 100644 --- a/src/Constant.cpp +++ b/src/Constant.cpp @@ -30,6 +30,8 @@ namespace fk case TYPE_STRING: return std::get(m_value); case TYPE_REF: return std::to_string(std::get(m_value)); case TYPE_PROGRAM: return ""; + case TYPE_ARRAY: return std::get> + (m_value)->string(); default: { std::stringstream ss; diff --git a/src/Constant.hpp b/src/Constant.hpp index 7843985..28912a2 100644 --- a/src/Constant.hpp +++ b/src/Constant.hpp @@ -4,6 +4,7 @@ #include "commons.hpp" #include "types.hpp" #include "Loc.hpp" +#include "Array.hpp" namespace fk { @@ -16,7 +17,8 @@ namespace fk bool, std::string, size_t, - std::shared_ptr + std::shared_ptr, + std::shared_ptr >; class Constant diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 2bbf733..163a557 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -7,6 +7,8 @@ namespace fk : m_loc { loc } { std::vector> text = { + {NODE_OSQUARE, "[", false}, + {NODE_CSQUARE, "]", false}, {NODE_IMPORT, "@", false}, {NODE_DECL, "$", false}, {NODE_NS, "::", false}, diff --git a/src/Node.hpp b/src/Node.hpp index db712c1..dbcafc2 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -8,7 +8,8 @@ G(NODE_MODULE), G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), G(NODE_STRING),\ G(NODE_IDENT), G(NODE_OPAR), G(NODE_CPAR), G(NODE_CALL), G(NODE_LAMBDA),\ G(NODE_RARROW), G(NODE_PARAMS), G(NODE_BODY), G(NODE_NS), G(NODE_IMPORT),\ - G(NODE_VARDECL), G(NODE_DECL) + G(NODE_VARDECL), G(NODE_DECL), G(NODE_ARRAY), G(NODE_OSQUARE), \ + G(NODE_CSQUARE) namespace fk { diff --git a/src/Parser.cpp b/src/Parser.cpp index d27ebf7..a4e4e4d 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -50,6 +50,10 @@ namespace fk std::shared_ptr Parser::parse_expr() { + if (type_is(NODE_OSQUARE)) + { + return parse_array(); + } if (type_all({NODE_IDENT, NODE_NS})) { @@ -249,6 +253,22 @@ namespace fk return vardecl; } + std::shared_ptr Parser::parse_array() + { + consume(NODE_OSQUARE); + + auto node = make_node(NODE_ARRAY); + + while (type_isnt(NODE_CSQUARE)) + { + node->add_child(parse_expr()); + } + + consume(NODE_CSQUARE); + + return node; + } + std::shared_ptr Parser::make_node(NodeType type) { return std::make_shared(type, "", loc()); diff --git a/src/Parser.hpp b/src/Parser.hpp index abb2f2f..3c32541 100644 --- a/src/Parser.hpp +++ b/src/Parser.hpp @@ -31,6 +31,7 @@ namespace fk std::shared_ptr parse_ns(); std::shared_ptr parse_import(); std::shared_ptr parse_short_import(); + std::shared_ptr parse_array(); std::shared_ptr make_node(NodeType type); Loc loc() const; diff --git a/src/SymEntry.hpp b/src/SymEntry.hpp index d4845fe..5b8411a 100644 --- a/src/SymEntry.hpp +++ b/src/SymEntry.hpp @@ -3,6 +3,7 @@ #include "commons.hpp" #include "Loc.hpp" +#include "types.hpp" namespace fk { @@ -27,15 +28,20 @@ namespace fk std::shared_ptr node() const { return m_node; } Loc loc() const { return m_loc; } size_t arity() const { return m_arity; } + bool is_array() const { return m_is_array; } SymEntry& set_global(bool global) { m_is_global = global; return *this; } SymEntry& set_addr(addr_t addr) { m_addr = addr; return *this; } SymEntry& set_arity(size_t arity) { m_arity = arity; return *this; } + SymEntry& set_is_array(bool is_array) + { m_is_array = is_array; return *this;} + SymEntry& set_parent(std::shared_ptr parent) { m_parent = parent; return *this; } SymEntry& set_node(std::shared_ptr node) { m_node = node; return *this; } + std::string string() const; private: @@ -47,6 +53,7 @@ namespace fk std::shared_ptr m_node; Loc m_loc; size_t m_arity = 0; + bool m_is_array = false; }; } diff --git a/src/VM.cpp b/src/VM.cpp index 8cbdb05..3f19fc6 100644 --- a/src/VM.cpp +++ b/src/VM.cpp @@ -31,6 +31,69 @@ namespace fk switch (instr.opcode) { + /*case OP_DEREF: { + std::vector indexes; + + for (size_t i=0; iget_const(pop()); + int index = std::get(index_val->value()); + indexes.insert(std::begin(indexes), index); + } + + size_t ref = + std::get(frame().program + ->get_const(pop())->value()); + + std::shared_ptr val = + std::get>(load_global(ref)); + + for (size_t i=0; iat(indexes[i])->value(); + + size_t ref = std::get(ref_val); + + auto arr = + std::get>(load_global(ref)); + + val = arr; + + } + + push(frame().program->add(val->at(indexes.back()))); + + m_pc++; + } break;*/ + + case OP_MAKE_ARRAY: { + std::vector> data; + + for (size_t i=0; iget_const(pop())); + } + + auto array = std::make_shared(); + + Loc loc {""}; + + for (auto val: data) + { + loc = val->loc(); + array->push(val); + } + + addr_t addr = store_global(array); + auto ref = std::make_shared(TYPE_REF, + addr, + loc); + push(frame().program->add(ref)); + + m_pc++; + } break; + case OP_IMPORT: { auto path_val = frame().program->get_const(pop()); std::filesystem::path path = @@ -222,6 +285,7 @@ namespace fk } break; case OP_CALL_REF: { + std::vector> args; for (size_t i=0; i>(&val)) + { + std::shared_ptr val = + std::get>(load_global(ref)); + + for (size_t i=0; i(args[i]->value()); + auto ref_val = val->at(k)->value(); + + size_t ref = std::get(ref_val); + + auto arr = + std::get>(load_global(ref)); + + val = arr; + + } + + push(frame().program->add + (val->at(std::get(args.back()->value())))); + + m_pc++; + break; + } auto lambda = std::get>(load_global(ref)); - auto self = std::make_shared(TYPE_REF, static_cast(ref), ref_val->loc()); diff --git a/src/VM.hpp b/src/VM.hpp index 27cbe95..640cf03 100644 --- a/src/VM.hpp +++ b/src/VM.hpp @@ -10,7 +10,8 @@ namespace fk { using global_t = std::variant, std::shared_ptr, - std::shared_ptr + std::shared_ptr, + std::shared_ptr >; struct Frame { diff --git a/src/opcodes.hpp b/src/opcodes.hpp index ef56a68..30238f0 100644 --- a/src/opcodes.hpp +++ b/src/opcodes.hpp @@ -5,7 +5,7 @@ G(OP_LOAD_GLOBAL), G(OP_LOAD_LOCAL), G(OP_STORE_LOCAL), \ G(OP_MAKE_FUNCTION), G(OP_CALL_REF), G(OP_RET), G(OP_BNE), \ G(OP_BR), G(OP_LOAD_CLOSURE), G(OP_STORE_CLOSURE), \ - G(OP_LOAD_MOD), G(OP_IMPORT), G(OP_IMPORT_SYS) + G(OP_LOAD_MOD), G(OP_IMPORT), G(OP_IMPORT_SYS), G(OP_MAKE_ARRAY) #include "commons.hpp" diff --git a/src/types.hpp b/src/types.hpp index 9fb9354..590a837 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -4,7 +4,8 @@ #include "commons.hpp" #define TYPES(G) G(TYPE_INT), G(TYPE_FLOAT), G(TYPE_BOOL), G(TYPE_STRING), \ - G(TYPE_REF), G(TYPE_PROGRAM) + G(TYPE_REF), G(TYPE_PROGRAM), G(TYPE_ARRAY), G(TYPE_NIL), \ + G(TYPE_FUNCTION) namespace fk { diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index 9c995bb..187ca65 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -109,3 +109,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_namespace") test_next("CPAR"); test_end(); } + +TEST_CASE_METHOD(LexerTest, "Lexer_array") +{ + m_lexer.scan(" [] "); + test_next("OSQUARE"); + test_next("CSQUARE"); + test_end(); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index f767c9d..b6be2f0 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -81,3 +81,15 @@ TEST_CASE_METHOD(ParserTest, "Parser_import") test_parse("MODULE(VARDECL(IDENT[example],IMPORT(STRING['example'])))", " ($ @example )"); } + +TEST_CASE_METHOD(ParserTest, "Parser_array") +{ + test_parse("MODULE(ARRAY)", + " [] "); + + test_parse("MODULE(ARRAY(BOOL[true]))", + " [true] "); + + test_parse("MODULE(ARRAY(INT[2],STRING['bim']))", + " [ 2 'bim'] "); +}