ADD: vardecl.
parent
0aa9ebd952
commit
073cbb4618
|
@ -0,0 +1,7 @@
|
||||||
|
(assert-fail a)
|
||||||
|
($ a 34)
|
||||||
|
(assert= 34 a)
|
||||||
|
|
||||||
|
($ b ($ c 9))
|
||||||
|
(assert= 9 b)
|
||||||
|
(assert= 9 c)
|
|
@ -22,3 +22,18 @@ void assert_fail(Node const& node,
|
||||||
(TYPE_NIL, node.loc(), 0));
|
(TYPE_NIL, node.loc(), 0));
|
||||||
program.append(OPCODE_LOAD_CONST, addr);
|
program.append(OPCODE_LOAD_CONST, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void declare(Node const& node,
|
||||||
|
Compiler& compiler,
|
||||||
|
Program& program,
|
||||||
|
SymTable& sym)
|
||||||
|
{
|
||||||
|
std::string ident = node.child_at(1)->repr();
|
||||||
|
compiler.compile(*node.child_at(2), program);
|
||||||
|
auto entry = sym.find_any(ident);
|
||||||
|
assert(entry);
|
||||||
|
size_t addr = sym.gen_addr();
|
||||||
|
|
||||||
|
sym.declare(ident, addr);
|
||||||
|
program.append(OPCODE_STORE_LOCAL, addr);
|
||||||
|
}
|
||||||
|
|
|
@ -8,4 +8,9 @@ void assert_fail(Node const& node,
|
||||||
Program& program,
|
Program& program,
|
||||||
SymTable& sym);
|
SymTable& sym);
|
||||||
|
|
||||||
|
void declare(Node const& node,
|
||||||
|
Compiler& compiler,
|
||||||
|
Program& program,
|
||||||
|
SymTable& sym);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,4 +20,5 @@ extern "C" void lib(Zarn& zarn)
|
||||||
assert_eq);
|
assert_eq);
|
||||||
|
|
||||||
zarn.register_macro("assert-fail", assert_fail);
|
zarn.register_macro("assert-fail", assert_fail);
|
||||||
|
zarn.register_macro("$", declare);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,13 +100,13 @@ namespace zn
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
|
@ -27,7 +27,17 @@ 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));
|
||||||
|
//int index = m_sym.gen_addr();
|
||||||
|
m_sym.prepare(varname, *vartype.type);
|
||||||
|
|
||||||
|
return vartype;
|
||||||
|
}
|
||||||
|
|
||||||
if (sym == std::nullopt)
|
if (sym == std::nullopt)
|
||||||
{
|
{
|
||||||
|
@ -75,6 +85,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 == 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,19 +10,48 @@ namespace zn
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymTable::prepare(std::string const& name, Type type)
|
||||||
|
{
|
||||||
|
m_syms.push_back(Sym {name, std::nullopt, type});
|
||||||
|
}
|
||||||
|
|
||||||
void SymTable::declare(std::string const& name, size_t addr)
|
void SymTable::declare(std::string const& name, size_t addr)
|
||||||
{
|
{
|
||||||
m_syms.push_back(Sym {name, addr});
|
auto itr = std::find_if(std::begin(m_syms),
|
||||||
|
std::end(m_syms),
|
||||||
|
[name](auto const& sym){
|
||||||
|
return sym.name == name;
|
||||||
|
});
|
||||||
|
|
||||||
|
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});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Sym> SymTable::find(std::string const& name)
|
std::optional<Sym> SymTable::find(std::string const& name)
|
||||||
|
{
|
||||||
|
for (size_t i=0; i<m_syms.size(); i++)
|
||||||
|
{
|
||||||
|
if (name == m_syms[i].name && m_syms[i].addr != std::nullopt)
|
||||||
|
{
|
||||||
|
return m_syms[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Sym> SymTable::find_any(std::string const& name)
|
||||||
{
|
{
|
||||||
for (size_t i=0; i<m_syms.size(); i++)
|
for (size_t i=0; i<m_syms.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -34,4 +63,11 @@ namespace zn
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t SymTable::gen_addr()
|
||||||
|
{
|
||||||
|
static size_t addr = 0;
|
||||||
|
addr++;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +19,9 @@ namespace zn
|
||||||
explicit SymTable();
|
explicit SymTable();
|
||||||
virtual ~SymTable();
|
virtual ~SymTable();
|
||||||
|
|
||||||
|
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);
|
void declare(std::string const& name, size_t addr);
|
||||||
|
|
||||||
void declare_function(std::string const& name,
|
void declare_function(std::string const& name,
|
||||||
|
@ -25,6 +29,9 @@ namespace zn
|
||||||
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();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Sym> m_syms;
|
std::vector<Sym> m_syms;
|
||||||
|
|
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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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