forked from KPGPMC/furlang
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c1b65838b0
|
|||
| eaa74fd573 | |||
| 9cd54c1c60 |
+1
-1
@@ -1 +1 @@
|
||||
TBD
|
||||
The commits must be as good as CHatingPython's.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "furvm/fwd.hpp"
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace furvm {
|
||||
|
||||
@@ -45,8 +44,6 @@ public:
|
||||
mod_p mod; /**< Shared pointer to a module with the bytecode. */
|
||||
std::size_t position; /**< Cursor to a current instruction in the bytecode. */
|
||||
std::size_t stackBase; /**< Snapshot of the stack size before this frame. */
|
||||
|
||||
std::vector<thing_p> variables; /**< Frame variables. */
|
||||
};
|
||||
public:
|
||||
/**
|
||||
@@ -142,30 +139,6 @@ public:
|
||||
* @return The thing.
|
||||
*/
|
||||
thing_p thing() const;
|
||||
public:
|
||||
/**
|
||||
* @brief Stores a thing in a variable.
|
||||
*
|
||||
* @param variable Variable to store the thing in.
|
||||
* @param thing Thing to store.
|
||||
*/
|
||||
void store_thing(variable_t variable, const thing_p& thing);
|
||||
|
||||
/**
|
||||
* @brief Stores a thing in a variable.
|
||||
*
|
||||
* @param variable Variable to store the thing in.
|
||||
* @param thing Thing to store.
|
||||
*/
|
||||
void store_thing(variable_t variable, thing_p&& thing);
|
||||
|
||||
/**
|
||||
* @brief Returns a thing stored in a variable.
|
||||
*
|
||||
* @param variable Variable where the thing is stored.
|
||||
* @return The thing stored in the variable.
|
||||
*/
|
||||
thing_p load_thing(variable_t variable) const;
|
||||
public:
|
||||
/**
|
||||
* @brief Executes next instruction.
|
||||
|
||||
@@ -132,11 +132,6 @@ using thing_handle = std::uint32_t;
|
||||
|
||||
// executor.hpp
|
||||
|
||||
/**
|
||||
* @brief A variable index type.
|
||||
*/
|
||||
using variable_t = std::uint16_t;
|
||||
|
||||
/**
|
||||
* @enum executor_flags
|
||||
* @brief Flags of an executor.
|
||||
|
||||
@@ -65,20 +65,6 @@ enum class instruction_t : byte {
|
||||
*/
|
||||
Mod,
|
||||
|
||||
/**
|
||||
* @brief Pushes a variable onto the stack.
|
||||
*
|
||||
* Fetches a variable denoted by next two bytes in little-endian and pushes it onto the stack.
|
||||
*/
|
||||
Load,
|
||||
|
||||
/**
|
||||
* @brief Stores an element from the stack in a variable.
|
||||
*
|
||||
* Pops a thing from the stack and stores it in a variable denoted by next two bytes in little-endian.
|
||||
*/
|
||||
Store,
|
||||
|
||||
/**
|
||||
* @brief Calls a function.
|
||||
*
|
||||
|
||||
@@ -9,7 +9,6 @@ namespace furvm {
|
||||
|
||||
class mod {
|
||||
friend class function;
|
||||
friend class serializer;
|
||||
public:
|
||||
using bytecode_t = std::vector<byte>; /**< An alias to a vector of bytes. */
|
||||
public:
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef FURVM_SERIALIZER_HPP
|
||||
#define FURVM_SERIALIZER_HPP
|
||||
|
||||
#include "furvm/fwd.hpp"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace furvm {
|
||||
|
||||
class serializer {
|
||||
public:
|
||||
static constexpr byte MODULE_MAGIC[4] = { 'F', 'u', 'r', 'M' };
|
||||
static constexpr std::uint32_t VERSION = 0;
|
||||
public:
|
||||
static bool serialize_module(std::ostream& os, const mod_p& mod);
|
||||
};
|
||||
|
||||
} // namespace furvm
|
||||
|
||||
#endif // FURVM_SERIALIZER_HPP
|
||||
@@ -3,11 +3,9 @@
|
||||
#include "furvm/context.hpp" // IWYU pragma: keep
|
||||
#include "furvm/exceptions.hpp"
|
||||
#include "furvm/function.hpp" // IWYU pragma: keep
|
||||
#include "furvm/fwd.hpp"
|
||||
#include "furvm/instruction.hpp"
|
||||
#include "furvm/thing.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace furvm {
|
||||
@@ -64,31 +62,6 @@ thing_p executor::thing() const {
|
||||
return m_stack.top();
|
||||
}
|
||||
|
||||
void executor::store_thing(variable_t variable, const thing_p& thing) {
|
||||
auto& frame = m_frames.top();
|
||||
frame.variables.resize(variable + 1);
|
||||
if (frame.variables[variable] != nullptr) {
|
||||
frame.variables[variable]->remove_reference();
|
||||
}
|
||||
frame.variables[variable] = thing;
|
||||
thing->add_reference();
|
||||
}
|
||||
|
||||
void executor::store_thing(variable_t variable, thing_p&& thing) {
|
||||
auto& frame = m_frames.top();
|
||||
frame.variables.resize(variable + 1);
|
||||
if (frame.variables[variable] != nullptr) {
|
||||
frame.variables[variable]->remove_reference();
|
||||
}
|
||||
thing->add_reference();
|
||||
frame.variables[variable] = std::move(thing);
|
||||
}
|
||||
|
||||
thing_p executor::load_thing(variable_t variable) const {
|
||||
const auto& frame = m_frames.top();
|
||||
return frame.variables[variable];
|
||||
}
|
||||
|
||||
void executor::step() {
|
||||
if ((m_flags & executor_flags::Suspended) == executor_flags::Suspended) return;
|
||||
|
||||
@@ -136,16 +109,6 @@ void executor::step() {
|
||||
auto lhs = pop_thing();
|
||||
push_thing(lhs % rhs);
|
||||
} break;
|
||||
case instruction_t::Load: {
|
||||
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
||||
push_thing(load_thing(variable));
|
||||
} break;
|
||||
case instruction_t::Store: {
|
||||
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
||||
store_thing(variable, std::move(pop_thing()));
|
||||
} break;
|
||||
case instruction_t::Call: {
|
||||
function_handle funcId = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
||||
|
||||
+8
-4
@@ -4,12 +4,10 @@
|
||||
#include "furvm/executor.hpp"
|
||||
#include "furvm/function.hpp"
|
||||
#include "furvm/instruction.hpp"
|
||||
#include "furvm/serializer.hpp"
|
||||
#include "furvm/thing.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
@@ -18,9 +16,16 @@ static constexpr std::array<furvm::byte, 8> s_bytecode = {
|
||||
67,
|
||||
furvm::byte(furvm::instruction_t::Clone),
|
||||
furvm::byte(furvm::instruction_t::Add),
|
||||
furvm::byte(furvm::instruction_t::Call),
|
||||
1,
|
||||
0,
|
||||
furvm::byte(furvm::instruction_t::Return),
|
||||
};
|
||||
|
||||
void print(furvm::executor& exec) {
|
||||
std::cout << exec.pop_thing()->int32() << '\n';
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
auto context = std::make_shared<furvm::context>();
|
||||
|
||||
@@ -28,8 +33,7 @@ int main(void) {
|
||||
|
||||
auto mainFunction = furvm::function::create(mainModule, 0);
|
||||
|
||||
std::ofstream file("./test.furm", std::ios::binary);
|
||||
furvm::serializer::serialize_module(file, mainModule);
|
||||
auto printFunction = furvm::function::create(mainModule, print);
|
||||
|
||||
auto executor = furvm::executor::create(context);
|
||||
executor->push_frame(mainFunction);
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#include "furvm/serializer.hpp"
|
||||
|
||||
#include "furvm/function.hpp" // IWYU pragma: keep
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <istream>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace furvm {
|
||||
|
||||
template <typename T>
|
||||
static inline void write_raw(std::ostream& os, const T& value) {
|
||||
os.write(reinterpret_cast<const char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void read_raw(std::istream& is, T& value) {
|
||||
is.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
static inline void write_u64(std::ostream& os, std::uint64_t value) {
|
||||
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 16ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 24ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 32ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 40ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 48ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 56ULL) & 0xFF));
|
||||
}
|
||||
|
||||
static inline void read_u64(std::istream& is, std::uint64_t& value) {
|
||||
value = (static_cast<std::uint64_t>(is.get()) << 0) | (static_cast<std::uint64_t>(is.get()) << 8) |
|
||||
(static_cast<std::uint64_t>(is.get()) << 16) | (static_cast<std::uint64_t>(is.get()) << 24) |
|
||||
(static_cast<std::uint64_t>(is.get()) << 32) | (static_cast<std::uint64_t>(is.get()) << 40) |
|
||||
(static_cast<std::uint64_t>(is.get()) << 48) | (static_cast<std::uint64_t>(is.get()) << 56);
|
||||
}
|
||||
|
||||
static inline void write_u32(std::ostream& os, std::uint32_t value) {
|
||||
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 16ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 24ULL) & 0xFF));
|
||||
}
|
||||
|
||||
static inline void read_u32(std::istream& is, std::uint32_t& value) {
|
||||
value = static_cast<std::uint32_t>(is.get() << 0) | static_cast<std::uint32_t>(is.get() << 8) |
|
||||
static_cast<std::uint32_t>(is.get() << 16) | static_cast<std::uint32_t>(is.get() << 24);
|
||||
}
|
||||
|
||||
static inline void write_u16(std::ostream& os, std::uint16_t value) {
|
||||
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
|
||||
os.put(static_cast<char>((value >> 8ULL) & 0xFF));
|
||||
}
|
||||
|
||||
static inline void read_u16(std::istream& is, std::uint16_t& value) {
|
||||
value = static_cast<std::uint16_t>(is.get() << 0) | static_cast<std::uint16_t>(is.get() << 8);
|
||||
}
|
||||
|
||||
static inline void write_u8(std::ostream& os, std::uint8_t value) {
|
||||
os.put(static_cast<char>((value >> 0ULL) & 0xFF));
|
||||
}
|
||||
|
||||
static inline void read_u8(std::istream& is, std::uint8_t& value) {
|
||||
value = static_cast<std::uint8_t>(is.get() << 0);
|
||||
}
|
||||
|
||||
bool serializer::serialize_module(std::ostream& os, const mod_p& mod) {
|
||||
os.write(reinterpret_cast<const char*>(MODULE_MAGIC), sizeof(MODULE_MAGIC));
|
||||
write_u32(os, VERSION);
|
||||
|
||||
write_u32(os, mod->m_functions.size());
|
||||
for (const auto& func : mod->m_functions) {
|
||||
write_u16(os, func->id());
|
||||
write_u8(os, static_cast<std::uint8_t>(func->type()));
|
||||
switch (func->type()) {
|
||||
case function_t::Normal: {
|
||||
write_u64(os, func->position());
|
||||
} break;
|
||||
case function_t::Native: {
|
||||
// TODO: Replace with a reference to the function's name from constant pool
|
||||
throw std::runtime_error("cannot serialize native functions yet");
|
||||
} break;
|
||||
case function_t::Import: {
|
||||
// TODO: Replace with a reference to the module's and function's name from constant pool
|
||||
throw std::runtime_error("cannot serialize import functions yet");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
write_u64(os, mod->m_bytecode.size());
|
||||
os.write(reinterpret_cast<const char*>(mod->m_bytecode.data()),
|
||||
static_cast<std::streamsize>(mod->m_bytecode.size()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace furvm
|
||||
Reference in New Issue
Block a user