ADD: var declaration and blocks.
parent
3eefed351c
commit
14e693c946
|
@ -0,0 +1,24 @@
|
|||
($ a 2)
|
||||
|
||||
(:
|
||||
(assert= 2 a)
|
||||
($ a 3)
|
||||
(assert= 3 a)
|
||||
|
||||
(:
|
||||
($ a 7)
|
||||
(assert= 7 a)
|
||||
(assert-static-fail ($ a 2))
|
||||
)
|
||||
|
||||
(assert= 3 a)
|
||||
)
|
||||
|
||||
(assert= 2 a)
|
||||
|
||||
($ b (: 2 6 9))
|
||||
|
||||
(assert= 9 b)
|
||||
|
||||
($ c (: 1 2 (: 3 4 (: 5 6 7))))
|
||||
(assert= 7 c)
|
|
@ -0,0 +1,10 @@
|
|||
(assert-static-fail a)
|
||||
($ a 12)
|
||||
(assert-static-fail ($ a 3))
|
||||
|
||||
($ b 13)
|
||||
($ c a)
|
||||
|
||||
(assert= 12 a)
|
||||
(assert= 13 b)
|
||||
(assert= 12 c)
|
|
@ -8,4 +8,6 @@ extern "C" void lib(Module& mod)
|
|||
mod.register_function("println", fkstd::println);
|
||||
|
||||
mod.register_macro("assert-static-fail", fkstd::assert_static_fail);
|
||||
mod.register_macro(":", fkstd::block);
|
||||
mod.register_macro("$", fkstd::decl);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,44 @@ namespace fkstd
|
|||
ss << "assertion failed";
|
||||
node->loc().error<assert_error>(LOG_ERROR, ss.str());
|
||||
}
|
||||
|
||||
void decl(Compiler& compiler,
|
||||
std::shared_ptr<Node> node,
|
||||
std::shared_ptr<Program> program)
|
||||
{
|
||||
static addr_t addr = 0;
|
||||
addr++;
|
||||
|
||||
std::string ident = node->child(1)->repr();
|
||||
auto rhs = node->child(2);
|
||||
|
||||
compiler.compile_prog(rhs, program);
|
||||
|
||||
compiler.sym()->declare_local(ident,
|
||||
addr,
|
||||
node->loc());
|
||||
|
||||
program->add(OP_STORE_LOCAL, addr);
|
||||
}
|
||||
|
||||
void block(Compiler& compiler,
|
||||
std::shared_ptr<Node> node,
|
||||
std::shared_ptr<Program> program)
|
||||
{
|
||||
compiler.sym()->enter_scope();
|
||||
|
||||
for (size_t i=1; i<node->size(); i++)
|
||||
{
|
||||
compiler.compile_prog(node->child(i), program);
|
||||
|
||||
if (i != node->size() - 1)
|
||||
{
|
||||
program->add(OP_POP);
|
||||
}
|
||||
}
|
||||
|
||||
compiler.sym()->leave_scope();
|
||||
|
||||
// std::cout << compiler.sym()->string() << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,15 @@ namespace fkstd
|
|||
void assert_static_fail(Compiler& compiler,
|
||||
std::shared_ptr<Node> node,
|
||||
std::shared_ptr<Program> program);
|
||||
|
||||
void decl(Compiler& compiler,
|
||||
std::shared_ptr<Node> node,
|
||||
std::shared_ptr<Program> program);
|
||||
|
||||
void block(Compiler& compiler,
|
||||
std::shared_ptr<Node> node,
|
||||
std::shared_ptr<Program> program);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,10 +72,12 @@ namespace fk
|
|||
|
||||
if (!entry->is_global())
|
||||
{
|
||||
throw std::runtime_error { "not implemented yet" };
|
||||
prog->add(OP_LOAD_LOCAL, entry->addr());
|
||||
}
|
||||
else
|
||||
{
|
||||
prog->add(OP_LOAD_GLOBAL, entry->addr());
|
||||
}
|
||||
|
||||
prog->add(OP_LOAD_GLOBAL, entry->addr());
|
||||
|
||||
} break;
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace fk
|
|||
explicit Compiler(std::shared_ptr<SymTable> sym);
|
||||
virtual ~Compiler();
|
||||
|
||||
std::shared_ptr<SymTable> sym() const { return m_sym; }
|
||||
|
||||
void add_macro(std::string const& name,
|
||||
std::shared_ptr<NativeMacro> macro);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "Parser.hpp"
|
||||
#include "src/Loc.hpp"
|
||||
#include "src/Node.hpp"
|
||||
|
||||
namespace fk
|
||||
{
|
||||
|
@ -48,7 +49,12 @@ namespace fk
|
|||
|
||||
std::shared_ptr<Node> Parser::parse_expr()
|
||||
{
|
||||
if (type_any({NODE_INT, NODE_FLOAT, NODE_BOOL, NODE_STRING}))
|
||||
if (type_any({
|
||||
NODE_INT,
|
||||
NODE_FLOAT,
|
||||
NODE_BOOL,
|
||||
NODE_STRING,
|
||||
NODE_IDENT}))
|
||||
{
|
||||
return consume();
|
||||
}
|
||||
|
|
|
@ -5,10 +5,14 @@ namespace fk
|
|||
/*explicit*/ SymEntry::SymEntry(std::string const& name,
|
||||
addr_t addr,
|
||||
bool is_global,
|
||||
int scope,
|
||||
std::shared_ptr<Node> parent,
|
||||
Loc const& loc)
|
||||
: m_name { name }
|
||||
, m_addr { addr }
|
||||
, m_is_global { is_global }
|
||||
, m_scope { scope }
|
||||
, m_parent { parent }
|
||||
, m_loc { loc }
|
||||
{
|
||||
}
|
||||
|
@ -20,7 +24,7 @@ namespace fk
|
|||
std::string SymEntry::string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_name << "\t" << m_addr << "\t" << m_is_global;
|
||||
ss << m_name << "\t" << m_addr << "\t" << m_is_global << "\t" << m_scope;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,21 +6,28 @@
|
|||
|
||||
namespace fk
|
||||
{
|
||||
class Node;
|
||||
|
||||
class SymEntry
|
||||
{
|
||||
public:
|
||||
explicit SymEntry(std::string const& name,
|
||||
addr_t addr,
|
||||
bool is_global,
|
||||
int scope,
|
||||
std::shared_ptr<Node> parent,
|
||||
Loc const& loc);
|
||||
virtual ~SymEntry();
|
||||
|
||||
std::string name() const { return m_name; }
|
||||
addr_t addr() const { return m_addr; }
|
||||
bool is_global() const { return m_is_global; }
|
||||
int scope() const { return m_scope; }
|
||||
std::shared_ptr<Node> parent() const { return m_parent; }
|
||||
Loc loc() const { return m_loc; }
|
||||
|
||||
void set_global(bool global) { m_is_global = global; }
|
||||
void set_addr(addr_t addr) { m_addr = addr; }
|
||||
|
||||
std::string string() const;
|
||||
|
||||
|
@ -28,6 +35,8 @@ namespace fk
|
|||
std::string m_name;
|
||||
addr_t m_addr;
|
||||
bool m_is_global = false;
|
||||
int m_scope;
|
||||
std::shared_ptr<Node> m_parent;
|
||||
Loc m_loc;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace fk
|
|||
{
|
||||
auto entry = find(name);
|
||||
|
||||
if (entry)
|
||||
if (entry && entry->scope() == m_scope)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "cannot declare existing variable '"
|
||||
|
@ -27,7 +27,7 @@ namespace fk
|
|||
entry->loc().error<symbol_error>(LOG_ERROR, ss.str());
|
||||
}
|
||||
|
||||
m_entries.push_back(SymEntry {name, addr, false, loc});
|
||||
m_entries.push_back(SymEntry {name, addr, false, m_scope, nullptr, loc});
|
||||
}
|
||||
|
||||
void SymTable::declare_global(std::string const& name,
|
||||
|
@ -40,15 +40,20 @@ namespace fk
|
|||
|
||||
std::optional<SymEntry> SymTable::find(std::string const& name)
|
||||
{
|
||||
std::optional<SymEntry> result;
|
||||
|
||||
for (auto& entry: m_entries)
|
||||
{
|
||||
if (entry.name() == name)
|
||||
if (entry.name() == name
|
||||
&& entry.scope() <= m_scope
|
||||
&& (result == std::nullopt ||
|
||||
entry.scope() > result->scope()))
|
||||
{
|
||||
return entry;
|
||||
result = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string SymTable::string() const
|
||||
|
@ -56,6 +61,9 @@ namespace fk
|
|||
std::stringstream ss;
|
||||
|
||||
ss << "======== SymTable ========\n";
|
||||
ss << std::setw(8) << std::left;
|
||||
ss << "name\taddr\tglobal\tscope" << std::endl;
|
||||
|
||||
for (auto const& entry: m_entries)
|
||||
{
|
||||
ss << entry.string() << std::endl;
|
||||
|
@ -63,4 +71,14 @@ namespace fk
|
|||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void SymTable::enter_scope()
|
||||
{
|
||||
m_scope++;
|
||||
}
|
||||
|
||||
void SymTable::leave_scope()
|
||||
{
|
||||
m_scope--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,12 @@ namespace fk
|
|||
|
||||
std::string string() const;
|
||||
|
||||
void enter_scope();
|
||||
void leave_scope();
|
||||
|
||||
private:
|
||||
std::vector<SymEntry> m_entries;
|
||||
int m_scope;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
29
src/VM.cpp
29
src/VM.cpp
|
@ -30,8 +30,10 @@ namespace fk
|
|||
|
||||
for (size_t i=0; i<instr.param; i++)
|
||||
{
|
||||
addr_t addr = pop();
|
||||
|
||||
args.insert(std::begin(args),
|
||||
frame().program->get_const(pop()));
|
||||
frame().program->get_const(addr));
|
||||
}
|
||||
|
||||
auto ref = std::get<size_t>(frame().program
|
||||
|
@ -44,6 +46,21 @@ namespace fk
|
|||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_LOAD_LOCAL: {
|
||||
auto value = frame().locals[instr.param];
|
||||
assert(value);
|
||||
push(frame().program->add(value));
|
||||
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_STORE_LOCAL: {
|
||||
auto value = frame().program->get_const(top());
|
||||
assert(value);
|
||||
frame().locals[instr.param] = value;
|
||||
m_pc++;
|
||||
} break;
|
||||
|
||||
case OP_LOAD_GLOBAL: {
|
||||
auto ref = std::make_shared<Constant>(TYPE_REF,
|
||||
(size_t) instr.param,
|
||||
|
@ -89,6 +106,16 @@ namespace fk
|
|||
return addr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Constant> VM::load_local(addr_t addr)
|
||||
{
|
||||
return frame().locals[addr];
|
||||
}
|
||||
|
||||
void VM::store_local(addr_t addr, std::shared_ptr<Constant> constant)
|
||||
{
|
||||
frame().locals[addr] = constant;
|
||||
}
|
||||
|
||||
std::string VM::string() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace fk
|
|||
|
||||
struct Frame {
|
||||
std::shared_ptr<Program> program;
|
||||
std::unordered_map<addr_t, std::shared_ptr<Constant>> locals;
|
||||
};
|
||||
|
||||
class VM
|
||||
|
@ -19,7 +20,7 @@ namespace fk
|
|||
explicit VM();
|
||||
virtual ~VM();
|
||||
|
||||
Frame frame() const { return m_frames.back(); }
|
||||
Frame& frame() { return m_frames.back(); }
|
||||
|
||||
void mount(std::shared_ptr<Program> program);
|
||||
void run();
|
||||
|
@ -28,6 +29,9 @@ namespace fk
|
|||
void store_global(addr_t addr, global_t value);
|
||||
size_t store_global(global_t value);
|
||||
|
||||
std::shared_ptr<Constant> load_local(addr_t addr);
|
||||
void store_local(addr_t addr, std::shared_ptr<Constant> constant);
|
||||
|
||||
std::string string() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define fk_OPCODES_HPP
|
||||
|
||||
#define OPCODES(G) G(OP_LOAD_CONST), G(OP_POP), G(OP_CALL_NATIVE), \
|
||||
G(OP_LOAD_GLOBAL)
|
||||
G(OP_LOAD_GLOBAL), G(OP_LOAD_LOCAL), G(OP_STORE_LOCAL)
|
||||
|
||||
#include "commons.hpp"
|
||||
|
||||
|
|
|
@ -14,16 +14,5 @@ protected:
|
|||
|
||||
TEST_CASE_METHOD(SymTableTest, "SymTable_declare_var")
|
||||
{
|
||||
REQUIRE(std::nullopt == m_sym.find("hello"));
|
||||
|
||||
m_sym.declare_local("hello", 404, m_loc);
|
||||
auto entry = m_sym.find("hello");
|
||||
|
||||
REQUIRE(std::nullopt != entry);
|
||||
REQUIRE("hello" == entry->name());
|
||||
REQUIRE(404 == entry->addr());
|
||||
REQUIRE(false == entry->is_global());
|
||||
|
||||
REQUIRE_THROWS_AS(m_sym.declare_local("hello", 407, m_loc),
|
||||
fk::symbol_error);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue