ADD: import modules.
parent
5d975eafdf
commit
6df8167669
|
@ -5,9 +5,16 @@ EXPR ::=
|
||||||
| CALL
|
| CALL
|
||||||
| LAMBDA
|
| LAMBDA
|
||||||
| FUNDECL
|
| FUNDECL
|
||||||
|
| VARDECL
|
||||||
|
| NS
|
||||||
|
| IMPORT
|
||||||
CALL ::= opar EXPR EXPR* cpar
|
CALL ::= opar EXPR EXPR* cpar
|
||||||
LAMBDA ::= opar rarrow opar PARAMS cpar BODY cpar
|
LAMBDA ::= opar rarrow opar PARAMS cpar BODY cpar
|
||||||
PARAMS ::= ident*
|
PARAMS ::= ident*
|
||||||
BODY ::= EXPR*
|
BODY ::= EXPR*
|
||||||
FUNDECL ::=
|
FUNDECL ::=
|
||||||
| opar ident opar ident PARAMS cpar BODY cpar
|
| opar decl opar ident PARAMS cpar BODY cpar
|
||||||
|
VARDECL ::= opar decl ident EXPR cpar
|
||||||
|
NS ::= ident ns ident
|
||||||
|
IMPORT ::= opar import string cpar
|
||||||
|
SHORT_IMPORT ::= opar decl import ident string? cpar
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
($ a (@ './mod2'))
|
||||||
|
|
||||||
|
(assert= 42 a::var)
|
||||||
|
(assert= 6 (a::fun 3))
|
|
@ -0,0 +1,2 @@
|
||||||
|
($ var 42)
|
||||||
|
($ (fun x) (* 2 x))
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
namespace fkstd
|
namespace fkstd
|
||||||
{
|
{
|
||||||
STDRET set(Loc loc, Module& mod, STDARGS args);
|
|
||||||
|
|
||||||
STDRET assert_eq(Loc loc, Module& mod, STDARGS args);
|
STDRET assert_eq(Loc loc, Module& mod, STDARGS args);
|
||||||
STDRET println(Loc loc, Module& mod, STDARGS args);
|
STDRET println(Loc loc, Module& mod, STDARGS args);
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
#include "fun.hpp"
|
#include "fun.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
|
||||||
Module* _module;
|
|
||||||
|
|
||||||
extern "C" void lib(Module& mod)
|
extern "C" void lib(Module& mod)
|
||||||
{
|
{
|
||||||
_module = &mod;
|
|
||||||
mod.register_function("assert=", fkstd::assert_eq);
|
mod.register_function("assert=", fkstd::assert_eq);
|
||||||
mod.register_function("println", fkstd::println);
|
mod.register_function("println", fkstd::println);
|
||||||
mod.register_function("+", fkstd::add_int);
|
mod.register_function("+", fkstd::add_int);
|
||||||
|
@ -25,6 +22,5 @@ extern "C" void lib(Module& mod)
|
||||||
mod.register_macro("!", fkstd::set_addr);
|
mod.register_macro("!", fkstd::set_addr);
|
||||||
mod.register_macro("assert-static-fail", fkstd::assert_static_fail);
|
mod.register_macro("assert-static-fail", fkstd::assert_static_fail);
|
||||||
mod.register_macro(":", fkstd::block);
|
mod.register_macro(":", fkstd::block);
|
||||||
mod.register_macro("$", fkstd::decl);
|
|
||||||
mod.register_macro("if", fkstd::if_macro);
|
mod.register_macro("if", fkstd::if_macro);
|
||||||
}
|
}
|
||||||
|
|
114
src/Compiler.cpp
114
src/Compiler.cpp
|
@ -1,10 +1,14 @@
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
|
#include "Module.hpp"
|
||||||
#include "Lambda.hpp"
|
#include "Lambda.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
namespace fk
|
namespace fk
|
||||||
{
|
{
|
||||||
/*explicit*/ Compiler::Compiler(std::shared_ptr<SymTable> sym)
|
/*explicit*/ Compiler::Compiler(Module& mod,
|
||||||
: m_sym { sym }
|
std::shared_ptr<SymTable> sym)
|
||||||
|
: m_mod { mod }
|
||||||
|
, m_sym { sym }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +22,24 @@ namespace fk
|
||||||
m_macros[name] = macro;
|
m_macros[name] = macro;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<NativeMacro> Compiler::get_macro(std::string const& name)
|
||||||
|
{
|
||||||
|
assert(m_macros.find(name) != std::end(m_macros));
|
||||||
|
return m_macros[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compiler::has_macro(std::string const& name) const
|
||||||
|
{
|
||||||
|
return m_macros.find(name) != std::end(m_macros);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<NativeMacro>>
|
||||||
|
Compiler::macros()
|
||||||
|
{
|
||||||
|
return m_macros;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<Program> Compiler::compile(std::shared_ptr<Node> node)
|
std::shared_ptr<Program> Compiler::compile(std::shared_ptr<Node> node)
|
||||||
{
|
{
|
||||||
auto prog = std::make_shared<Program>();
|
auto prog = std::make_shared<Program>();
|
||||||
|
@ -50,6 +72,73 @@ namespace fk
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_VARDECL: {
|
||||||
|
m_addr++;
|
||||||
|
|
||||||
|
std::string ident = node->child(0)->repr();
|
||||||
|
auto rhs = node->child(1);
|
||||||
|
|
||||||
|
push_decl(ident);
|
||||||
|
compile_prog(rhs, prog);
|
||||||
|
pop_decl();
|
||||||
|
|
||||||
|
auto entry = sym()->declare_local(ident,
|
||||||
|
m_addr,
|
||||||
|
node->loc())
|
||||||
|
.set_node(rhs);
|
||||||
|
|
||||||
|
prog->add(OP_STORE_LOCAL, m_addr);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_NS: {
|
||||||
|
auto mod = node->child(0);
|
||||||
|
auto var = node->child(1);
|
||||||
|
|
||||||
|
if (has_macro(var->repr()))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
prog->load_const(std::make_shared<Constant>(TYPE_STRING,
|
||||||
|
var->repr(),
|
||||||
|
node->loc()));
|
||||||
|
|
||||||
|
compile_prog(mod, prog);
|
||||||
|
|
||||||
|
prog->add(OP_LOAD_MOD);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case NODE_IMPORT: {
|
||||||
|
std::string val = node->child(0)->repr();
|
||||||
|
|
||||||
|
std::string path_str = val.substr(1, val.size() - 2);
|
||||||
|
std::filesystem::path path = path_str;
|
||||||
|
|
||||||
|
if (path_str[0] == '.')
|
||||||
|
{
|
||||||
|
if (!path.has_extension())
|
||||||
|
{
|
||||||
|
path += ".fk";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = std::make_shared<Constant>
|
||||||
|
(TYPE_STRING, path.string(), node->loc());
|
||||||
|
prog->load_const(res);
|
||||||
|
prog->add(OP_IMPORT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto res = std::make_shared<Constant>
|
||||||
|
(TYPE_STRING, path.string(),
|
||||||
|
node->loc());
|
||||||
|
|
||||||
|
prog->load_const(res);
|
||||||
|
prog->add(OP_IMPORT_SYS);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_LAMBDA: {
|
case NODE_LAMBDA: {
|
||||||
auto params = node->child(0);
|
auto params = node->child(0);
|
||||||
auto body = node->child(1);
|
auto body = node->child(1);
|
||||||
|
@ -70,7 +159,7 @@ namespace fk
|
||||||
|
|
||||||
m_sym->declare_local(func_name, params->size(), node->loc());
|
m_sym->declare_local(func_name, params->size(), node->loc());
|
||||||
|
|
||||||
Compiler compiler {m_sym};
|
Compiler compiler {m_mod, m_sym};
|
||||||
for (auto e: m_macros)
|
for (auto e: m_macros)
|
||||||
{
|
{
|
||||||
compiler.add_macro(e.first, e.second);
|
compiler.add_macro(e.first, e.second);
|
||||||
|
@ -92,13 +181,24 @@ namespace fk
|
||||||
case NODE_CALL: {
|
case NODE_CALL: {
|
||||||
std::string ident = node->child(0)->repr();
|
std::string ident = node->child(0)->repr();
|
||||||
|
|
||||||
|
|
||||||
if (auto itr=m_macros.find(ident);
|
if (auto itr=m_macros.find(ident);
|
||||||
itr != std::end(m_macros))
|
itr != std::end(m_macros))
|
||||||
{
|
{
|
||||||
auto macro = itr->second;
|
auto macro = itr->second;
|
||||||
macro->call(*this, node, prog);
|
macro->call(*this, node, prog);
|
||||||
}
|
}
|
||||||
|
else if (node->child(0)->type() == NODE_NS
|
||||||
|
&& has_macro(node->child(0)->child(1)->repr()))
|
||||||
|
{
|
||||||
|
std::string name = node->child(0)->child(1)->repr();
|
||||||
|
|
||||||
|
if (auto itr=m_macros.find(name);
|
||||||
|
itr != std::end(m_macros))
|
||||||
|
{
|
||||||
|
auto macro = itr->second;
|
||||||
|
macro->call(*this, node, prog);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<node->size(); i++)
|
for (size_t i=0; i<node->size(); i++)
|
||||||
|
@ -106,8 +206,10 @@ namespace fk
|
||||||
compile_prog(node->child(i), prog);
|
compile_prog(node->child(i), prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (node->child(0)->type() == NODE_LAMBDA
|
if (node->child(0)->type() == NODE_LAMBDA
|
||||||
|| node->child(0)->type() == NODE_CALL)
|
|| node->child(0)->type() == NODE_CALL
|
||||||
|
|| node->child(0)->type() == NODE_NS)
|
||||||
{
|
{
|
||||||
prog->add(OP_CALL_REF, node->size() - 1);
|
prog->add(OP_CALL_REF, node->size() - 1);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +239,7 @@ namespace fk
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prog->add(OP_CALL_NATIVE, node->size() - 1);
|
prog->add(OP_CALL_REF, node->size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,12 @@ namespace fk
|
||||||
size_t arity;
|
size_t arity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Module;
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Compiler(std::shared_ptr<SymTable> sym);
|
explicit Compiler(Module& mod, std::shared_ptr<SymTable> sym);
|
||||||
virtual ~Compiler();
|
virtual ~Compiler();
|
||||||
|
|
||||||
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
||||||
|
@ -26,6 +28,14 @@ namespace fk
|
||||||
void add_macro(std::string const& name,
|
void add_macro(std::string const& name,
|
||||||
std::shared_ptr<NativeMacro> macro);
|
std::shared_ptr<NativeMacro> macro);
|
||||||
|
|
||||||
|
std::shared_ptr<NativeMacro> get_macro(std::string const& name);
|
||||||
|
|
||||||
|
bool has_macro(std::string const& name) const;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<NativeMacro>>
|
||||||
|
macros();
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<Program> compile(std::shared_ptr<Node> node);
|
std::shared_ptr<Program> compile(std::shared_ptr<Node> node);
|
||||||
|
|
||||||
void compile_prog(std::shared_ptr<Node> node,
|
void compile_prog(std::shared_ptr<Node> node,
|
||||||
|
@ -35,6 +45,8 @@ namespace fk
|
||||||
void pop_decl();
|
void pop_decl();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Module& m_mod;
|
||||||
|
addr_t m_addr = 0;
|
||||||
std::shared_ptr<SymTable> m_sym;
|
std::shared_ptr<SymTable> m_sym;
|
||||||
std::vector<std::string> m_decl_stack;
|
std::vector<std::string> m_decl_stack;
|
||||||
std::unordered_map<std::string,
|
std::unordered_map<std::string,
|
||||||
|
|
|
@ -7,6 +7,9 @@ namespace fk
|
||||||
: m_loc { loc }
|
: m_loc { loc }
|
||||||
{
|
{
|
||||||
std::vector<std::tuple<NodeType, std::string, bool>> text = {
|
std::vector<std::tuple<NodeType, std::string, bool>> text = {
|
||||||
|
{NODE_IMPORT, "@", false},
|
||||||
|
{NODE_DECL, "$", false},
|
||||||
|
{NODE_NS, "::", false},
|
||||||
{NODE_RARROW, "->", false},
|
{NODE_RARROW, "->", false},
|
||||||
{NODE_OPAR, "(", false},
|
{NODE_OPAR, "(", false},
|
||||||
{NODE_CPAR, ")", false},
|
{NODE_CPAR, ")", false},
|
||||||
|
@ -255,8 +258,16 @@ namespace fk
|
||||||
std::string repr;
|
std::string repr;
|
||||||
|
|
||||||
while (cursor < m_source.size()
|
while (cursor < m_source.size()
|
||||||
&& !is_sep(cursor))
|
&& !is_sep(cursor)
|
||||||
|
&& m_source[cursor])
|
||||||
{
|
{
|
||||||
|
if (cursor + 1 < m_source.size()
|
||||||
|
&& m_source[cursor] == ':'
|
||||||
|
&& m_source[cursor + 1] == ':')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
repr += m_source[cursor];
|
repr += m_source[cursor];
|
||||||
cursor++;
|
cursor++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,27 @@ namespace fk
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Module> Module::get_mod(std::string const& name)
|
||||||
|
{
|
||||||
|
assert(m_native_modules.find(name) != std::end(m_native_modules));
|
||||||
|
return m_native_modules[name];
|
||||||
|
}
|
||||||
|
|
||||||
void Module::build()
|
void Module::build()
|
||||||
{
|
{
|
||||||
import_std();
|
import_std();
|
||||||
m_source = load_sources();
|
m_source = load_sources();
|
||||||
m_ast = m_parser->parse(m_source);
|
m_ast = m_parser->parse(m_source);
|
||||||
|
|
||||||
|
// Add natives macros before compilation
|
||||||
|
for (auto mod: m_native_modules)
|
||||||
|
{
|
||||||
|
for (auto e: mod.second->compiler()->macros())
|
||||||
|
{
|
||||||
|
m_compiler->add_macro(e.first, e.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_program = m_compiler->compile(m_ast);
|
m_program = m_compiler->compile(m_ast);
|
||||||
|
|
||||||
m_vm->mount(m_program);
|
m_vm->mount(m_program);
|
||||||
|
@ -43,6 +59,14 @@ namespace fk
|
||||||
f(*this);
|
f(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Module> Module::register_module(std::string const& name)
|
||||||
|
{
|
||||||
|
auto mod = std::make_shared<Module>(name);
|
||||||
|
m_native_modules[name] = mod;
|
||||||
|
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
void Module::register_function(std::string const& name, native_t native)
|
void Module::register_function(std::string const& name, native_t native)
|
||||||
{
|
{
|
||||||
auto fun = std::make_shared<NativeFunction>(native);
|
auto fun = std::make_shared<NativeFunction>(native);
|
||||||
|
|
|
@ -18,15 +18,20 @@ namespace fk
|
||||||
explicit Module(std::filesystem::path source_path);
|
explicit Module(std::filesystem::path source_path);
|
||||||
virtual ~Module();
|
virtual ~Module();
|
||||||
|
|
||||||
|
std::shared_ptr<Compiler> compiler() const { return m_compiler; }
|
||||||
std::shared_ptr<Program> program() const { return m_program; }
|
std::shared_ptr<Program> program() const { return m_program; }
|
||||||
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
||||||
std::shared_ptr<VM> vm() const { return m_vm; }
|
std::shared_ptr<VM> vm() const { return m_vm; }
|
||||||
|
|
||||||
|
std::shared_ptr<Module> get_mod(std::string const& name);
|
||||||
|
|
||||||
void build();
|
void build();
|
||||||
|
|
||||||
void import_std();
|
void import_std();
|
||||||
void import_library(std::filesystem::path lib_path);
|
void import_library(std::filesystem::path lib_path);
|
||||||
|
|
||||||
|
std::shared_ptr<Module> register_module(std::string const& name);
|
||||||
|
|
||||||
void register_function(std::string const& name, native_t native);
|
void register_function(std::string const& name, native_t native);
|
||||||
void register_macro(std::string const& name, macro_t macro);
|
void register_macro(std::string const& name, macro_t macro);
|
||||||
|
|
||||||
|
@ -37,10 +42,13 @@ namespace fk
|
||||||
std::shared_ptr<Lexer> m_lexer = std::make_shared<Lexer>(m_loc);
|
std::shared_ptr<Lexer> m_lexer = std::make_shared<Lexer>(m_loc);
|
||||||
std::shared_ptr<Parser> m_parser = std::make_shared<Parser>(*m_lexer);
|
std::shared_ptr<Parser> m_parser = std::make_shared<Parser>(*m_lexer);
|
||||||
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
|
std::shared_ptr<SymTable> m_sym = std::make_shared<SymTable>();
|
||||||
std::shared_ptr<Compiler> m_compiler = std::make_shared<Compiler>(m_sym);
|
std::shared_ptr<Compiler> m_compiler = std::make_shared<Compiler>(*this,
|
||||||
|
m_sym);
|
||||||
std::shared_ptr<Node> m_ast;
|
std::shared_ptr<Node> m_ast;
|
||||||
std::shared_ptr<VM> m_vm = std::make_shared<VM>(*this);
|
std::shared_ptr<VM> m_vm = std::make_shared<VM>(*this);
|
||||||
std::shared_ptr<Program> m_program = std::make_shared<Program>();
|
std::shared_ptr<Program> m_program = std::make_shared<Program>();
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Module>> m_native_modules;
|
||||||
|
|
||||||
std::string load_sources();
|
std::string load_sources();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
#define NODE_TYPES(G) \
|
#define NODE_TYPES(G) \
|
||||||
G(NODE_MODULE), G(NODE_INT), G(NODE_FLOAT), G(NODE_BOOL), G(NODE_STRING),\
|
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_IDENT), G(NODE_OPAR), G(NODE_CPAR), G(NODE_CALL), G(NODE_LAMBDA),\
|
||||||
G(NODE_RARROW), G(NODE_PARAMS), G(NODE_BODY)
|
G(NODE_RARROW), G(NODE_PARAMS), G(NODE_BODY), G(NODE_NS), G(NODE_IMPORT),\
|
||||||
|
G(NODE_VARDECL), G(NODE_DECL)
|
||||||
|
|
||||||
namespace fk
|
namespace fk
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include "src/Loc.hpp"
|
#include "src/Loc.hpp"
|
||||||
#include "src/Node.hpp"
|
#include "src/Node.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace fk
|
namespace fk
|
||||||
{
|
{
|
||||||
|
@ -49,6 +50,24 @@ namespace fk
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::parse_expr()
|
std::shared_ptr<Node> Parser::parse_expr()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (type_all({NODE_IDENT, NODE_NS}))
|
||||||
|
{
|
||||||
|
return parse_ns();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_all({NODE_OPAR, NODE_DECL, NODE_IMPORT,
|
||||||
|
NODE_IDENT, NODE_STRING, NODE_CPAR})
|
||||||
|
|| type_all({NODE_OPAR, NODE_DECL, NODE_IMPORT,
|
||||||
|
NODE_IDENT, NODE_CPAR}))
|
||||||
|
{
|
||||||
|
return parse_short_import();
|
||||||
|
}
|
||||||
|
else if (type_all({NODE_OPAR, NODE_IMPORT}))
|
||||||
|
{
|
||||||
|
return parse_import();
|
||||||
|
}
|
||||||
|
|
||||||
if (type_any({
|
if (type_any({
|
||||||
NODE_INT,
|
NODE_INT,
|
||||||
NODE_FLOAT,
|
NODE_FLOAT,
|
||||||
|
@ -59,11 +78,14 @@ namespace fk
|
||||||
return consume();
|
return consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_all({NODE_OPAR, NODE_IDENT, NODE_OPAR, NODE_IDENT})
|
if (type_all({NODE_OPAR, NODE_DECL, NODE_OPAR, NODE_IDENT}))
|
||||||
&& m_tokens[m_cursor + 1]->repr() == "$")
|
|
||||||
{
|
{
|
||||||
return parse_fundecl();
|
return parse_fundecl();
|
||||||
}
|
}
|
||||||
|
else if (type_all({NODE_OPAR, NODE_DECL}))
|
||||||
|
{
|
||||||
|
return parse_vardecl();
|
||||||
|
}
|
||||||
else if (type_all({NODE_OPAR, NODE_RARROW}))
|
else if (type_all({NODE_OPAR, NODE_RARROW}))
|
||||||
{
|
{
|
||||||
return parse_lambda();
|
return parse_lambda();
|
||||||
|
@ -142,7 +164,7 @@ namespace fk
|
||||||
std::shared_ptr<Node> Parser::parse_fundecl()
|
std::shared_ptr<Node> Parser::parse_fundecl()
|
||||||
{
|
{
|
||||||
consume(NODE_OPAR);
|
consume(NODE_OPAR);
|
||||||
auto dollar = consume(NODE_IDENT);
|
auto dollar = consume(NODE_DECL);
|
||||||
|
|
||||||
consume(NODE_OPAR);
|
consume(NODE_OPAR);
|
||||||
auto ident = consume(NODE_IDENT);
|
auto ident = consume(NODE_IDENT);
|
||||||
|
@ -152,8 +174,7 @@ namespace fk
|
||||||
auto body = parse_body();
|
auto body = parse_body();
|
||||||
consume(NODE_CPAR);
|
consume(NODE_CPAR);
|
||||||
|
|
||||||
auto res = make_node(NODE_CALL);
|
auto res = make_node(NODE_VARDECL);
|
||||||
res->add_child(dollar);
|
|
||||||
res->add_child(ident);
|
res->add_child(ident);
|
||||||
|
|
||||||
auto lambda = make_node(NODE_LAMBDA);
|
auto lambda = make_node(NODE_LAMBDA);
|
||||||
|
@ -164,6 +185,70 @@ namespace fk
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_vardecl()
|
||||||
|
{
|
||||||
|
auto node = make_node(NODE_VARDECL);
|
||||||
|
consume(NODE_OPAR);
|
||||||
|
consume(NODE_DECL);
|
||||||
|
|
||||||
|
node->add_child(consume(NODE_IDENT));
|
||||||
|
node->add_child(parse_expr());
|
||||||
|
consume(NODE_CPAR);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse_ns()
|
||||||
|
{
|
||||||
|
auto ns = make_node(NODE_NS);
|
||||||
|
ns->add_child(consume(NODE_IDENT));
|
||||||
|
consume(NODE_NS);
|
||||||
|
ns->add_child(consume(NODE_IDENT));
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_short_import()
|
||||||
|
{
|
||||||
|
consume(NODE_OPAR);
|
||||||
|
consume(NODE_DECL);
|
||||||
|
|
||||||
|
auto node_import = consume(NODE_IMPORT);
|
||||||
|
auto ident = consume(NODE_IDENT);
|
||||||
|
std::shared_ptr<Node> str;
|
||||||
|
|
||||||
|
if (type_is(NODE_CPAR))
|
||||||
|
{
|
||||||
|
str = std::make_shared<Node>(NODE_STRING,
|
||||||
|
"'" + ident->repr() + "'",
|
||||||
|
ident->loc());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str = consume(NODE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
consume(NODE_CPAR);
|
||||||
|
|
||||||
|
auto vardecl = make_node(NODE_VARDECL);
|
||||||
|
vardecl->add_child(ident);
|
||||||
|
|
||||||
|
auto imp = make_node(NODE_IMPORT);
|
||||||
|
imp->add_child(str);
|
||||||
|
vardecl->add_child(imp);
|
||||||
|
|
||||||
|
return vardecl;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> Parser::make_node(NodeType type)
|
std::shared_ptr<Node> Parser::make_node(NodeType type)
|
||||||
{
|
{
|
||||||
return std::make_shared<Node>(type, "", loc());
|
return std::make_shared<Node>(type, "", loc());
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace fk
|
||||||
std::shared_ptr<Node> parse_params();
|
std::shared_ptr<Node> parse_params();
|
||||||
std::shared_ptr<Node> parse_body();
|
std::shared_ptr<Node> parse_body();
|
||||||
std::shared_ptr<Node> parse_fundecl();
|
std::shared_ptr<Node> parse_fundecl();
|
||||||
|
std::shared_ptr<Node> parse_vardecl();
|
||||||
|
std::shared_ptr<Node> parse_ns();
|
||||||
|
std::shared_ptr<Node> parse_import();
|
||||||
|
std::shared_ptr<Node> parse_short_import();
|
||||||
|
|
||||||
std::shared_ptr<Node> make_node(NodeType type);
|
std::shared_ptr<Node> make_node(NodeType type);
|
||||||
Loc loc() const;
|
Loc loc() const;
|
||||||
|
|
144
src/VM.cpp
144
src/VM.cpp
|
@ -1,5 +1,7 @@
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "src/opcodes.hpp"
|
#include "opcodes.hpp"
|
||||||
|
#include "Module.hpp"
|
||||||
|
#include "src/NativeFunction.hpp"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace fk
|
namespace fk
|
||||||
|
@ -29,6 +31,103 @@ namespace fk
|
||||||
|
|
||||||
switch (instr.opcode)
|
switch (instr.opcode)
|
||||||
{
|
{
|
||||||
|
case OP_IMPORT: {
|
||||||
|
auto path_val = frame().program->get_const(pop());
|
||||||
|
std::filesystem::path path =
|
||||||
|
std::get<std::string>(path_val->value());
|
||||||
|
|
||||||
|
auto mod = std::make_shared<Module>(path);
|
||||||
|
mod->build();
|
||||||
|
|
||||||
|
addr_t addr = store_global(mod);
|
||||||
|
auto res = std::make_shared<Constant>(TYPE_REF, addr,
|
||||||
|
path_val->loc());
|
||||||
|
push(frame().program->add(res));
|
||||||
|
m_pc++;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_IMPORT_SYS: {
|
||||||
|
auto path_val = frame().program->get_const(pop());
|
||||||
|
|
||||||
|
std::filesystem::path path =
|
||||||
|
std::get<std::string>(path_val->value());
|
||||||
|
|
||||||
|
auto mod = m_mod.get_mod(path);
|
||||||
|
|
||||||
|
addr_t addr = store_global(mod);
|
||||||
|
auto res = std::make_shared<Constant>(TYPE_REF, addr,
|
||||||
|
path_val->loc());
|
||||||
|
push(frame().program->add(res));
|
||||||
|
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case OP_LOAD_MOD: {
|
||||||
|
addr_t mod_addr = pop();
|
||||||
|
auto mod_val = frame().program->get_const(mod_addr);
|
||||||
|
size_t mod_ref =
|
||||||
|
std::get<size_t>(mod_val->value());
|
||||||
|
|
||||||
|
auto mod = std::get<std::shared_ptr<Module>>
|
||||||
|
(load_global(mod_ref));
|
||||||
|
|
||||||
|
addr_t ident_addr = pop();
|
||||||
|
auto ident =
|
||||||
|
std::get<std::string>(frame().program->
|
||||||
|
get_const(ident_addr)->value());
|
||||||
|
|
||||||
|
auto entry = mod->sym()->find_global(ident);
|
||||||
|
|
||||||
|
if (mod->compiler()->has_macro(ident))
|
||||||
|
{
|
||||||
|
m_pc++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
std::cerr << "cannot load " << ident << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->is_global())
|
||||||
|
{
|
||||||
|
auto fun = std::get<std::shared_ptr<NativeFunction>>
|
||||||
|
(mod->vm()->m_globals[entry->addr()]);
|
||||||
|
size_t addr = store_global(fun);
|
||||||
|
|
||||||
|
auto ref = std::make_shared<Constant>(TYPE_REF,
|
||||||
|
addr,
|
||||||
|
Loc {""});
|
||||||
|
push(frame().program->add(ref));
|
||||||
|
m_pc++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto var = mod->vm()->load_local(entry->addr());
|
||||||
|
|
||||||
|
if (var->type() == TYPE_REF)
|
||||||
|
{
|
||||||
|
auto value = mod->vm()->load_global
|
||||||
|
(std::get<size_t>(var->value()));
|
||||||
|
|
||||||
|
size_t new_addr = store_global(value);
|
||||||
|
|
||||||
|
push(frame().program->add
|
||||||
|
(std::make_shared<Constant>(TYPE_REF,
|
||||||
|
new_addr,
|
||||||
|
mod_val->loc())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto value = mod->vm()->load_local(entry->addr());
|
||||||
|
push(frame().program->add(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pc++;
|
||||||
|
} break;
|
||||||
|
|
||||||
case OP_STORE_CLOSURE: {
|
case OP_STORE_CLOSURE: {
|
||||||
auto val = frame().program->get_const(top());
|
auto val = frame().program->get_const(top());
|
||||||
auto lambda = frame().lambda;
|
auto lambda = frame().lambda;
|
||||||
|
@ -135,6 +234,19 @@ namespace fk
|
||||||
|
|
||||||
addr_t ref = std::get<addr_t>(ref_val->value());
|
addr_t ref = std::get<addr_t>(ref_val->value());
|
||||||
|
|
||||||
|
auto val = load_global(ref);
|
||||||
|
|
||||||
|
if (std::get_if<std::shared_ptr<NativeFunction>>(&val))
|
||||||
|
{
|
||||||
|
auto fun = std::get<std::shared_ptr<NativeFunction>>
|
||||||
|
(load_global(ref));
|
||||||
|
|
||||||
|
push(frame().program->add(fun->call(ref_val->loc(),
|
||||||
|
m_mod, args)));
|
||||||
|
m_pc++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto lambda = std::get<std::shared_ptr<Lambda>>(load_global(ref));
|
auto lambda = std::get<std::shared_ptr<Lambda>>(load_global(ref));
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,36 +271,6 @@ namespace fk
|
||||||
m_pc = 0;
|
m_pc = 0;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OP_CALL_NATIVE: {
|
|
||||||
std::vector<std::shared_ptr<Constant>> args;
|
|
||||||
|
|
||||||
for (size_t i=0; i<instr.param; i++)
|
|
||||||
{
|
|
||||||
addr_t addr = pop();
|
|
||||||
|
|
||||||
args.insert(std::begin(args),
|
|
||||||
frame().program->get_const(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ref_val = frame().program->get_const(pop());
|
|
||||||
|
|
||||||
Loc loc = ref_val->loc();
|
|
||||||
|
|
||||||
if (instr.param > 0)
|
|
||||||
{
|
|
||||||
loc = args.front()->loc();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ref = std::get<size_t>(ref_val->value());
|
|
||||||
|
|
||||||
auto fun = std::get<std::shared_ptr<NativeFunction>>
|
|
||||||
(load_global(ref));
|
|
||||||
|
|
||||||
push(frame().program->add(fun->call(loc, m_mod, args)));
|
|
||||||
|
|
||||||
m_pc++;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case OP_LOAD_LOCAL: {
|
case OP_LOAD_LOCAL: {
|
||||||
auto value = frame().locals[instr.param];
|
auto value = frame().locals[instr.param];
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
namespace fk
|
namespace fk
|
||||||
{
|
{
|
||||||
using global_t = std::variant<std::shared_ptr<NativeFunction>,
|
using global_t = std::variant<std::shared_ptr<NativeFunction>,
|
||||||
|
std::shared_ptr<Module>,
|
||||||
std::shared_ptr<Lambda>
|
std::shared_ptr<Lambda>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#ifndef fk_OPCODES_HPP
|
#ifndef fk_OPCODES_HPP
|
||||||
#define fk_OPCODES_HPP
|
#define fk_OPCODES_HPP
|
||||||
|
|
||||||
#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), G(OP_CALL_NATIVE), \
|
#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), \
|
||||||
G(OP_LOAD_GLOBAL), G(OP_LOAD_LOCAL), G(OP_STORE_LOCAL), \
|
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_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_BR), G(OP_LOAD_CLOSURE), G(OP_STORE_CLOSURE), \
|
||||||
|
G(OP_LOAD_MOD), G(OP_IMPORT), G(OP_IMPORT_SYS)
|
||||||
|
|
||||||
#include "commons.hpp"
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
|
|
@ -97,3 +97,15 @@ TEST_CASE_METHOD(LexerTest, "Lexer_lambda")
|
||||||
test_next("CPAR");
|
test_next("CPAR");
|
||||||
test_end();
|
test_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_namespace")
|
||||||
|
{
|
||||||
|
m_lexer.scan(" (a::x 3) ");
|
||||||
|
test_next("OPAR");
|
||||||
|
test_next("IDENT[a]");
|
||||||
|
test_next("NS");
|
||||||
|
test_next("IDENT[x]");
|
||||||
|
test_next("INT[3]");
|
||||||
|
test_next("CPAR");
|
||||||
|
test_end();
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,12 @@ TEST_CASE_METHOD(ParserTest, "Parser_call")
|
||||||
" (bim 2 '3' false) ");
|
" (bim 2 '3' false) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_vardecl")
|
||||||
|
{
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[hello],INT[3]))",
|
||||||
|
" ($ hello 3) ");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_lambda")
|
TEST_CASE_METHOD(ParserTest, "Parser_lambda")
|
||||||
{
|
{
|
||||||
test_parse("MODULE(LAMBDA(PARAMS,BODY))",
|
test_parse("MODULE(LAMBDA(PARAMS,BODY))",
|
||||||
|
@ -50,7 +56,28 @@ TEST_CASE_METHOD(ParserTest, "Parser_lambda")
|
||||||
|
|
||||||
TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
|
TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
|
||||||
{
|
{
|
||||||
test_parse("MODULE(CALL(IDENT[$],IDENT[f],"
|
test_parse("MODULE(VARDECL(IDENT[f],"
|
||||||
"LAMBDA(PARAMS(IDENT[x]),BODY(INT[7]))))",
|
"LAMBDA(PARAMS(IDENT[x]),BODY(INT[7]))))",
|
||||||
" ($ (f x) 7) ");
|
" ($ (f x) 7) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_namespace")
|
||||||
|
{
|
||||||
|
test_parse("MODULE(CALL(NS(IDENT[x],IDENT[y]),IDENT[z]))",
|
||||||
|
" (x::y z) ");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_import")
|
||||||
|
{
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[x],IMPORT(STRING['y'])))",
|
||||||
|
" ($ x (@ 'y') )");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[x],IMPORT(STRING['y'])))",
|
||||||
|
" ($ @x 'y' )");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[bim],IMPORT(STRING['bam'])))",
|
||||||
|
" ($ @bim 'bam' )");
|
||||||
|
|
||||||
|
test_parse("MODULE(VARDECL(IDENT[example],IMPORT(STRING['example'])))",
|
||||||
|
" ($ @example )");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue