diff --git a/furvm/include/furvm/instruction.hpp b/furvm/include/furvm/instruction.hpp index fdad85c..59c0cc4 100644 --- a/furvm/include/furvm/instruction.hpp +++ b/furvm/include/furvm/instruction.hpp @@ -25,6 +25,19 @@ enum class instruction_t : byte { */ 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. */ diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 813dd87..9231132 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -283,24 +283,39 @@ public: 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"); - auto& list = get(); - if (newSize < 0 || newSize == list.size) return; + auto& array = get(); + if (newSize < 0 || newSize == array.dynamic.size) return; std::size_t innerSize = compute_size_na(*m_type->array.type); std::byte* newData = new std::byte[innerSize * newSize]; - std::memcpy(newData, list.data, innerSize * std::min(list.size, newSize)); - list.size = newSize; - delete[] list.data; - list.data = newData; + std::memcpy(newData, array.dynamic.data, innerSize * std::min(array.dynamic.size, newSize)); + array.dynamic.size = newSize; + delete[] array.dynamic.data; + array.dynamic.data = newData; } thing at(long_t index) const { if (m_type->t != type_t::Array) throw bad_thing_access(); - auto& list = get(); - if (index < 0 || index >= list.size) throw std::out_of_range("index out of range"); - thing res = { std::make_shared(m_type->array.type), m_modules, m_allocator }; - res.get() = list.data; // TODO: Account for padding, alignment and stuff + + std::size_t elementSize = compute_size_na(*m_type->array.type); + thing res = { std::make_shared(*m_type->array.type), m_modules, m_allocator }; + if (m_type->array.size == 0) { + auto& array = get(); + if (index < 0 || index >= array.dynamic.size) throw std::out_of_range("index out of range"); + res.get() = array.dynamic.data + (index * elementSize); + return std::move(res); + } + + std::byte* data = reinterpret_cast(m_data)->data; + if (index < 0 || index >= m_type->array.size) throw std::out_of_range("index out of range"); + res.get() = 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().dynamic.size; + return m_type->array.size; + } public: static type_p resolve_type(const type_p& initType, const mod_container& modules) { type_p rsv = initType; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 80fda48..5956af4 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -6,6 +6,7 @@ #include "furvm/fwd.hpp" #include "furvm/instruction.hpp" #include "furvm/thing.hpp" +#include "furvm/type.hpp" #include #include @@ -94,6 +95,32 @@ void executor::step() { push_thing({ *m_context->at("core")->type_at(2), m_context, m_context->thing_alloc() })->get() = frame.mod->byte(frame.position++); } break; + case instruction_t::Array: { + type_id typeId = static_cast(frame.mod->byte(frame.position)) | + (static_cast(frame.mod->byte(frame.position + 1)) << 8) | + (static_cast(frame.mod->byte(frame.position + 2)) << 16) | + (static_cast(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: { pop_thing(); } break; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index cf2a4f3..d55f3d3 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -10,13 +10,33 @@ #include #include +static void print_thing(const furvm::thing& 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) { + auto context = std::make_shared(); + +#if 0 // NOLINT if (argc != 2) { std::cerr << "Usage: " << argv[0] << " \n"; return 1; } - auto context = std::make_shared(); std::ifstream file(argv[1]); if (!file.is_open()) { @@ -24,14 +44,29 @@ int main(int argc, char** argv) { return 1; } - furvm::mod_h mod = context->emplace("main", furvm::mod::load(file)); - furvm::function_h func = mod->function_at("main"); + furvm::mod_h mod = context->emplace("main", std::move(furvm::mod::load(file))); +#else + static const furvm::byte s_bytecode[] = { + static_cast(furvm::instruction_t::Array), + 0, + 0, + 0, + 0, + static_cast(furvm::instruction_t::Call), + 1, + 0, + static_cast(furvm::instruction_t::Return), + }; - mod->set_native_function("print", - [](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; }); + furvm::mod_h mod = context->emplace("main", s_bytecode, s_bytecode + sizeof(s_bytecode)); + mod->emplace_type(std::make_shared(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); - executor->push_frame(mod, *func); + executor->push_frame(mod, *mainFunc); while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) { executor->step();