Skip to content

Commit

Permalink
add more table support to bytecode / luafunction vm
Browse files Browse the repository at this point in the history
  • Loading branch information
meepen committed Jul 9, 2021
1 parent db85c3e commit 847ed9b
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 31 deletions.
62 changes: 61 additions & 1 deletion src/vm/bytecode/expressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ static void generate_functioncallexpression(bytecodegenerator &gen, node &_expr,
auto argsize = arglist.children.size();

for (int i = 0; i < arglist.children.size(); i++) {
auto &arg = arglist.children[i];
auto &arg = arglist.children[i];
if (dynamic_cast<expressions::varargexpression *>(arg.get()) && i == arglist.children.size() - 1) {
opcode = bytecode::instruction_opcode_CALLV;
argsize--;
Expand All @@ -304,6 +304,66 @@ static void generate_functioncallexpression(bytecodegenerator &gen, node &_expr,
}
}

static void populate_tablevalue(bytecode::tablevalue *val, bytecodegenerator &gen, node &_expr) {
if (auto numvalue = dynamic_cast<expressions::numberexpression *>(&_expr)) {
val->set_type(bytecode::tablevalue_valuetype_NUMBER);
val->set_index(gen.add(numvalue->data));
}
else if (auto strvalue = dynamic_cast<expressions::stringexpression *>(&_expr)) {
val->set_type(bytecode::tablevalue_valuetype_STRING);
val->set_index(gen.add(strvalue->data));
}
else if (auto strvalue = dynamic_cast<expressions::trueexpression *>(&_expr)) {
val->set_type(bytecode::tablevalue_valuetype_CONSTANT);
val->set_index(0);
}
else if (auto strvalue = dynamic_cast<expressions::falseexpression *>(&_expr)) {
val->set_type(bytecode::tablevalue_valuetype_CONSTANT);
val->set_index(1);
}
else if (auto strvalue = dynamic_cast<expressions::nilexpression *>(&_expr)) {
val->set_type(bytecode::tablevalue_valuetype_CONSTANT);
val->set_index(2);
}
else {
throw exception(string("cannot create tablevalue for ") + _expr.tostring());
}
}

static void generate_tableexpression(bytecodegenerator &gen, node &_expr, std::uint32_t target, std::uint32_t size) {
auto obj = *dynamic_cast<expressions::tableexpression *>(&_expr);
auto bcid = gen.curfunc.proto->tables_size();
gen.emit(bytecode::instruction_opcode_TABLE, target, bcid);
auto bcobj = gen.curfunc.proto->add_tables();
for (auto &hashpart : obj.hashpart) {
auto bckv = bcobj->add_hashpart();
auto key = new bytecode::tablevalue;
try {
populate_tablevalue(key, gen, *hashpart.first.get());
}
catch (std::exception &e) {
delete key;
throw;
}

bckv->set_allocated_key(key);
auto value = new bytecode::tablevalue;
try {
populate_tablevalue(value, gen, *hashpart.second.get());
}
catch (std::exception &e) {
delete value;
throw;
}
bckv->set_allocated_value(value);
}

for (auto &arraypart : obj.arraypart) {
auto bcarraypart = bcobj->add_arraypart();
populate_tablevalue(bcarraypart, gen, *arraypart.get());
}
}


#define ADD(x) { typeid(expressions::x), generate_##x }
std::unordered_map<std::type_index, expressiongenerator> bytecode::expressionmap = {
Expand Down
10 changes: 5 additions & 5 deletions src/vm/proto/src/bytecode.proto
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ message instruction {
}

opcode op = 1;
optional uint32 a = 2;
optional uint32 b = 3;
optional uint32 c = 4;
uint32 a = 2;
uint32 b = 3;
uint32 c = 4;
}

message tablevalue {
Expand All @@ -77,7 +77,7 @@ message tablevalue {
FUNCTION = 4;
}
valuetype type = 1;
optional uint32 index = 2;
uint32 index = 2;
}

message hashpartvalue {
Expand Down Expand Up @@ -105,5 +105,5 @@ message prototype {

uint32 stacksize = 8;

optional string identifier = 6;
string identifier = 6;
}
34 changes: 25 additions & 9 deletions src/vm/software/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace lorelai {
return std::hash<uintptr_t>()(reinterpret_cast<uintptr_t>(this));
}

virtual string tostring(softwarestate &state) {
virtual string tostring(softwarestate &state) const {
return typenames[_typeid()];
}

Expand All @@ -45,6 +45,7 @@ namespace lorelai {
virtual bool LORELAI_SOFTWARE_DEFAULT_FUNCTION(rawget, softwarestate &state, object &out, const object &index)
virtual void LORELAI_SOFTWARE_DEFAULT_FUNCTION(rawset, softwarestate &state, const object &index, const object &data)
virtual state::_retdata LORELAI_SOFTWARE_DEFAULT_FUNCTION(call, softwarestate &state, int nargs, int nrets)
virtual void LORELAI_SOFTWARE_DEFAULT_FUNCTION(setindex, softwarestate &state, object &key, object &value)

void LORELAI_SOFTWARE_DEFAULT_FUNCTION(length, softwarestate &state, object &out)
bool LORELAI_SOFTWARE_DEFAULT_FUNCTION(lessthan, softwarestate &state, object &rhs);
Expand Down Expand Up @@ -100,7 +101,6 @@ namespace lorelai {
}

public:

LORELAI_INLINE void set(referenceobject &ref) {
type = TABLE;
raw.ref = &ref;
Expand Down Expand Up @@ -136,10 +136,6 @@ namespace lorelai {
return false;
}

if (type >= TABLE) {
return raw.ref == other.raw.ref;
}

switch (type) {
case NUMBER:
return raw.num == other.raw.num;
Expand All @@ -148,7 +144,7 @@ namespace lorelai {
case NIL:
return true;
default:
throw;
return raw.ref == other.raw.ref;
}
}

Expand Down Expand Up @@ -310,6 +306,15 @@ namespace lorelai {

return raw.ref->index(state, out, index);
}

void setindex (softwarestate &state, object &key, object &value) {
if (type < TABLE) {
throw exception(string("NYI: cannot setindex ") + gettypename());
}

return raw.ref->setindex(state, key, value);
}

state::_retdata call (softwarestate &state, int nargs, int nrets) {
if (type < TABLE) {
throw exception(string("NYI: cannot call ") + gettypename());
Expand All @@ -332,7 +337,7 @@ namespace lorelai {
convertexception("number");
}

inline string tostring (softwarestate &state) {
inline string tostring (softwarestate &state) const {
switch (type) {
case NIL:
return "nil";
Expand Down Expand Up @@ -426,7 +431,7 @@ namespace lorelai {
return lorelai::tonumber(str);
}

string tostring(softwarestate &state) override {
string tostring(softwarestate &state) const override {
return str;
}

Expand All @@ -445,6 +450,11 @@ namespace lorelai {
};

class luafunctionobject : public functionobject {
struct tabledata {
std::vector<std::pair<bytecode::tablevalue, bytecode::tablevalue>> hashpart;
std::vector<bytecode::tablevalue> arraypart;
};
void fromtablevalue(object &out, const bytecode::tablevalue &data);
public:
static object create(softwarestate &state, std::shared_ptr<bytecode::prototype> proto);

Expand All @@ -466,6 +476,7 @@ namespace lorelai {
std::uint32_t stacksize;
std::vector<object> strings;
std::vector<object> numbers;
std::vector<tabledata> tables;
};

class cfunctionobject : public functionobject {
Expand Down Expand Up @@ -519,6 +530,11 @@ namespace lorelai {
}
}


void setindex(softwarestate &state, object &key, object &value) override {
rawset(state, key, value);
}

public:
object _metatable;
std::unordered_map<object, object> data;
Expand Down
69 changes: 67 additions & 2 deletions src/vm/software/types/luafunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <exception>
#include <string>
#include <memory>
#include <iostream>

using namespace lorelai;
using namespace lorelai::vm;
Expand All @@ -16,6 +17,35 @@ struct luafunctionobject::instruction {
std::uint32_t c;
};

void luafunctionobject::fromtablevalue(object &out, const bytecode::tablevalue &data) {
switch (data.type()) {
case bytecode::tablevalue_valuetype_CONSTANT:
switch (data.index()) {
case 0:
out.set(true);
break;
case 1:
out.set(false);
break;
default:
out.set();
break;
}
break;

case bytecode::tablevalue_valuetype_NUMBER:
out.set(numbers[data.index()]);
break;

case bytecode::tablevalue_valuetype_STRING:
out.set(strings[data.index()]);
break;

default:
throw exception("unsupported type in table");
}
}


state::_retdata luafunctionobject::call(softwarestate &state, int nrets, int nargs) {
int multres = 0;
Expand Down Expand Up @@ -125,6 +155,9 @@ state::_retdata luafunctionobject::call(softwarestate &state, int nrets, int nar
vmcase (INDEX)
stackptr[instr->b].index(state, stackptr[instr->a], stackptr[instr->c]);
vmbreak;
vmcase (SETINDEX)
stackptr[instr->a].setindex(state, stackptr[instr->b], stackptr[instr->c]);
vmbreak;
vmcase (NOT)
stackptr[instr->a].set(!stackptr[instr->b].tobool(state));
vmbreak;
Expand Down Expand Up @@ -164,8 +197,27 @@ state::_retdata luafunctionobject::call(softwarestate &state, int nrets, int nar
vmcase (DIVIDE)
stackptr[instr->b].divide(state, stackptr[instr->a], stackptr[instr->c]);
vmbreak;
vmcase (TABLE) {
auto tbl = tableobject::create(state);
auto &tmplate = tables[instr->b];
for (auto &kv : tmplate.hashpart) {
object key;
object value;
fromtablevalue(key, kv.first);
fromtablevalue(value, kv.second);
tbl.rawset(state, key, value);
}
int i = 0;
for (auto &arr : tmplate.arraypart) {
object val;
fromtablevalue(val, arr);
tbl.rawset(state, static_cast<double>(++i), val);
}
stackptr[instr->a].set(tbl);
vmbreak;
}
default:
throw exception(string("opcode not implemented: ") + bytecode::instruction_opcode_Name(instr->opcode));
throw exception(string("opcode not implemented: ") + bytecode::instruction_opcode_Name(static_cast<bytecode::instruction_opcode>(instr->opcode)));
}
}

Expand All @@ -176,7 +228,7 @@ object luafunctionobject::create(softwarestate &state, std::shared_ptr<bytecode:
luafunctionobject::luafunctionobject(softwarestate &state, std::shared_ptr<bytecode::prototype> proto) {
auto oob = proto->instructions_size();
size = oob + 1;
allocated = std::shared_ptr<instruction>(new instruction[oob], std::default_delete<instruction[]>());
allocated = std::shared_ptr<instruction>(new instruction[size], std::default_delete<instruction[]>());
allocated.get()[oob] = {
bytecode::instruction_opcode_RETURN,
0,
Expand Down Expand Up @@ -228,6 +280,19 @@ luafunctionobject::luafunctionobject(softwarestate &state, std::shared_ptr<bytec
numbers.push_back(object(proto->numbers(i)));
}

for (int i = 0; i < proto->tables_size(); i++) {
auto &tbl = proto->tables(i);
tabledata data;
for (int j = 0; j < tbl.hashpart_size(); j++) {
auto &hashpart = tbl.hashpart(j);
data.hashpart.push_back(std::make_pair(hashpart.key(), hashpart.value()));
}
for (int j = 0; j < tbl.arraypart_size(); j++) {
data.arraypart.push_back(tbl.arraypart(j));
}
tables.push_back(data);
}

stacksize = proto->stacksize();
}

Expand Down
12 changes: 1 addition & 11 deletions tests/runtime/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,7 @@ static void printproto(lorelai::bytecode::prototype &bytecode) {

std::cout << "#" << index << std::string(max_index.size() - index.size() + 1, ' ') << "| " << instrname << std::string(longest - instrname.size(), ' ') << "| ";

if (instruct.has_a()) {
std::cout << instruct.a();
if (instruct.has_b()) {
std::cout << ", " << instruct.b();
if (instruct.has_c()) {
std::cout << ", " << instruct.c();
}
}
}

std::cout << std::endl;
std::cout << instruct.a() << ", " << instruct.b() << ", " << instruct.c() << std::endl;
}
}

Expand Down
7 changes: 4 additions & 3 deletions tests/test.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local t = {}
t.a = 1
local t = {1, [false] = true, [true] = false}

print(t.a)
t.a = "lmao"

print(t[1], t[true], t[false], t.a)

0 comments on commit 847ed9b

Please sign in to comment.