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
|
#define COMMON_HPP
|
||||||
|
|
||||||
#include "../src/Zarn.hpp"
|
#include "../src/Zarn.hpp"
|
||||||
|
#include "../src/Module.hpp"
|
||||||
|
|
||||||
using namespace zn;
|
using namespace zn;
|
||||||
|
|
||||||
#define STDARGS std::vector<std::shared_ptr<Constant>>
|
#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 "common.hpp"
|
||||||
#include "fun.hpp"
|
#include "fun.hpp"
|
||||||
|
#include "macro.hpp"
|
||||||
|
#include "../src/types.hpp"
|
||||||
|
|
||||||
extern "C" void lib(Zarn& zarn)
|
extern "C" void lib(Zarn& zarn)
|
||||||
{
|
{
|
||||||
|
@ -16,4 +18,8 @@ extern "C" void lib(Zarn& zarn)
|
||||||
->param_any()
|
->param_any()
|
||||||
->ret(TYPE_NIL),
|
->ret(TYPE_NIL),
|
||||||
assert_eq);
|
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/SymTable.cpp',
|
||||||
'src/NativeFunction.cpp',
|
'src/NativeFunction.cpp',
|
||||||
'src/Prototype.cpp',
|
'src/Prototype.cpp',
|
||||||
|
'src/NativeMacro.cpp',
|
||||||
'src/Zarn.cpp',
|
'src/Zarn.cpp',
|
||||||
],
|
],
|
||||||
install: true)
|
install: true)
|
||||||
|
@ -49,6 +50,7 @@ shared_library('zarn-std',
|
||||||
sources: [
|
sources: [
|
||||||
'libstd/std.cpp',
|
'libstd/std.cpp',
|
||||||
'libstd/fun.cpp',
|
'libstd/fun.cpp',
|
||||||
|
'libstd/macro.cpp',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
zarn_dep
|
zarn_dep
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
#include "Compiler.hpp"
|
#include "Compiler.hpp"
|
||||||
#include "src/Node.hpp"
|
#include "Module.hpp"
|
||||||
#include "src/Program.hpp"
|
#include "Node.hpp"
|
||||||
|
#include "Program.hpp"
|
||||||
|
#include "NativeMacro.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
/*explicit*/ Compiler::Compiler(Logger& logger, SymTable& sym)
|
/*explicit*/ Compiler::Compiler(Module& mod,
|
||||||
: m_logger { logger }
|
Logger& logger,
|
||||||
|
SymTable& sym)
|
||||||
|
: m_mod { mod }
|
||||||
|
, m_logger { logger }
|
||||||
, m_sym { sym }
|
, 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)
|
void Compiler::compile(Node const& node, Program& program)
|
||||||
{
|
{
|
||||||
switch (node.type())
|
switch (node.type())
|
||||||
|
@ -31,12 +41,44 @@ namespace zn
|
||||||
// FUNCTION STUFF
|
// FUNCTION STUFF
|
||||||
// ==============
|
// ==============
|
||||||
case NODE_CALL: {
|
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++)
|
for (size_t i=0; i<node.size(); i++)
|
||||||
{
|
{
|
||||||
compile(*node.child_at(i), program);
|
compile(*node.child_at(i), program);
|
||||||
}
|
}
|
||||||
|
|
||||||
program.append(OPCODE_CALL_NATIVE, node.size() - 1);
|
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;
|
} break;
|
||||||
|
|
||||||
// VALUES
|
// VALUES
|
||||||
|
@ -44,19 +86,30 @@ namespace zn
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
std::string ident = node.repr();
|
std::string ident = node.repr();
|
||||||
auto sym = m_sym.find(ident);
|
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)
|
if (sym->prototype)
|
||||||
{
|
{
|
||||||
auto ref = std::make_shared<Constant>(TYPE_REF,
|
auto ref = std::make_shared<Constant>(TYPE_REF,
|
||||||
node.loc(),
|
node.loc(),
|
||||||
(int) sym->addr);
|
(int) *sym->addr);
|
||||||
size_t val = program.add_constant(ref);
|
size_t val = program.add_constant(ref);
|
||||||
program.append(OPCODE_LOAD_CONST, val);
|
program.append(OPCODE_LOAD_CONST, val);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
program.append(OPCODE_LOAD_LOCAL, sym->addr);
|
program.append(OPCODE_LOAD_LOCAL, *sym->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -11,17 +11,23 @@ namespace zn
|
||||||
{
|
{
|
||||||
ZN_ERROR(compile_error);
|
ZN_ERROR(compile_error);
|
||||||
|
|
||||||
|
class NativeMacro;
|
||||||
|
class Module;
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Compiler(Logger& logger, SymTable& sym);
|
explicit Compiler(Module& mod, Logger& logger, SymTable& sym);
|
||||||
virtual ~Compiler();
|
virtual ~Compiler();
|
||||||
|
|
||||||
|
void add_macro(std::shared_ptr<NativeMacro> macro);
|
||||||
void compile(Node const& node, Program& program);
|
void compile(Node const& node, Program& program);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Module& m_mod;
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
SymTable& m_sym;
|
SymTable& m_sym;
|
||||||
|
std::vector<std::shared_ptr<NativeMacro>> m_macros;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,10 @@ namespace zn
|
||||||
{
|
{
|
||||||
case TYPE_NIL: return "<nil>";
|
case TYPE_NIL: return "<nil>";
|
||||||
case TYPE_INT: return std::to_string(std::get<int>(*m_value));
|
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: {
|
default: {
|
||||||
std::cerr << "cannot stringify "
|
std::cerr << "cannot stringify "
|
||||||
<< (TypeStr[m_type] + strlen("TYPE_"))
|
<< (TypeStr[m_type] + strlen("TYPE_"))
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
|
#include "Zarn.hpp"
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
|
@ -48,11 +49,8 @@ namespace zn
|
||||||
|
|
||||||
m_zarn.load_std_library();
|
m_zarn.load_std_library();
|
||||||
|
|
||||||
StaticPass static_pass { m_logger, m_sym };
|
m_static_pass.execute(*ast);
|
||||||
static_pass.execute(*ast);
|
m_compiler.compile(*ast, m_program);
|
||||||
|
|
||||||
Compiler compiler { m_logger, m_sym };
|
|
||||||
compiler.compile(*ast, m_program);
|
|
||||||
|
|
||||||
m_vm.execute(m_program);
|
m_vm.execute(m_program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
|
#include "StaticPass.hpp"
|
||||||
|
#include "Compiler.hpp"
|
||||||
#include "Zarn.hpp"
|
#include "Zarn.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
|
@ -18,6 +20,12 @@ namespace zn
|
||||||
explicit Module(Logger& logger);
|
explicit Module(Logger& logger);
|
||||||
virtual ~Module();
|
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);
|
void load_from_file(std::filesystem::path file_path);
|
||||||
|
|
||||||
std::string string() const;
|
std::string string() const;
|
||||||
|
@ -27,7 +35,9 @@ namespace zn
|
||||||
Program m_program;
|
Program m_program;
|
||||||
VM m_vm { m_program };
|
VM m_vm { m_program };
|
||||||
SymTable m_sym;
|
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: {
|
case NODE_CALL: {
|
||||||
std::string ident = node.child_at(0)->repr();
|
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)
|
if (sym == std::nullopt)
|
||||||
{
|
{
|
||||||
m_logger.log<static_error>(LOG_ERROR,
|
return TypeSlot {TYPE_NIL, TAG_ANY};
|
||||||
node.loc(),
|
|
||||||
"cannot call unknown function '"
|
|
||||||
+ ident
|
|
||||||
+ "'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto proto = sym->prototype;
|
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
|
if (proto->get_param_count() != node.size() - 1
|
||||||
&& proto->get_param(proto->get_param_count() - 1).tag
|
&& proto->get_param(proto->get_param_count() - 1).tag
|
||||||
|
@ -79,6 +93,19 @@ namespace zn
|
||||||
return proto->get_ret();
|
return proto->get_ret();
|
||||||
} break;
|
} 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: {
|
case NODE_INT: {
|
||||||
return TypeSlot {TYPE_INT};
|
return TypeSlot {TYPE_INT};
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace zn
|
||||||
virtual ~StaticPass();
|
virtual ~StaticPass();
|
||||||
|
|
||||||
TypeSlot execute(Node const& node);
|
TypeSlot execute(Node const& node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
SymTable& m_sym;
|
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,
|
void SymTable::declare_function(std::string const& name,
|
||||||
size_t addr,
|
size_t addr,
|
||||||
std::shared_ptr<Prototype> prototype)
|
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<Sym> SymTable::find(std::string const& name)
|
||||||
{
|
{
|
||||||
|
std::optional<size_t> best;
|
||||||
|
|
||||||
for (size_t i=0; i<m_syms.size(); i++)
|
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;
|
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 "common.hpp"
|
||||||
#include "Prototype.hpp"
|
#include "Prototype.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
struct Sym {
|
struct Sym {
|
||||||
std::string name;
|
std::string name;
|
||||||
size_t addr;
|
std::optional<size_t> addr;
|
||||||
|
Type type;
|
||||||
std::shared_ptr<Prototype> prototype = nullptr;
|
std::shared_ptr<Prototype> prototype = nullptr;
|
||||||
|
int scope = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SymTable
|
class SymTable
|
||||||
|
@ -18,16 +21,30 @@ namespace zn
|
||||||
explicit SymTable();
|
explicit SymTable();
|
||||||
virtual ~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,
|
void declare_function(std::string const& name,
|
||||||
size_t addr,
|
size_t addr,
|
||||||
std::shared_ptr<Prototype> prototype);
|
std::shared_ptr<Prototype> prototype);
|
||||||
|
|
||||||
std::optional<Sym> find(std::string const& name);
|
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:
|
private:
|
||||||
std::vector<Sym> m_syms;
|
std::vector<Sym> m_syms;
|
||||||
|
int m_scope = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
src/VM.cpp
44
src/VM.cpp
|
@ -35,8 +35,14 @@ namespace zn
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OPCODE_LOAD_LOCAL: {
|
case OPCODE_LOAD_LOCAL: {
|
||||||
auto constant = frame().locals[to_vm_addr(param)];
|
auto constant = load_local(param);
|
||||||
push(program.add_constant(constant));
|
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++;
|
m_pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -97,17 +103,14 @@ namespace zn
|
||||||
|
|
||||||
size_t VM::store_local(int index, std::shared_ptr<Constant> constant)
|
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;
|
size_t addr = frame().locals.size() - 1;
|
||||||
m_addr_mapping[index] = addr;
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Constant> VM::load_local(int index) const
|
std::shared_ptr<Constant> VM::load_local(int index) const
|
||||||
{
|
{
|
||||||
size_t addr = to_vm_addr(index);
|
return m_frames.back().locals.at(index);
|
||||||
assert(addr < m_frames.back().locals.size());
|
|
||||||
return m_frames.back().locals[addr];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t VM::store_global(global_var_t var)
|
size_t VM::store_global(global_var_t var)
|
||||||
|
@ -116,26 +119,6 @@ namespace zn
|
||||||
return m_globals.size() - 1;
|
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()
|
Frame& VM::frame()
|
||||||
{
|
{
|
||||||
return m_frames.back();
|
return m_frames.back();
|
||||||
|
@ -153,4 +136,11 @@ namespace zn
|
||||||
m_stack.pop_back();
|
m_stack.pop_back();
|
||||||
return value;
|
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 {
|
struct Frame {
|
||||||
Program& program;
|
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>>;
|
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 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:
|
private:
|
||||||
std::vector<Frame> m_frames;
|
std::vector<Frame> m_frames;
|
||||||
std::vector<int> m_stack;
|
std::vector<int> m_stack;
|
||||||
std::vector<global_var_t> m_globals;
|
std::vector<global_var_t> m_globals;
|
||||||
std::unordered_map<int, size_t> m_addr_mapping;
|
|
||||||
size_t m_pc = 0;
|
size_t m_pc = 0;
|
||||||
|
|
||||||
Frame& frame();
|
Frame& frame();
|
||||||
void push(int value);
|
void push(int value);
|
||||||
int pop();
|
int pop();
|
||||||
|
int top();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
src/Zarn.cpp
25
src/Zarn.cpp
|
@ -4,18 +4,19 @@
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
/*explicit*/ Zarn::Zarn(SymTable& sym, VM& vm)
|
/*explicit*/ Zarn::Zarn(Compiler& compiler, SymTable& sym, VM& vm)
|
||||||
: m_sym { sym }
|
: m_compiler { compiler }
|
||||||
|
, m_sym { sym }
|
||||||
, m_vm { vm }
|
, m_vm { vm }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ Zarn::~Zarn()
|
/*virtual*/ Zarn::~Zarn()
|
||||||
{
|
{
|
||||||
for (void* handler: m_handlers)
|
//for (void* handler: m_handlers)
|
||||||
{
|
// {
|
||||||
// dlclose(handler);
|
// // dlclose(handler);
|
||||||
}
|
// }
|
||||||
|
|
||||||
m_handlers.clear();
|
m_handlers.clear();
|
||||||
}
|
}
|
||||||
|
@ -27,12 +28,16 @@ namespace zn
|
||||||
auto func = std::make_shared<NativeFunction>(prototype, body);
|
auto func = std::make_shared<NativeFunction>(prototype, body);
|
||||||
int addr = m_vm.store_global(func);
|
int addr = m_vm.store_global(func);
|
||||||
m_sym.declare_function(name, addr, prototype);
|
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()
|
void Zarn::load_std_library()
|
||||||
{
|
{
|
||||||
load_library(ZN_LIBDIR / "libzarn-std.so");
|
load_library(ZN_LIBDIR / "libzarn-std.so");
|
||||||
|
|
|
@ -4,22 +4,27 @@
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "SymTable.hpp"
|
#include "SymTable.hpp"
|
||||||
#include "VM.hpp"
|
#include "VM.hpp"
|
||||||
|
#include "NativeMacro.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
class Zarn
|
class Zarn
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Zarn(SymTable& sym, VM& vm);
|
explicit Zarn(Compiler& compiler, SymTable& sym, VM& vm);
|
||||||
virtual ~Zarn();
|
virtual ~Zarn();
|
||||||
|
|
||||||
void register_function(std::string const& name,
|
void register_function(std::string const& name,
|
||||||
std::shared_ptr<Prototype> prototype,
|
std::shared_ptr<Prototype> prototype,
|
||||||
native_fn_t body);
|
native_fn_t body);
|
||||||
|
|
||||||
|
void register_macro(std::string const& name,
|
||||||
|
native_macro_t macro);
|
||||||
|
|
||||||
void load_std_library();
|
void load_std_library();
|
||||||
void load_library(std::filesystem::path lib_path);
|
void load_library(std::filesystem::path lib_path);
|
||||||
private:
|
private:
|
||||||
|
Compiler& m_compiler;
|
||||||
SymTable& m_sym;
|
SymTable& m_sym;
|
||||||
VM& m_vm;
|
VM& m_vm;
|
||||||
std::vector<void*> m_handlers;
|
std::vector<void*> m_handlers;
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
#define TYPES(G) \
|
#define TYPES(G) \
|
||||||
G(TYPE_NIL), \
|
G(TYPE_NIL), \
|
||||||
G(TYPE_INT), \
|
G(TYPE_INT), \
|
||||||
G(TYPE_REF)
|
G(TYPE_REF), \
|
||||||
|
G(TYPE_FUNCTION)
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
|
|
Reference in New Issue