Compare commits
5 Commits
55c094e4ec
...
f63cbf4cea
Author | SHA1 | Date |
---|---|---|
bog | f63cbf4cea | |
bog | 820d26491a | |
bog | 073cbb4618 | |
bog | 0aa9ebd952 | |
bog | ee1b52cae1 |
|
@ -0,0 +1,20 @@
|
|||
($ a 2)
|
||||
(assert= 2 a)
|
||||
|
||||
(:
|
||||
($ a 9)
|
||||
(assert= 9 a)
|
||||
|
||||
(:
|
||||
($ a 42)
|
||||
(assert= 42 a)
|
||||
)
|
||||
|
||||
(assert= 9 a)
|
||||
)
|
||||
|
||||
(assert= 2 a)
|
||||
|
||||
(:($ b 43))
|
||||
|
||||
(assert-fail b)
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
TOTAL=0
|
||||
SUCCESS=0
|
||||
|
||||
for file in `find -name "*.zn"`
|
||||
do
|
||||
NAME=$(basename $file | cut -d'.' -f1)
|
||||
MSG=$(zarn "$file" 2>&1 > /dev/null)
|
||||
|
||||
STATUS=$?
|
||||
|
||||
echo -en "\e[34m$NAME ... \e[0m"
|
||||
if [ $STATUS -eq 0 ]
|
||||
then
|
||||
echo -e "\e[32mok\e[0m"
|
||||
SUCCESS=$(($SUCCESS + 1))
|
||||
else
|
||||
echo -e "\e[31mko\e[0m"
|
||||
echo "$MSG"
|
||||
fi
|
||||
|
||||
TOTAL=$((TOTAL + 1))
|
||||
done
|
||||
|
||||
FAILURE=$(($TOTAL - $SUCCESS))
|
||||
|
||||
if [ $SUCCESS -eq $TOTAL ]
|
||||
then
|
||||
echo -e "\e[32m======== All tests passed ========\e[0m"
|
||||
else
|
||||
echo -e "\e[31m======== $FAILURE tests failed ========\e[0m"
|
||||
fi
|
||||
|
||||
echo -e "\e[0mok:\t$SUCCESS\e[0m"
|
||||
echo -e "\e[0mko:\t$FAILURE\e[0m"
|
||||
|
||||
if [ $SUCCESS -eq $TOTAL ]
|
||||
then
|
||||
echo -e "\e[32mTOTAL:\t$TOTAL\e[0m"
|
||||
else
|
||||
echo -e "\e[31mTOTAL:\t$TOTAL\e[0m"
|
||||
fi
|
|
@ -0,0 +1,8 @@
|
|||
(assert-fail a)
|
||||
($ a 34)
|
||||
(assert-fail (a))
|
||||
(assert= 34 a)
|
||||
|
||||
($ b ($ c 9))
|
||||
(assert= 9 b)
|
||||
(assert= 9 c)
|
|
@ -2,6 +2,8 @@
|
|||
#define COMMON_HPP
|
||||
|
||||
#include "../src/Zarn.hpp"
|
||||
#include "../src/Module.hpp"
|
||||
|
||||
using namespace zn;
|
||||
|
||||
#define STDARGS std::vector<std::shared_ptr<Constant>>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#include "macro.hpp"
|
||||
|
||||
void assert_fail(Node const& node, Module& mod)
|
||||
{
|
||||
try
|
||||
{
|
||||
mod.static_pass().execute(*node.child_at(1));
|
||||
mod.compiler().compile(*node.child_at(1), mod.program());
|
||||
|
||||
Loc loc = node.loc();
|
||||
|
||||
std::cerr << loc.file_path().string() << ":" << loc.line();
|
||||
std::cerr << " ASSERTION FAILED" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
}
|
||||
|
||||
size_t addr = mod.program().add_constant(std::make_shared<Constant>
|
||||
(TYPE_NIL, node.loc(), 0));
|
||||
mod.program().append(OPCODE_LOAD_CONST, addr);
|
||||
}
|
||||
|
||||
void declare(Node const& node, Module &mod)
|
||||
{
|
||||
std::string ident = node.child_at(1)->repr();
|
||||
mod.compiler().compile(*node.child_at(2), mod.program());
|
||||
auto entry = mod.sym().find_any(ident);
|
||||
assert(entry);
|
||||
size_t addr = mod.sym().gen_addr();
|
||||
|
||||
mod.sym().declare(ident, addr, entry->scope);
|
||||
mod.program().append(OPCODE_STORE_LOCAL, addr);
|
||||
}
|
||||
|
||||
void block(Node const& node, Module& mod)
|
||||
{
|
||||
mod.sym().enter_scope();
|
||||
|
||||
for (size_t i=1; i<node.size(); i++)
|
||||
{
|
||||
mod.static_pass().execute(*node.child_at(i));
|
||||
mod.compiler().compile(*node.child_at(i), mod.program());
|
||||
|
||||
if (i != node.size() - 1)
|
||||
{
|
||||
mod.program().append(OPCODE_POP);
|
||||
}
|
||||
}
|
||||
|
||||
mod.sym().leave_scope();
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef MACRO_HPP
|
||||
#define MACRO_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
void assert_fail(Node const& node, Module& mod);
|
||||
|
||||
void declare(Node const& node, Module& mod);
|
||||
|
||||
void block(Node const& node, Module& mod);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
#include "common.hpp"
|
||||
#include "fun.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "../src/types.hpp"
|
||||
|
||||
extern "C" void lib(Zarn& zarn)
|
||||
{
|
||||
|
@ -16,4 +18,8 @@ extern "C" void lib(Zarn& zarn)
|
|||
->param_any()
|
||||
->ret(TYPE_NIL),
|
||||
assert_eq);
|
||||
|
||||
zarn.register_macro("assert-fail", assert_fail);
|
||||
zarn.register_macro("$", declare);
|
||||
zarn.register_macro(":", block);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ zarn_lib = shared_library('zarn',
|
|||
'src/SymTable.cpp',
|
||||
'src/NativeFunction.cpp',
|
||||
'src/Prototype.cpp',
|
||||
'src/NativeMacro.cpp',
|
||||
'src/Zarn.cpp',
|
||||
],
|
||||
install: true)
|
||||
|
@ -49,6 +50,7 @@ shared_library('zarn-std',
|
|||
sources: [
|
||||
'libstd/std.cpp',
|
||||
'libstd/fun.cpp',
|
||||
'libstd/macro.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
zarn_dep
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
#include "Compiler.hpp"
|
||||
#include "src/Node.hpp"
|
||||
#include "src/Program.hpp"
|
||||
#include "Module.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "Program.hpp"
|
||||
#include "NativeMacro.hpp"
|
||||
|
||||
namespace zn
|
||||
{
|
||||
/*explicit*/ Compiler::Compiler(Logger& logger, SymTable& sym)
|
||||
: m_logger { logger }
|
||||
/*explicit*/ Compiler::Compiler(Module& mod,
|
||||
Logger& logger,
|
||||
SymTable& sym)
|
||||
: m_mod { mod }
|
||||
, m_logger { logger }
|
||||
, m_sym { sym }
|
||||
{
|
||||
}
|
||||
|
@ -14,6 +19,11 @@ namespace zn
|
|||
{
|
||||
}
|
||||
|
||||
void Compiler::add_macro(std::shared_ptr<NativeMacro> macro)
|
||||
{
|
||||
m_macros.push_back(macro);
|
||||
}
|
||||
|
||||
void Compiler::compile(Node const& node, Program& program)
|
||||
{
|
||||
switch (node.type())
|
||||
|
@ -31,12 +41,44 @@ namespace zn
|
|||
// FUNCTION STUFF
|
||||
// ==============
|
||||
case NODE_CALL: {
|
||||
std::string ident = node.child_at(0)->repr();
|
||||
auto sym = m_sym.find(ident);
|
||||
|
||||
if (sym)
|
||||
{
|
||||
for (size_t i=0; i<node.size(); i++)
|
||||
{
|
||||
compile(*node.child_at(i), program);
|
||||
}
|
||||
|
||||
program.append(OPCODE_CALL_NATIVE, node.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool found_macro = false;
|
||||
|
||||
for (auto macro: m_macros)
|
||||
{
|
||||
if (macro->name() == ident)
|
||||
{
|
||||
macro->execute(node, m_mod);
|
||||
found_macro = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_macro)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "cannot call undefined function '"
|
||||
<< ident
|
||||
<< "'";
|
||||
|
||||
m_logger.log<compile_error>(LOG_ERROR,
|
||||
node.loc(),
|
||||
ss.str());
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
// VALUES
|
||||
|
@ -44,19 +86,30 @@ namespace zn
|
|||
case NODE_IDENT: {
|
||||
std::string ident = node.repr();
|
||||
auto sym = m_sym.find(ident);
|
||||
assert(sym);
|
||||
|
||||
if (!sym)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "cannot use undefined variable '"
|
||||
<< ident
|
||||
<< "'";
|
||||
|
||||
m_logger.log<compile_error>(LOG_ERROR,
|
||||
node.loc(),
|
||||
ss.str());
|
||||
}
|
||||
|
||||
if (sym->prototype)
|
||||
{
|
||||
auto ref = std::make_shared<Constant>(TYPE_REF,
|
||||
node.loc(),
|
||||
(int) sym->addr);
|
||||
(int) *sym->addr);
|
||||
size_t val = program.add_constant(ref);
|
||||
program.append(OPCODE_LOAD_CONST, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
program.append(OPCODE_LOAD_LOCAL, sym->addr);
|
||||
program.append(OPCODE_LOAD_LOCAL, *sym->addr);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
|
|
@ -11,17 +11,23 @@ namespace zn
|
|||
{
|
||||
ZN_ERROR(compile_error);
|
||||
|
||||
class NativeMacro;
|
||||
class Module;
|
||||
|
||||
class Compiler
|
||||
{
|
||||
public:
|
||||
explicit Compiler(Logger& logger, SymTable& sym);
|
||||
explicit Compiler(Module& mod, Logger& logger, SymTable& sym);
|
||||
virtual ~Compiler();
|
||||
|
||||
void add_macro(std::shared_ptr<NativeMacro> macro);
|
||||
void compile(Node const& node, Program& program);
|
||||
|
||||
private:
|
||||
Module& m_mod;
|
||||
Logger& m_logger;
|
||||
SymTable& m_sym;
|
||||
std::vector<std::shared_ptr<NativeMacro>> m_macros;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ namespace zn
|
|||
{
|
||||
case TYPE_NIL: return "<nil>";
|
||||
case TYPE_INT: return std::to_string(std::get<int>(*m_value));
|
||||
case TYPE_REF: {
|
||||
return "<ref " + std::to_string(std::get<int>(*m_value)) + ">";
|
||||
} break;
|
||||
|
||||
default: {
|
||||
std::cerr << "cannot stringify "
|
||||
<< (TypeStr[m_type] + strlen("TYPE_"))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Module.hpp"
|
||||
#include "Zarn.hpp"
|
||||
#include "Lexer.hpp"
|
||||
#include "Parser.hpp"
|
||||
#include "Program.hpp"
|
||||
|
@ -48,11 +49,8 @@ namespace zn
|
|||
|
||||
m_zarn.load_std_library();
|
||||
|
||||
StaticPass static_pass { m_logger, m_sym };
|
||||
static_pass.execute(*ast);
|
||||
|
||||
Compiler compiler { m_logger, m_sym };
|
||||
compiler.compile(*ast, m_program);
|
||||
m_static_pass.execute(*ast);
|
||||
m_compiler.compile(*ast, m_program);
|
||||
|
||||
m_vm.execute(m_program);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "VM.hpp"
|
||||
#include "Program.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "StaticPass.hpp"
|
||||
#include "Compiler.hpp"
|
||||
#include "Zarn.hpp"
|
||||
|
||||
namespace zn
|
||||
|
@ -18,6 +20,12 @@ namespace zn
|
|||
explicit Module(Logger& logger);
|
||||
virtual ~Module();
|
||||
|
||||
Compiler& compiler() { return m_compiler; }
|
||||
StaticPass& static_pass() { return m_static_pass; }
|
||||
|
||||
Program& program() { return m_program; }
|
||||
SymTable& sym() { return m_sym; }
|
||||
|
||||
void load_from_file(std::filesystem::path file_path);
|
||||
|
||||
std::string string() const;
|
||||
|
@ -27,7 +35,9 @@ namespace zn
|
|||
Program m_program;
|
||||
VM m_vm { m_program };
|
||||
SymTable m_sym;
|
||||
Zarn m_zarn {m_sym, m_vm};
|
||||
StaticPass m_static_pass {m_logger, m_sym};
|
||||
Compiler m_compiler {*this, m_logger, m_sym};
|
||||
Zarn m_zarn {m_compiler, m_sym, m_vm};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#include "NativeMacro.hpp"
|
||||
|
||||
namespace zn
|
||||
{
|
||||
/*explicit*/ NativeMacro::NativeMacro(std::string const& name,
|
||||
native_macro_t macro)
|
||||
: m_name { name }
|
||||
, m_macro { macro }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ NativeMacro::~NativeMacro()
|
||||
{
|
||||
}
|
||||
|
||||
void NativeMacro::execute(Node const& node,
|
||||
Module& mod)
|
||||
{
|
||||
m_macro(node, mod);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef zn_NATIVEMACRO_HPP
|
||||
#define zn_NATIVEMACRO_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
#include "Compiler.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace zn
|
||||
{
|
||||
class Module;
|
||||
|
||||
using native_macro_t = std::function<void
|
||||
(Node const&,
|
||||
Module&)>;
|
||||
|
||||
class NativeMacro
|
||||
{
|
||||
public:
|
||||
explicit NativeMacro(std::string const& name, native_macro_t macro);
|
||||
virtual ~NativeMacro();
|
||||
|
||||
std::string name() const { return m_name; }
|
||||
|
||||
|
||||
void execute(Node const& node,
|
||||
Module&);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
native_macro_t m_macro;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -27,19 +27,33 @@ namespace zn
|
|||
|
||||
case NODE_CALL: {
|
||||
std::string ident = node.child_at(0)->repr();
|
||||
auto sym = m_sym.find(ident);
|
||||
auto sym = m_sym.find_any(ident);
|
||||
|
||||
if (ident == "$")
|
||||
{
|
||||
std::string varname = node.child_at(1)->repr();
|
||||
auto vartype = execute(*node.child_at(2));
|
||||
m_sym.prepare(varname, *vartype.type);
|
||||
|
||||
return vartype;
|
||||
}
|
||||
|
||||
if (sym == std::nullopt)
|
||||
{
|
||||
m_logger.log<static_error>(LOG_ERROR,
|
||||
node.loc(),
|
||||
"cannot call unknown function '"
|
||||
+ ident
|
||||
+ "'");
|
||||
return TypeSlot {TYPE_NIL, TAG_ANY};
|
||||
}
|
||||
|
||||
auto proto = sym->prototype;
|
||||
assert(proto);
|
||||
|
||||
if (!proto)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "cannot call a none function variable '"
|
||||
<< ident
|
||||
<< "'";
|
||||
|
||||
m_logger.log<static_error>(LOG_ERROR, node.loc(), ss.str());
|
||||
}
|
||||
|
||||
if (proto->get_param_count() != node.size() - 1
|
||||
&& proto->get_param(proto->get_param_count() - 1).tag
|
||||
|
@ -79,6 +93,19 @@ namespace zn
|
|||
return proto->get_ret();
|
||||
} break;
|
||||
|
||||
case NODE_IDENT: {
|
||||
std::string ident = node.repr();
|
||||
auto sym = m_sym.find_any(ident);
|
||||
if (sym) assert(sym->scope <= m_sym.scope());
|
||||
if (sym == std::nullopt)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "undeclared var '" << ident << "'";
|
||||
m_logger.log<static_error>(LOG_ERROR, node.loc(), ss.str());
|
||||
}
|
||||
return TypeSlot {sym->type};
|
||||
} break;
|
||||
|
||||
case NODE_INT: {
|
||||
return TypeSlot {TYPE_INT};
|
||||
} break;
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace zn
|
|||
virtual ~StaticPass();
|
||||
|
||||
TypeSlot execute(Node const& node);
|
||||
|
||||
private:
|
||||
Logger& m_logger;
|
||||
SymTable& m_sym;
|
||||
|
|
|
@ -10,28 +10,115 @@ namespace zn
|
|||
{
|
||||
}
|
||||
|
||||
void SymTable::declare(std::string const& name, size_t addr)
|
||||
void SymTable::prepare(std::string const& name, Type type)
|
||||
{
|
||||
m_syms.push_back(Sym {name, addr});
|
||||
m_syms.push_back(Sym {name, std::nullopt, type, nullptr, m_scope});
|
||||
}
|
||||
|
||||
void SymTable::declare(std::string const& name,
|
||||
size_t addr,
|
||||
int scope)
|
||||
{
|
||||
auto itr = std::find_if(std::begin(m_syms),
|
||||
std::end(m_syms),
|
||||
[name, scope](auto const& sym){
|
||||
return sym.name == name
|
||||
&& sym.scope == scope;
|
||||
});
|
||||
|
||||
if (itr == std::end(m_syms))
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
itr->addr = addr;
|
||||
}
|
||||
|
||||
void SymTable::declare_function(std::string const& name,
|
||||
size_t addr,
|
||||
std::shared_ptr<Prototype> prototype)
|
||||
{
|
||||
m_syms.push_back(Sym {name, addr, prototype});
|
||||
m_syms.push_back(Sym {name, addr, TYPE_FUNCTION, prototype, m_scope});
|
||||
}
|
||||
|
||||
std::optional<Sym> SymTable::find(std::string const& name)
|
||||
{
|
||||
std::optional<size_t> best;
|
||||
|
||||
for (size_t i=0; i<m_syms.size(); i++)
|
||||
{
|
||||
if (name == m_syms[i].name)
|
||||
if (name == m_syms[i].name
|
||||
&& m_syms[i].addr
|
||||
&& (best == std::nullopt ||
|
||||
(m_syms[i].scope > m_syms[*best].scope
|
||||
&& m_syms[*best].scope < m_scope)))
|
||||
{
|
||||
return m_syms[i];
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (best)
|
||||
{
|
||||
return m_syms[*best];
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Sym> SymTable::find_any(std::string const& name)
|
||||
{
|
||||
std::optional<size_t> best;
|
||||
|
||||
for (size_t i=0; i<m_syms.size(); i++)
|
||||
{
|
||||
if (name == m_syms[i].name
|
||||
&& m_syms[i].scope <= m_scope
|
||||
&& (best == std::nullopt ||
|
||||
(m_syms[i].scope > m_syms[*best].scope
|
||||
&& m_syms[*best].scope <= m_scope)))
|
||||
{
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (best)
|
||||
{
|
||||
return m_syms[*best];
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t SymTable::gen_addr()
|
||||
{
|
||||
static size_t addr = 0;
|
||||
addr++;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void SymTable::enter_scope()
|
||||
{
|
||||
m_scope++;
|
||||
}
|
||||
|
||||
void SymTable::leave_scope()
|
||||
{
|
||||
m_scope--;
|
||||
}
|
||||
|
||||
std::string SymTable::string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "======== " << m_scope << " ========\n";
|
||||
|
||||
for (auto sym: m_syms)
|
||||
{
|
||||
ss << sym.scope << "\t" << sym.name << " "
|
||||
<< (sym.addr ? "[" + std::to_string(*sym.addr) + "]" : "[nil]")
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
|
||||
#include "common.hpp"
|
||||
#include "Prototype.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
namespace zn
|
||||
{
|
||||
struct Sym {
|
||||
std::string name;
|
||||
size_t addr;
|
||||
std::optional<size_t> addr;
|
||||
Type type;
|
||||
std::shared_ptr<Prototype> prototype = nullptr;
|
||||
int scope = 0;
|
||||
};
|
||||
|
||||
class SymTable
|
||||
|
@ -18,16 +21,30 @@ namespace zn
|
|||
explicit SymTable();
|
||||
virtual ~SymTable();
|
||||
|
||||
void declare(std::string const& name, size_t addr);
|
||||
int scope() const { return m_scope; }
|
||||
size_t size() const { return m_syms.size(); }
|
||||
|
||||
void prepare(std::string const& name, Type type);
|
||||
void declare(std::string const& name,
|
||||
size_t addr,
|
||||
int scope);
|
||||
|
||||
void declare_function(std::string const& name,
|
||||
size_t addr,
|
||||
std::shared_ptr<Prototype> prototype);
|
||||
|
||||
std::optional<Sym> find(std::string const& name);
|
||||
std::optional<Sym> find_any(std::string const& name);
|
||||
|
||||
size_t gen_addr();
|
||||
|
||||
void enter_scope();
|
||||
void leave_scope();
|
||||
|
||||
std::string string() const;
|
||||
private:
|
||||
std::vector<Sym> m_syms;
|
||||
int m_scope = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
44
src/VM.cpp
44
src/VM.cpp
|
@ -35,8 +35,14 @@ namespace zn
|
|||
} break;
|
||||
|
||||
case OPCODE_LOAD_LOCAL: {
|
||||
auto constant = frame().locals[to_vm_addr(param)];
|
||||
push(program.add_constant(constant));
|
||||
auto constant = load_local(param);
|
||||
size_t addr = program.add_constant(constant);
|
||||
push(addr);
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OPCODE_STORE_LOCAL: {
|
||||
store_local(param, frame().program.constant(top()));
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
|
@ -97,17 +103,14 @@ namespace zn
|
|||
|
||||
size_t VM::store_local(int index, std::shared_ptr<Constant> constant)
|
||||
{
|
||||
frame().locals.push_back(constant);
|
||||
frame().locals[index] = constant;
|
||||
size_t addr = frame().locals.size() - 1;
|
||||
m_addr_mapping[index] = addr;
|
||||
return addr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Constant> VM::load_local(int index) const
|
||||
{
|
||||
size_t addr = to_vm_addr(index);
|
||||
assert(addr < m_frames.back().locals.size());
|
||||
return m_frames.back().locals[addr];
|
||||
return m_frames.back().locals.at(index);
|
||||
}
|
||||
|
||||
size_t VM::store_global(global_var_t var)
|
||||
|
@ -116,26 +119,6 @@ namespace zn
|
|||
return m_globals.size() - 1;
|
||||
}
|
||||
|
||||
size_t VM::to_vm_addr(int user_addr) const
|
||||
{
|
||||
return m_addr_mapping.at(user_addr);
|
||||
}
|
||||
|
||||
int VM::to_user_addr(size_t vm_addr) const
|
||||
{
|
||||
for (auto const& entry: m_addr_mapping)
|
||||
{
|
||||
if (entry.second == vm_addr)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "cannot find user addr of '"
|
||||
<< vm_addr << "'" << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
Frame& VM::frame()
|
||||
{
|
||||
return m_frames.back();
|
||||
|
@ -153,4 +136,11 @@ namespace zn
|
|||
m_stack.pop_back();
|
||||
return value;
|
||||
}
|
||||
|
||||
int VM::top()
|
||||
{
|
||||
assert(m_stack.size() > 0);
|
||||
int value = m_stack.back();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace zn
|
|||
{
|
||||
struct Frame {
|
||||
Program& program;
|
||||
std::vector<std::shared_ptr<Constant>> locals;
|
||||
std::unordered_map<int, std::shared_ptr<Constant>> locals;
|
||||
};
|
||||
|
||||
using global_var_t = std::variant<std::shared_ptr<NativeFunction>>;
|
||||
|
@ -30,19 +30,16 @@ namespace zn
|
|||
|
||||
size_t store_global(global_var_t var);
|
||||
|
||||
size_t to_vm_addr(int user_addr) const;
|
||||
int to_user_addr(size_t vm_addr) const;
|
||||
|
||||
private:
|
||||
std::vector<Frame> m_frames;
|
||||
std::vector<int> m_stack;
|
||||
std::vector<global_var_t> m_globals;
|
||||
std::unordered_map<int, size_t> m_addr_mapping;
|
||||
size_t m_pc = 0;
|
||||
|
||||
Frame& frame();
|
||||
void push(int value);
|
||||
int pop();
|
||||
int top();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
25
src/Zarn.cpp
25
src/Zarn.cpp
|
@ -4,18 +4,19 @@
|
|||
|
||||
namespace zn
|
||||
{
|
||||
/*explicit*/ Zarn::Zarn(SymTable& sym, VM& vm)
|
||||
: m_sym { sym }
|
||||
/*explicit*/ Zarn::Zarn(Compiler& compiler, SymTable& sym, VM& vm)
|
||||
: m_compiler { compiler }
|
||||
, m_sym { sym }
|
||||
, m_vm { vm }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Zarn::~Zarn()
|
||||
{
|
||||
for (void* handler: m_handlers)
|
||||
{
|
||||
// dlclose(handler);
|
||||
}
|
||||
//for (void* handler: m_handlers)
|
||||
// {
|
||||
// // dlclose(handler);
|
||||
// }
|
||||
|
||||
m_handlers.clear();
|
||||
}
|
||||
|
@ -27,12 +28,16 @@ namespace zn
|
|||
auto func = std::make_shared<NativeFunction>(prototype, body);
|
||||
int addr = m_vm.store_global(func);
|
||||
m_sym.declare_function(name, addr, prototype);
|
||||
|
||||
// auto ref = std::make_shared<Constant>(TYPE_REF, addr);
|
||||
// m_vm.store_local(0, ref);
|
||||
// m_sym.declare_function(name, 0, prototype);
|
||||
}
|
||||
|
||||
void Zarn::register_macro(std::string const& name,
|
||||
native_macro_t macro)
|
||||
{
|
||||
auto m = std::make_shared<NativeMacro>(name, macro);
|
||||
m_compiler.add_macro(m);
|
||||
}
|
||||
|
||||
|
||||
void Zarn::load_std_library()
|
||||
{
|
||||
load_library(ZN_LIBDIR / "libzarn-std.so");
|
||||
|
|
|
@ -4,22 +4,27 @@
|
|||
#include "common.hpp"
|
||||
#include "SymTable.hpp"
|
||||
#include "VM.hpp"
|
||||
#include "NativeMacro.hpp"
|
||||
|
||||
namespace zn
|
||||
{
|
||||
class Zarn
|
||||
{
|
||||
public:
|
||||
explicit Zarn(SymTable& sym, VM& vm);
|
||||
explicit Zarn(Compiler& compiler, SymTable& sym, VM& vm);
|
||||
virtual ~Zarn();
|
||||
|
||||
void register_function(std::string const& name,
|
||||
std::shared_ptr<Prototype> prototype,
|
||||
native_fn_t body);
|
||||
|
||||
void register_macro(std::string const& name,
|
||||
native_macro_t macro);
|
||||
|
||||
void load_std_library();
|
||||
void load_library(std::filesystem::path lib_path);
|
||||
private:
|
||||
Compiler& m_compiler;
|
||||
SymTable& m_sym;
|
||||
VM& m_vm;
|
||||
std::vector<void*> m_handlers;
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#define TYPES(G) \
|
||||
G(TYPE_NIL), \
|
||||
G(TYPE_INT), \
|
||||
G(TYPE_REF)
|
||||
G(TYPE_REF), \
|
||||
G(TYPE_FUNCTION)
|
||||
|
||||
namespace zn
|
||||
{
|
||||
|
|
Reference in New Issue