ADD: import local modules.

main
bog 2023-09-13 21:11:36 +02:00
parent 25bd1f28f6
commit 078877aa26
23 changed files with 373 additions and 8 deletions

View File

@ -11,6 +11,9 @@ EXPR ::=
| LAMBDA | LAMBDA
| BLOCK | BLOCK
| ARRAY | ARRAY
| IMPORT
| SHORT_IMPORT
| NS
VARDECL ::= opar decl ident EXPR cpar VARDECL ::= opar decl ident EXPR cpar
FUNDECL ::= opar decl opar ident* cpar BODY cpar FUNDECL ::= opar decl opar ident* cpar BODY cpar
FUNCALL ::= opar EXPR EXPR* cpar FUNCALL ::= opar EXPR EXPR* cpar
@ -19,3 +22,6 @@ PARAMS ::= ident*
BODY ::= EXPR* BODY ::= EXPR*
BLOCK ::= opar colon EXPR* cpar BLOCK ::= opar colon EXPR* cpar
ARRAY ::= osquare EXPR* csquare ARRAY ::= osquare EXPR* csquare
IMPORT ::= opar import string cpar
SHORT_IMPORT ::= opar decl import ident string cpar
NS ::= ident ns ident

4
examples/mod.gri Normal file
View File

@ -0,0 +1,4 @@
($ @m './mod2.gri')
(assert= 32 (m::twice 16))
(assert= 3.14159 m::pi)

2
examples/mod2.gri Normal file
View File

@ -0,0 +1,2 @@
($ (twice n) (* n 2))
($ pi 3.14159)

View File

@ -32,6 +32,7 @@ grino_src = static_library('grino',
'src/SymTable.cpp', 'src/SymTable.cpp',
'src/Loader.cpp', 'src/Loader.cpp',
'src/Addr.cpp', 'src/Addr.cpp',
'src/Module.cpp',
]) ])
grino_dep = declare_dependency(link_with: grino_src) grino_dep = declare_dependency(link_with: grino_src)

View File

