feat: introduce array and get instruction
This commit is contained in:
@@ -25,6 +25,19 @@ enum class instruction_t : byte {
|
|||||||
*/
|
*/
|
||||||
PushConstant,
|
PushConstant,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes a new array onto the stack.
|
||||||
|
*
|
||||||
|
* Type is the next 4 bytes in little-endian.
|
||||||
|
* If the type is dynamic the array's size will be popped off of the stack.
|
||||||
|
*/
|
||||||
|
Array,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes an element from an array onto the stack.
|
||||||
|
*/
|
||||||
|
Get,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pops top element from the stack.
|
* @brief Pops top element from the stack.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -283,24 +283,39 @@ public:
|
|||||||
if (m_type->t != type_t::Array) throw bad_thing_access();
|
if (m_type->t != type_t::Array) throw bad_thing_access();
|
||||||
if (m_type->array.size > 0) throw std::runtime_error("cannot resize a static array");
|
if (m_type->array.size > 0) throw std::runtime_error("cannot resize a static array");
|
||||||
|
|
||||||
auto& list = get<array_t>();
|
auto& array = get<array_t>();
|
||||||
if (newSize < 0 || newSize == list.size) return;
|
if (newSize < 0 || newSize == array.dynamic.size) return;
|
||||||
std::size_t innerSize = compute_size_na(*m_type->array.type);
|
std::size_t innerSize = compute_size_na(*m_type->array.type);
|
||||||
std::byte* newData = new std::byte[innerSize * newSize];
|
std::byte* newData = new std::byte[innerSize * newSize];
|
||||||
std::memcpy(newData, list.data, innerSize * std::min(list.size, newSize));
|
std::memcpy(newData, array.dynamic.data, innerSize * std::min(array.dynamic.size, newSize));
|
||||||
list.size = newSize;
|
array.dynamic.size = newSize;
|
||||||
delete[] list.data;
|
delete[] array.dynamic.data;
|
||||||
list.data = newData;
|
array.dynamic.data = newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
thing at(long_t index) const {
|
thing at(long_t index) const {
|
||||||
if (m_type->t != type_t::Array) throw bad_thing_access();
|
if (m_type->t != type_t::Array) throw bad_thing_access();
|
||||||
auto& list = get<array_t>();
|
|
||||||
if (index < 0 || index >= list.size) throw std::out_of_range("index out of range");
|
std::size_t elementSize = compute_size_na(*m_type->array.type);
|
||||||
thing res = { std::make_shared<type>(m_type->array.type), m_modules, m_allocator };
|
thing res = { std::make_shared<class type>(*m_type->array.type), m_modules, m_allocator };
|
||||||
res.get<reference_t>() = list.data; // TODO: Account for padding, alignment and stuff
|
if (m_type->array.size == 0) {
|
||||||
|
auto& array = get<array_t>();
|
||||||
|
if (index < 0 || index >= array.dynamic.size) throw std::out_of_range("index out of range");
|
||||||
|
res.get<reference_t>() = array.dynamic.data + (index * elementSize);
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::byte* data = reinterpret_cast<array_t*>(m_data)->data;
|
||||||
|
if (index < 0 || index >= m_type->array.size) throw std::out_of_range("index out of range");
|
||||||
|
res.get<reference_t>() = data + (index * elementSize);
|
||||||
|
return std::move(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size() const {
|
||||||
|
if (m_type->t != type_t::Array) throw std::runtime_error("not an array");
|
||||||
|
if (m_type->array.size == 0) return get<array_t>().dynamic.size;
|
||||||
|
return m_type->array.size;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
static type_p resolve_type(const type_p& initType, const mod_container& modules) {
|
static type_p resolve_type(const type_p& initType, const mod_container& modules) {
|
||||||
type_p rsv = initType;
|
type_p rsv = initType;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
#include "furvm/instruction.hpp"
|
#include "furvm/instruction.hpp"
|
||||||
#include "furvm/thing.hpp"
|
#include "furvm/thing.hpp"
|
||||||
|
#include "furvm/type.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -94,6 +95,32 @@ void executor::step() {
|
|||||||
push_thing({ *m_context->at("core")->type_at(2), m_context, m_context->thing_alloc() })->get<int_t>() =
|
push_thing({ *m_context->at("core")->type_at(2), m_context, m_context->thing_alloc() })->get<int_t>() =
|
||||||
frame.mod->byte(frame.position++);
|
frame.mod->byte(frame.position++);
|
||||||
} break;
|
} break;
|
||||||
|
case instruction_t::Array: {
|
||||||
|
type_id typeId = static_cast<type_id>(frame.mod->byte(frame.position)) |
|
||||||
|
(static_cast<type_id>(frame.mod->byte(frame.position + 1)) << 8) |
|
||||||
|
(static_cast<type_id>(frame.mod->byte(frame.position + 2)) << 16) |
|
||||||
|
(static_cast<type_id>(frame.mod->byte(frame.position + 3)) << 24);
|
||||||
|
frame.position += 4;
|
||||||
|
|
||||||
|
auto type = furvm::thing<>::resolve_type(*frame.mod->type_at(typeId), m_context);
|
||||||
|
if (type == nullptr || type->t != type_t::Array || *type->array.type == nullptr)
|
||||||
|
throw std::runtime_error("invalid array type");
|
||||||
|
|
||||||
|
auto array = push_thing({ type, m_context, m_context->thing_alloc() });
|
||||||
|
|
||||||
|
if (type->array.size == 0) {
|
||||||
|
auto sizeThing = pop_thing();
|
||||||
|
long_t size = sizeThing->integer();
|
||||||
|
array->resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
push_thing(std::move(array));
|
||||||
|
} break;
|
||||||
|
case instruction_t::Get: {
|
||||||
|
auto index = pop_thing();
|
||||||
|
auto array = pop_thing();
|
||||||
|
push_thing(array->at(index->integer()));
|
||||||
|
} break;
|
||||||
case instruction_t::Drop: {
|
case instruction_t::Drop: {
|
||||||
pop_thing();
|
pop_thing();
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
+41
-6
@@ -10,13 +10,33 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
static void print_thing(const furvm::thing<furvm::thing_allocator>& thing) {
|
||||||
|
auto rsv = thing.resolve();
|
||||||
|
switch (rsv.type()->t) {
|
||||||
|
case furvm::type_t::Primitive: {
|
||||||
|
std::cout << rsv.integer();
|
||||||
|
} break;
|
||||||
|
case furvm::type_t::Array: {
|
||||||
|
std::cout << "{ ";
|
||||||
|
for (furvm::long_t i = 0; i < rsv.size(); ++i) {
|
||||||
|
if (i > 0) std::cout << ", ";
|
||||||
|
print_thing(rsv.at(i));
|
||||||
|
}
|
||||||
|
std::cout << " }\n";
|
||||||
|
} break;
|
||||||
|
default: std::cerr << "{Something went wrong}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
auto context = std::make_shared<furvm::context>();
|
||||||
|
|
||||||
|
#if 0 // NOLINT
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
std::cerr << "Usage: " << argv[0] << " <mod.fmod>\n";
|
std::cerr << "Usage: " << argv[0] << " <mod.fmod>\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto context = std::make_shared<furvm::context>();
|
|
||||||
|
|
||||||
std::ifstream file(argv[1]);
|
std::ifstream file(argv[1]);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
@@ -24,14 +44,29 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
furvm::mod_h mod = context->emplace("main", furvm::mod::load(file));
|
furvm::mod_h mod = context->emplace("main", std::move(furvm::mod::load(file)));
|
||||||
furvm::function_h func = mod->function_at("main");
|
#else
|
||||||
|
static const furvm::byte s_bytecode[] = {
|
||||||
|
static_cast<furvm::byte>(furvm::instruction_t::Array),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
static_cast<furvm::byte>(furvm::instruction_t::Call),
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
static_cast<furvm::byte>(furvm::instruction_t::Return),
|
||||||
|
};
|
||||||
|
|
||||||
mod->set_native_function("print",
|
furvm::mod_h mod = context->emplace("main", s_bytecode, s_bytecode + sizeof(s_bytecode));
|
||||||
[](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; });
|
mod->emplace_type(std::make_shared<furvm::type>(context->at("core")->type_at(2), 10)).dispatch();
|
||||||
|
auto mainFunc = mod->emplace_function("main", 0, 0);
|
||||||
|
mod->emplace_function_private("print", 1, "print").dispatch();
|
||||||
|
#endif
|
||||||
|
mod->set_native_function("print", [](furvm::executor& executor) { print_thing(*executor.load_thing(0)); });
|
||||||
|
|
||||||
furvm::executor_h executor = context->emplace_executor(context);
|
furvm::executor_h executor = context->emplace_executor(context);
|
||||||
executor->push_frame(mod, *func);
|
executor->push_frame(mod, *mainFunc);
|
||||||
|
|
||||||
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) {
|
||||||
executor->step();
|
executor->step();
|
||||||
|
|||||||
Reference in New Issue
Block a user