Compare commits
2 Commits
81a439b2ad
...
2519560451
| Author | SHA1 | Date | |
|---|---|---|---|
|
2519560451
|
|||
|
7c74850aff
|
@@ -23,9 +23,9 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func
|
||||
switch (function.type()) {
|
||||
case furlang::ir::function_t::Normal: {
|
||||
if (function.access() == furlang::ir::function_access_t::Public)
|
||||
mod.emplace_function(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
mod.emplace_function_named(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
else
|
||||
mod.emplace_function_private(function.name(), function.param_count(), mod.bytecode().size()).dispatch();
|
||||
mod.emplace_function(function.param_count(), mod.bytecode().size()).dispatch();
|
||||
|
||||
function_context ctx;
|
||||
for (furlang::ir::block_index idx = 0; idx < function.blocks().size(); ++idx) {
|
||||
@@ -48,9 +48,9 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func
|
||||
} break;
|
||||
case furlang::ir::function_t::Native: {
|
||||
if (function.access() == furlang::ir::function_access_t::Public)
|
||||
mod.emplace_function(function.name(), function.param_count(), function.name()).dispatch();
|
||||
mod.emplace_function_named(function.name(), function.param_count(), function.name()).dispatch();
|
||||
else
|
||||
mod.emplace_function_private(function.name(), function.param_count(), function.name()).dispatch();
|
||||
mod.emplace_function(function.param_count(), function.name()).dispatch();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ void furvm_generator::generate_instruction(furvm::mod& mod,
|
||||
const auto& call = dynamic_cast<const furlang::ir::call_instruction&>(instr);
|
||||
|
||||
// TODO: Implement a queue for unknown functions
|
||||
furvm::function_id func = mod.get_function_id(call.name());
|
||||
furvm::function_id func = mod.function_at(call.name()).id();
|
||||
mod.bytecode().push_back(static_cast<furvm::byte>(furvm::instruction_t::Call));
|
||||
mod.bytecode().push_back((func >> 0) & 0xFF);
|
||||
mod.bytecode().push_back((func >> 8) & 0xFF);
|
||||
|
||||
@@ -36,29 +36,21 @@ public:
|
||||
/**
|
||||
* @brief Constructs a normal function.
|
||||
*
|
||||
* @param name Name of the function.
|
||||
* @param paramCount Paremeter count.
|
||||
* @param position Offset in bytecode of the function.
|
||||
*/
|
||||
template <typename Name>
|
||||
function(Name&& name, std::uint32_t paramCount, bytecode_pos position)
|
||||
: m_name(std::forward<Name>(name)), m_type(function_t::Normal), m_paramCount(paramCount), m_value(position) {}
|
||||
function(std::uint32_t paramCount, bytecode_pos position)
|
||||
: m_type(function_t::Normal), m_paramCount(paramCount), m_value(position) {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a native function.
|
||||
*
|
||||
* @param name Name of the function.
|
||||
* @param paramCount Paremeter count.
|
||||
* @param native Native function tag.
|
||||
*/
|
||||
template <typename Name,
|
||||
typename Native,
|
||||
typename = std::enable_if_t<std::is_constructible_v<native_function, Native>>>
|
||||
function(Name&& name, std::uint32_t paramCount, Native&& native)
|
||||
: m_name(std::forward<Name>(name)),
|
||||
m_type(function_t::Native),
|
||||
m_paramCount(paramCount),
|
||||
m_value(std::forward<Native>(native)) {}
|
||||
template <typename Native, typename = std::enable_if_t<std::is_constructible_v<native_function, Native>>>
|
||||
function(std::uint32_t paramCount, Native&& native)
|
||||
: m_type(function_t::Native), m_paramCount(paramCount), m_value(std::forward<Native>(native)) {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an import function.
|
||||
@@ -103,13 +95,6 @@ public:
|
||||
*/
|
||||
function& operator=(const function&);
|
||||
public:
|
||||
/**
|
||||
* @brief Returns a name of this function.
|
||||
*
|
||||
* @return The name.
|
||||
*/
|
||||
constexpr const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* @brief Returns a type of this function.
|
||||
*
|
||||
@@ -154,7 +139,6 @@ public:
|
||||
return m_value.imp;
|
||||
}
|
||||
private:
|
||||
std::string m_name;
|
||||
function_t m_type;
|
||||
std::uint32_t m_paramCount;
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -86,51 +86,38 @@ public:
|
||||
function_h emplace_function(Args&&... args) {
|
||||
function_h function;
|
||||
if constexpr (std::is_constructible_v<class function, Args...>) {
|
||||
function = m_functions.emplace_back(std::forward<Args>(args)...);
|
||||
function = std::move(m_functions.emplace_back(std::forward<Args>(args)...));
|
||||
} else {
|
||||
function = m_functions.emplace(std::forward<Args>(args)...);
|
||||
function = std::move(m_functions.emplace(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
m_functionMap[function->name()] = function.id();
|
||||
m_publicFunctions[function->name()] = function.id();
|
||||
m_functionMap[function.id()] = "";
|
||||
return std::move(function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emplaces a function in the module's function container.
|
||||
*
|
||||
* Emplaces the function in module's function container and name to function map .
|
||||
* Emplaces the function in module's function container and name to function map.
|
||||
*
|
||||
* @param args Arguments forwarded into the container's emplace_back function.
|
||||
* @return A handle to the emplaced function.
|
||||
*/
|
||||
template <typename... Args>
|
||||
function_h emplace_function_private(Args&&... args) {
|
||||
function_h function = m_functions.emplace_back(std::forward<Args>(args)...);
|
||||
m_functionMap[function->name()] = function.id();
|
||||
template <typename NameFwd,
|
||||
typename... Args,
|
||||
typename = std::enable_if_t<std::is_constructible_v<std::string, NameFwd>>>
|
||||
function_h emplace_function_named(NameFwd&& name, Args&&... args) {
|
||||
function_h function;
|
||||
if constexpr (std::is_constructible_v<class function, Args...>) {
|
||||
function = std::move(m_functions.emplace_back(std::forward<Args>(args)...));
|
||||
} else {
|
||||
function = std::move(m_functions.emplace(std::forward<Args>(args)...));
|
||||
}
|
||||
std::string nameInst = std::forward<NameFwd>(name);
|
||||
m_functionNames[nameInst] = function.id();
|
||||
m_functionMap[function.id()] = nameInst;
|
||||
return std::move(function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a function in the module's function container.
|
||||
*
|
||||
* @param function Function to insert.
|
||||
*/
|
||||
template <typename Function>
|
||||
auto push_back(Function&& function) {
|
||||
return emplace_function(std::forward<Function>(function));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a function in the module's function container.
|
||||
*
|
||||
* @param function Function to insert.
|
||||
*/
|
||||
template <typename Function>
|
||||
auto push_back_private(Function&& function) {
|
||||
return emplace_function_private(std::forward<Function>(function));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a function from the module.
|
||||
*
|
||||
@@ -155,7 +142,7 @@ public:
|
||||
*/
|
||||
template <typename NameFwd, typename = std::enable_if_t<std::is_constructible_v<std::string, NameFwd>>>
|
||||
auto function_at(NameFwd&& name) {
|
||||
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
||||
return function_at(m_functionNames.at(std::forward<NameFwd>(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,18 +153,7 @@ public:
|
||||
*/
|
||||
template <typename NameFwd, typename = std::enable_if_t<std::is_constructible_v<std::string, NameFwd>>>
|
||||
auto function_at(NameFwd&& name) const {
|
||||
return function_at(m_publicFunctions.at(std::forward<NameFwd>(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an id of a function from the module.
|
||||
*
|
||||
* @param name Name of the function.
|
||||
* @return An id of the function.
|
||||
*/
|
||||
template <typename NameFwd>
|
||||
auto get_function_id(NameFwd&& name) {
|
||||
return m_functionMap.at(std::forward<NameFwd>(name));
|
||||
return function_at(m_functionNames.at(std::forward<NameFwd>(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,8 +238,8 @@ public:
|
||||
private:
|
||||
bytecode_t m_bytecode;
|
||||
|
||||
std::unordered_map<std::string, function_id> m_functionMap;
|
||||
std::unordered_map<std::string, function_id> m_publicFunctions;
|
||||
std::unordered_map<std::string, function_id> m_functionNames;
|
||||
std::unordered_map<function_id, std::string> m_functionMap;
|
||||
handle_container<function_h> m_functions;
|
||||
|
||||
handle_container<type_h> m_types;
|
||||
|
||||
@@ -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<array_t>();
|
||||
if (newSize < 0 || newSize == list.size) return;
|
||||
auto& array = get<array_t>();
|
||||
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<array_t>();
|
||||
if (index < 0 || index >= list.size) throw std::out_of_range("index out of range");
|
||||
thing res = { std::make_shared<type>(m_type->array.type), m_modules, m_allocator };
|
||||
res.get<reference_t>() = 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<class type>(*m_type->array.type), m_modules, m_allocator };
|
||||
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);
|
||||
}
|
||||
|
||||
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:
|
||||
static type_p resolve_type(const type_p& initType, const mod_container& modules) {
|
||||
type_p rsv = initType;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "furvm/fwd.hpp"
|
||||
#include "furvm/instruction.hpp"
|
||||
#include "furvm/thing.hpp"
|
||||
#include "furvm/type.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#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>() =
|
||||
frame.mod->byte(frame.position++);
|
||||
} 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: {
|
||||
pop_thing();
|
||||
} break;
|
||||
|
||||
@@ -23,7 +23,7 @@ function::~function() {
|
||||
}
|
||||
|
||||
function::function(function&& other) noexcept
|
||||
: m_name(std::move(other.m_name)), m_type(other.m_type), m_paramCount(other.m_paramCount) {
|
||||
: m_type(other.m_type), m_paramCount(other.m_paramCount) {
|
||||
switch (m_type) {
|
||||
case function_t::Normal: {
|
||||
m_value.position = other.m_value.position;
|
||||
@@ -42,7 +42,6 @@ function::function(function&& other) noexcept
|
||||
function& function::operator=(function&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
|
||||
m_name = std::move(other.m_name);
|
||||
m_type = other.m_type;
|
||||
m_paramCount = other.m_paramCount;
|
||||
switch (m_type) {
|
||||
@@ -63,7 +62,7 @@ function& function::operator=(function&& other) noexcept {
|
||||
}
|
||||
|
||||
function::function(const function& other)
|
||||
: m_name(other.m_name), m_type(other.m_type), m_paramCount(other.m_paramCount) {
|
||||
: m_type(other.m_type), m_paramCount(other.m_paramCount) {
|
||||
switch (m_type) {
|
||||
case function_t::Normal: {
|
||||
m_value.position = other.m_value.position;
|
||||
@@ -81,7 +80,6 @@ function::function(const function& other)
|
||||
function& function::operator=(const function& other) {
|
||||
if (this == &other) return *this;
|
||||
|
||||
m_name = other.m_name;
|
||||
m_type = other.m_type;
|
||||
m_paramCount = other.m_paramCount;
|
||||
switch (m_type) {
|
||||
|
||||
+41
-6
@@ -10,13 +10,33 @@
|
||||
#include <memory>
|
||||
#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) {
|
||||
auto context = std::make_shared<furvm::context>();
|
||||
|
||||
#if 0 // NOLINT
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " <mod.fmod>\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto context = std::make_shared<furvm::context>();
|
||||
|
||||
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::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::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<furvm::type>(context->at("core")->type_at(2), 10)).dispatch();
|
||||
auto mainFunc = mod->emplace_function_named("main", 0, 0);
|
||||
mod->emplace_function(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();
|
||||
|
||||
+10
-5
@@ -27,9 +27,8 @@ std::ostream& mod::serialize(std::ostream& os) const {
|
||||
continue;
|
||||
}
|
||||
|
||||
function_h func = m_functions.at(id);
|
||||
bool isPublic = m_publicFunctions.find(func->name()) != m_publicFunctions.end();
|
||||
detail::serialize(os, isPublic ? func->name() : ""); // private functions have empty names
|
||||
function_h func = m_functions.at(id);
|
||||
detail::serialize(os, m_functionMap.at(func.id()));
|
||||
detail::serialize(os, func->param_count());
|
||||
detail::serialize(os, std::uint8_t(func->type()));
|
||||
switch (func->type()) {
|
||||
@@ -98,12 +97,18 @@ mod mod::load(std::istream& is) {
|
||||
case function_t::Normal: {
|
||||
decltype(std::declval<function>().position()) offset = 0;
|
||||
detail::load(is, offset);
|
||||
mod.emplace_function(id, std::move(name), paramCount, offset).dispatch();
|
||||
if (name.empty())
|
||||
mod.emplace_function_named(std::move(name), id, paramCount, offset).dispatch();
|
||||
else
|
||||
mod.emplace_function(id, paramCount, offset).dispatch();
|
||||
} break;
|
||||
case function_t::Native: {
|
||||
std::string native;
|
||||
detail::load(is, native);
|
||||
mod.emplace_function(id, std::move(name), paramCount, std::move(native)).dispatch();
|
||||
if (name.empty())
|
||||
mod.emplace_function_named(std::move(name), id, paramCount, std::move(native)).dispatch();
|
||||
else
|
||||
mod.emplace_function(id, paramCount, std::move(native)).dispatch();
|
||||
} break;
|
||||
case function_t::Import: {
|
||||
std::string modName;
|
||||
|
||||
Reference in New Issue
Block a user