@ -1,5 +1,6 @@
#include "Compiler.hpp" #include "Compiler.hpp"
#include "Program.hpp" #include "Program.hpp"
#include "Module.hpp"
#include "SymTable.hpp" #include "SymTable.hpp"
#include "src/opcodes.hpp" #include "src/opcodes.hpp"
#include "StaticFunction.hpp" #include "StaticFunction.hpp"
@ -31,6 +32,25 @@ namespace grino
} }
} break; } break;
case NODE_IMPORT: {
std::string name = node->child(0).lock()->repr();
name = name.substr(1, name.size() - 2);
program.push_value(Value::make_string(node->loc(), name));
program.push_instr(OPCODE_MK_MOD);
} break;
case NODE_NS: {
auto mod = node->child(0).lock();
auto var = node->child(1).lock()->repr();
compile(mod, program, sym);
program.push_value(Value::make_string(node->loc(), var));
program.push_instr(OPCODE_LOAD_NS);
} break;
case NODE_BODY: { case NODE_BODY: {
for (size_t i=0; i<node->size(); i++) for (size_t i=0; i<node->size(); i++)
{ {

View File

@ -7,6 +7,8 @@ namespace grino
: m_logger { logger } : m_logger { logger }
, m_loc {source_path, 1} , m_loc {source_path, 1}
{ {
add_text(NODE_NS, "::", false);
add_text(NODE_IMPORT, "@", false);
add_text(NODE_COLON, ":", false); add_text(NODE_COLON, ":", false);
add_text(NODE_OSQUARE, "[", false); add_text(NODE_OSQUARE, "[", false);
add_text(NODE_CSQUARE, "]", false); add_text(NODE_CSQUARE, "]", false);

View File

@ -2,6 +2,8 @@
#include "Function.hpp" #include "Function.hpp"
#include "src/config.in.hpp" #include "src/config.in.hpp"
#include <dlfcn.h> #include <dlfcn.h>
#include "Lexer.hpp"
#include "Parser.hpp"
namespace grino namespace grino
{ {
@ -16,6 +18,51 @@ namespace grino
{ {
} }
std::vector<std::filesystem::path>
Loader::dependencies(std::shared_ptr<Node> node)
{
std::vector<std::filesystem::path> deps;
std::function<void(std::shared_ptr<Node>)>
f = [&](std::shared_ptr<Node> n){
if (n->type() == NODE_IMPORT)
{
std::string str = n->child(0).lock()->repr();
deps.push_back(str.substr(1, str.size() - 2));
}
else
{
for (size_t i=0; i<n->size(); i++)
{
f(n->child(i).lock());
}
}
};
f(node);
return deps;
}
std::shared_ptr<Node>
Loader::user_module(std::filesystem::path path)
{
std::string source;
{
std::ifstream file { path };
assert(file);
std::string line;
while (std::getline(file, line))
{ source += line + (file.eof() ? "" : "\n"); }
}
Logger logger;
Lexer lexer {logger, path};
Parser parser {logger, lexer};
return parser.parse(source);
}
void Loader::load_libraries() void Loader::load_libraries()
{ {
for (auto entry: std::filesystem::directory_iterator(GRINO_LIBDIR)) for (auto entry: std::filesystem::directory_iterator(GRINO_LIBDIR))

View File

@ -17,6 +17,11 @@ namespace grino
VM& vm() const { return m_vm; } VM& vm() const { return m_vm; }
std::vector<std::filesystem::path>
dependencies(std::shared_ptr<Node> node);
std::shared_ptr<Node> user_module(std::filesystem::path path);
void load_libraries(); void load_libraries();
void load_library(std::filesystem::path path); void load_library(std::filesystem::path path);

64
src/Module.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "Module.hpp"
#include "Loader.hpp"
#include "Lexer.hpp"
#include "Parser.hpp"
#include "Compiler.hpp"
namespace grino
{
/*explicit*/ Module::Module(std::filesystem::path path,
std::string const& name /*= "" */)
: m_path { path }
, m_name { name == "" ? m_path.filename().stem().string() : name }
, m_program { std::make_shared<Program>()}
, m_sym_table { std::make_shared<SymTable>(m_logger)}
, m_vm { std::make_shared<VM>(m_logger, *m_program)}
{
}
/*virtual*/ Module::~Module()
{
}
void Module::load()
{
std::string source;
{
std::ifstream file { m_path };
assert(file);
std::string line;
while (std::getline(file, line))
{ source += line + (file.eof() ? "" : "\n"); }
}
Lexer lexer {m_logger, m_path};
Parser parser {m_logger, lexer};
auto ast = parser.parse(source);
Addr addr;
Compiler compiler {m_logger, addr};
m_vm = std::make_shared<VM>(m_logger, *m_program);
Loader loader {*m_vm, compiler, *m_sym_table};
loader.load_libraries();
compiler.compile(ast, *m_program, *m_sym_table);
m_vm->run();
}
std::shared_ptr<Value> Module::find(std::string const& name)
{
auto entry = m_sym_table->find_no_scope(name);
assert(entry);
assert(entry->is_object == false);
return m_vm->local(entry->addr);
}
std::shared_ptr<Value> Module::from_heap(size_t addr)
{
return m_vm->heap(addr);
}
}

33
src/Module.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef grino_MODULE_HPP
#define grino_MODULE_HPP
#include "commons.hpp"
#include "Program.hpp"
#include "SymTable.hpp"
#include "VM.hpp"
namespace grino
{
class Module
{
public:
explicit Module(std::filesystem::path path, std::string const& name="");
virtual ~Module();
std::string name() const { return m_name; }
void load();
std::shared_ptr<Value> find(std::string const& name);
std::shared_ptr<Value> from_heap(size_t addr);
private:
std::filesystem::path m_path;
std::string m_name;
Logger m_logger;
std::shared_ptr<Program> m_program;
std::shared_ptr<SymTable> m_sym_table;
std::shared_ptr<VM> m_vm;
};
}
#endif

View File

@ -23,7 +23,9 @@
G(NODE_BLOCK), \ G(NODE_BLOCK), \
G(NODE_ARRAY), \ G(NODE_ARRAY), \
G(NODE_FLOAT), \ G(NODE_FLOAT), \
G(NODE_STRING) G(NODE_STRING), \
G(NODE_IMPORT), \
G(NODE_NS)
namespace grino namespace grino
{ {

View File

@ -118,11 +118,27 @@ namespace grino
std::shared_ptr<Node> Parser::parse_expr() std::shared_ptr<Node> Parser::parse_expr()
{ {
if (type_is({NODE_IDENT, NODE_NS}))
{
return parse_ns();
}
if (type_is(NODE_OSQUARE)) if (type_is(NODE_OSQUARE))
{ {
return parse_array(); return parse_array();
} }
if (type_is({NODE_OPAR, NODE_DECL, NODE_IMPORT}))
{
return parse_short_import();
}
if (type_is({NODE_OPAR, NODE_IMPORT}))
{
return parse_import();
}
if (type_is({NODE_OPAR, NODE_COLON})) if (type_is({NODE_OPAR, NODE_COLON}))
{ {
return parse_block(); return parse_block();
@ -294,4 +310,42 @@ namespace grino
return node; return node;
} }
std::shared_ptr<Node> Parser::parse_import()
{
consume(NODE_OPAR);
auto node = consume(NODE_IMPORT);
node->add_child(consume(NODE_STRING));
consume(NODE_CPAR);
return node;
}
std::shared_ptr<Node> Parser::parse_ns()
{
auto node = make_node(NODE_NS);
node->add_child(consume(NODE_IDENT));
consume(NODE_NS);
node->add_child(consume(NODE_IDENT));
return node;
}
std::shared_ptr<Node> Parser::parse_short_import()
{
consume(NODE_OPAR);
consume(NODE_DECL);
consume(NODE_IMPORT);
auto ident = consume(NODE_IDENT);
auto val = consume(NODE_STRING);
consume(NODE_CPAR);
auto node = make_node(NODE_VARDECL);
node->add_child(ident);
auto imp = make_node(NODE_IMPORT);
imp->add_child(val);
node->add_child(imp);
return node;
}
} }

View File

@ -42,6 +42,9 @@ namespace grino
std::shared_ptr<Node> parse_body(); std::shared_ptr<Node> parse_body();
std::shared_ptr<Node> parse_block(); std::shared_ptr<Node> parse_block();
std::shared_ptr<Node> parse_array(); std::shared_ptr<Node> parse_array();
std::shared_ptr<Node> parse_import();
std::shared_ptr<Node> parse_short_import();
std::shared_ptr<Node> parse_ns();
}; };
} }

View File

@ -57,6 +57,22 @@ namespace grino
return entry; return entry;
} }
std::optional<SymEntry>
SymTable::find_no_scope(std::string const& name)
{
std::optional<SymEntry> entry;
for (size_t i=0; i<m_entries.size(); i++)
{
if (m_entries[i].name == name)
{
entry = m_entries[i];
}
}
return entry;
}
void SymTable::purge(size_t scope) void SymTable::purge(size_t scope)
{ {
auto itr = std::remove_if(std::begin(m_entries), auto itr = std::remove_if(std::begin(m_entries),

View File

@ -28,6 +28,7 @@ namespace grino
size_t scope); size_t scope);
std::optional<SymEntry> find(std::string const& name, size_t scope); std::optional<SymEntry> find(std::string const& name, size_t scope);
std::optional<SymEntry> find_no_scope(std::string const& name);
void purge(size_t scope); void purge(size_t scope);

View File

@ -1,5 +1,6 @@
#include "VM.hpp" #include "VM.hpp"
#include "src/Value.hpp" #include "src/Value.hpp"
#include "Module.hpp"
#include "src/opcodes.hpp" #include "src/opcodes.hpp"
#include <optional> #include <optional>
@ -32,6 +33,45 @@ namespace grino
switch (instr.opcode) switch (instr.opcode)
{ {
case OPCODE_MK_MOD: {
auto path = std::filesystem::path(program()
.constant(pop())
->as_string());
auto mod = std::make_shared<Module>(path);
mod->load();
size_t addr = heap_size();
Loc loc {"???", 0};
set_heap(addr, Value::make_module(loc, mod));
auto ref = Value::make_ref(loc, addr);
push(program().push_constant(ref));
m_pc++;
} break;
case OPCODE_LOAD_NS: {
std::string var = program().constant(pop())->as_string();
size_t ref_val = program().constant(pop())->as_ref();
auto mod = heap(ref_val);
auto val = mod->as_module()->find(var);
if (val->type() == TYPE_REF)
{
size_t heap_addr = val->as_ref();
auto heap_val = mod->as_module()->from_heap(heap_addr);
size_t addr = heap_size();
set_heap(addr, heap_val);
val = Value::make_ref(heap_val->loc(), addr);
}
push(program().push_constant(val));
m_pc++;
} break;
case OPCODE_MK_ARRAY: { case OPCODE_MK_ARRAY: {
size_t const N = *instr.param; size_t const N = *instr.param;

View File

@ -1,6 +1,7 @@
#include "Value.hpp" #include "Value.hpp"
#include "Program.hpp" #include "Program.hpp"
#include "src/types.hpp" #include "src/types.hpp"
#include "Module.hpp"
namespace grino namespace grino
{ {
@ -84,6 +85,10 @@ namespace grino
return Value::make_int(loc, val->as_int()); return Value::make_int(loc, val->as_int());
} break; } break;
case TYPE_STRING: {
return Value::make_string(loc, val->as_string());
} break;
case TYPE_REF: { case TYPE_REF: {
return Value::make_ref(loc, val->as_ref()); return Value::make_ref(loc, val->as_ref());
} break; } break;
@ -115,11 +120,26 @@ namespace grino
return value; return value;
} }
/*static*/
std::shared_ptr<Value> Value::make_module(Loc const& loc,
std::shared_ptr<Module> val)
{
auto value = std::make_shared<Value>(loc);
value->m_type = TYPE_MODULE;
value->m_module_val = val;
return value;
}
std::shared_ptr<Program> Value::as_program() const std::shared_ptr<Program> Value::as_program() const
{ {
return m_program_val; return m_program_val;
} }
std::shared_ptr<Module> Value::as_module() const
{
return m_module_val;
}
std::string Value::string() const std::string Value::string() const
{ {
switch (m_type) switch (m_type)
@ -132,6 +152,7 @@ namespace grino
case TYPE_FUNCTION: return "<function>"; case TYPE_FUNCTION: return "<function>";
case TYPE_REF: return "&" + std::to_string(*m_ref_val); case TYPE_REF: return "&" + std::to_string(*m_ref_val);
case TYPE_PROGRAM: return "<program>"; case TYPE_PROGRAM: return "<program>";
case TYPE_MODULE: return "<module " + m_module_val->name() + ">";
case TYPE_ARRAY: { case TYPE_ARRAY: {
std::stringstream ss; std::stringstream ss;
ss << "["; ss << "[";
@ -166,6 +187,7 @@ namespace grino
return std::fabs(*m_float_val - *other.m_float_val) < FLOAT_APPROX; return std::fabs(*m_float_val - *other.m_float_val) < FLOAT_APPROX;
case TYPE_REF: return *m_ref_val == *other.m_ref_val; case TYPE_REF: return *m_ref_val == *other.m_ref_val;
case TYPE_PROGRAM: return false; case TYPE_PROGRAM: return false;
case TYPE_MODULE: return false;
default: default:
std::cerr << "cannot compare equality with value " std::cerr << "cannot compare equality with value "

View File

@ -9,6 +9,7 @@
namespace grino namespace grino
{ {
class Program; class Program;
class Module;
using val_array_t = std::vector<std::shared_ptr<Value>>; using val_array_t = std::vector<std::shared_ptr<Value>>;
@ -40,6 +41,9 @@ namespace grino
static std::shared_ptr<Value> make_string(Loc const& loc, static std::shared_ptr<Value> make_string(Loc const& loc,
std::string const& val); std::string const& val);
static std::shared_ptr<Value> make_module(Loc const& loc,
std::shared_ptr<Module> val);
explicit Value(Loc const& loc); explicit Value(Loc const& loc);
virtual ~Value() = default; virtual ~Value() = default;
@ -54,6 +58,7 @@ namespace grino
val_array_t& as_array() { return *m_array_val; } val_array_t& as_array() { return *m_array_val; }
val_array_t const& as_array() const { return *m_array_val; } val_array_t const& as_array() const { return *m_array_val; }
std::string const& as_string() const { return *m_string_val; } std::string const& as_string() const { return *m_string_val; }
std::shared_ptr<Module> as_module() const;
std::string string() const; std::string string() const;
bool equals(Value const& other) const; bool equals(Value const& other) const;
@ -69,6 +74,7 @@ namespace grino
std::optional<size_t> m_ref_val; std::optional<size_t> m_ref_val;
std::optional<val_array_t> m_array_val; std::optional<val_array_t> m_array_val;
std::optional<std::string> m_string_val; std::optional<std::string> m_string_val;
std::shared_ptr<Module> m_module_val;
}; };
} }

View File

@ -12,11 +12,18 @@
#include "Loader.hpp" #include "Loader.hpp"
#include "Addr.hpp" #include "Addr.hpp"
void run(char** argv, bool debug_mode)
void run(char* const source_name, bool debug_mode)
{ {
std::string source; std::string source;
{ {
std::ifstream file { argv[optind] }; if (!std::filesystem::exists(source_name))
{
std::cerr << "file " << source_name << " doesnt exists" << std::endl;
abort();
}
std::ifstream file { source_name };
assert(file); assert(file);
std::string line; std::string line;
@ -25,7 +32,7 @@ void run(char** argv, bool debug_mode)
} }
grino::Logger logger; grino::Logger logger;
grino::Lexer lexer {logger, argv[optind]}; grino::Lexer lexer {logger, source_name};
grino::Parser parser {logger, lexer}; grino::Parser parser {logger, lexer};
auto ast = parser.parse(source); auto ast = parser.parse(source);
@ -46,6 +53,11 @@ void run(char** argv, bool debug_mode)
grino::Loader loader {vm, compiler, sym_table}; grino::Loader loader {vm, compiler, sym_table};
loader.load_libraries(); loader.load_libraries();
for (auto dep: loader.dependencies(ast))
{
// TODO: import them
}
compiler.compile(ast, program, sym_table); compiler.compile(ast, program, sym_table);
if (debug_mode) if (debug_mode)
@ -108,13 +120,13 @@ int main(int argc, char** argv)
{ {
if (debug_mode) if (debug_mode)
{ {
run(argv, debug_mode); run(argv[optind], debug_mode);
} }
else else
{ {
try try
{ {
run(argv, debug_mode); run(argv[optind], debug_mode);
} }
catch(std::exception const& err) catch(std::exception const& err)
{ {

View File

@ -17,7 +17,9 @@
G(OPCODE_NOT), \ G(OPCODE_NOT), \
G(OPCODE_RET), \ G(OPCODE_RET), \
G(OPCODE_MK_FUN), \ G(OPCODE_MK_FUN), \
G(OPCODE_MK_ARRAY), G(OPCODE_MK_ARRAY), \
G(OPCODE_MK_MOD), \
G(OPCODE_LOAD_NS),
namespace grino namespace grino
{ {

View File

@ -12,7 +12,8 @@
G(TYPE_PROGRAM), \ G(TYPE_PROGRAM), \
G(TYPE_FLOAT), \ G(TYPE_FLOAT), \
G(TYPE_ARRAY), \ G(TYPE_ARRAY), \
G(TYPE_STRING) G(TYPE_STRING), \
G(TYPE_MODULE)
namespace grino namespace grino

View File

@ -129,3 +129,13 @@ TEST_CASE_METHOD(LexerTest, "Lexer_strings")
test_next(lexer, "STRING[''bim'']"); test_next(lexer, "STRING[''bim'']");
test_end(lexer); test_end(lexer);
} }
TEST_CASE_METHOD(LexerTest, "Lexer_import")
{
grino::Lexer lexer {m_logger, "tests/lexer"};
lexer.scan(" @ :: ");
test_next(lexer, "IMPORT");
test_next(lexer, "NS");
test_end(lexer);
}

View File

@ -105,3 +105,15 @@ TEST_CASE_METHOD(ParserTest, "Parser_string")
test_parse("MODULE(BLOCK(ARRAY(STRING['bim !'],FLOAT[28.5],IDENT[salut])))", test_parse("MODULE(BLOCK(ARRAY(STRING['bim !'],FLOAT[28.5],IDENT[salut])))",
"(: ['bim !' 28.5 salut] )"); "(: ['bim !' 28.5 salut] )");
} }
TEST_CASE_METHOD(ParserTest, "Parser_import")
{
test_parse("MODULE(IMPORT(STRING['./salut']))",
"(@ './salut')");
test_parse("MODULE(NS(IDENT[hello],IDENT[world]))",
" hello::world ");
test_parse("MODULE(VARDECL(IDENT[bim],IMPORT(STRING['hello'])))",
"($ @bim 'hello')");
}