diff --git a/furas/examples/array.furas b/furas/examples/array.furas index 771664e..3d687e0 100644 --- a/furas/examples/array.furas +++ b/furas/examples/array.furas @@ -1,23 +1,34 @@ -type arr = array $s8 11 +type arr = array $s8 10 func println $arr = native println public func main = #main main: array $arr + dup store %0 + + lenof + push $s32 1 + sub + store %1 + push $s32 0 loop: dup - push $s32 10 + load %1 eq jnz #end body: dup load %0 + swap push $s8 69 set + push $s32 1 + add + jmp #loop end: drop diff --git a/furas/examples/array2.furas b/furas/examples/array2.furas new file mode 100644 index 0000000..ae51298 --- /dev/null +++ b/furas/examples/array2.furas @@ -0,0 +1,34 @@ +type arr = array $s8 10 + +func println $arr = native println + +public func main = #main +main: + array $arr + store %0 + + push $s32 1 + store %1 + + push $s32 0 +loop: + dup + load %1 + eq + jnz #end +body: + dup + load %0 + swap + push $s8 69 + set + + push $s32 1 + add + + jmp #loop +end: + drop + load %0 + call $arr println + ret diff --git a/furas/examples/ops.furas b/furas/examples/ops.furas new file mode 100644 index 0000000..d320ea1 --- /dev/null +++ b/furas/examples/ops.furas @@ -0,0 +1,23 @@ +func println $u32 = native println + +public func main = #main +main: + push $u32 0 + store %0 +loop_header: + load %0 + push $u32 10 + ge + jnz #loop_end +loop_body: + load %0 + call $u32 println + + load %0 + push $u32 1 + add + store %0 + + jmp #loop_header +loop_end: + ret diff --git a/furas/examples/simple.furas b/furas/examples/simple.furas new file mode 100644 index 0000000..e69de29 diff --git a/furas/include/furas/token.hpp b/furas/include/furas/token.hpp index 67e0767..d34baab 100644 --- a/furas/include/furas/token.hpp +++ b/furas/include/furas/token.hpp @@ -37,6 +37,7 @@ struct token { Set, Drop, Dup, + Swap, Clone, Ref, Add, diff --git a/furas/src/gen.cpp b/furas/src/gen.cpp index fb0850f..6044b68 100644 --- a/furas/src/gen.cpp +++ b/furas/src/gen.cpp @@ -40,6 +40,7 @@ std::unordered_map instructions = { { token::Set, { furvm::instruction_t::Set } }, { token::Drop, { furvm::instruction_t::Drop } }, { token::Dup, { furvm::instruction_t::Duplicate } }, + { token::Swap, { furvm::instruction_t::Swap } }, { token::Clone, { furvm::instruction_t::Clone } }, { token::Ref, { furvm::instruction_t::Reference } }, { token::Add, { furvm::instruction_t::Add } }, @@ -89,6 +90,7 @@ const char* token_type(enum token::type type) { case token::Set: return "set"; case token::Drop: return "drop"; case token::Dup: return "dup"; + case token::Swap: return "swap"; case token::Clone: return "clone"; case token::Ref: return "ref"; case token::Add: return "add"; @@ -384,27 +386,36 @@ struct mod_context { auto it = types.find(std::string(typeName->value.string)); if (it == types.end()) return { generator_error::UnexpectedToken, "Unknown type "s + std::string(typeName->value.string) }; + // TODO: Add support for signed integers auto value = eat_token(lexer, token::Unsigned); if (!value) return result.error; auto type = it->second; switch (type->type) { case furvm::mod_type::S8: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushS8)); + mod.bytecode().push_back(value->value.uint & 0xFF); } break; case furvm::mod_type::U8: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushU8)); + mod.bytecode().push_back(value->value.uint & 0xFF); } break; case furvm::mod_type::S16: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushS16)); + mod.bytecode().push_back(value->value.uint & 0xFF); + mod.bytecode().push_back((value->value.uint >> 8) & 0xFF); } break; case furvm::mod_type::U16: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushU16)); + mod.bytecode().push_back(value->value.uint & 0xFF); + mod.bytecode().push_back((value->value.uint >> 8) & 0xFF); } break; case furvm::mod_type::S32: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushS32)); + mod.bytecode().push_back(value->value.uint & 0xFF); } break; case furvm::mod_type::U32: { mod.bytecode().push_back(static_cast(furvm::instruction_t::PushU32)); + mod.bytecode().push_back(value->value.uint & 0xFF); } break; default: return { generator_error::UnexpectedToken, "Unexpected type "s + std::string(typeName->value.string) }; @@ -417,6 +428,7 @@ struct mod_context { case token::Set: case token::Drop: case token::Dup: + case token::Swap: case token::Clone: case token::Ref: case token::Add: @@ -503,7 +515,7 @@ struct mod_context { mod.bytecode().push_back(0); return { generator_error::Success }; } - std::ptrdiff_t jmpOff = static_cast(offset - mod.bytecode().size() + 1); + std::ptrdiff_t jmpOff = static_cast(offset - mod.bytecode().size() - 1); if (jmpOff < std::numeric_limits::min() || jmpOff > std::numeric_limits::max()) { assert(false); // TODO: Further jumps are not implemented diff --git a/furas/src/lexer.cpp b/furas/src/lexer.cpp index bc70dc4..89c3e11 100644 --- a/furas/src/lexer.cpp +++ b/furas/src/lexer.cpp @@ -46,6 +46,7 @@ token_r lexer::next_token() { { "set", token::Set }, { "drop", token::Drop }, { "dup", token::Dup }, + { "swap", token::Swap }, { "clone", token::Clone }, { "ref", token::Ref }, { "add", token::Add }, diff --git a/furvm/include/furvm/fwd.hpp b/furvm/include/furvm/fwd.hpp index d7d3798..fb12a2e 100644 --- a/furvm/include/furvm/fwd.hpp +++ b/furvm/include/furvm/fwd.hpp @@ -111,7 +111,7 @@ using function_id = std::uint16_t; /** * @brief A handle to a furvm function. */ -using function_h = handle>; +using function_h = handle>; // module.hpp diff --git a/furvm/include/furvm/instruction.hpp b/furvm/include/furvm/instruction.hpp index be6cba0..b6d4d8f 100644 --- a/furvm/include/furvm/instruction.hpp +++ b/furvm/include/furvm/instruction.hpp @@ -76,6 +76,11 @@ enum class instruction_t : byte { */ Duplicate, + /** + * @brief Swaps two top elements of the stack. + */ + Swap, + /** * @brief Clones top element on the stack. */ diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 1b12813..153ac1d 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -502,6 +502,32 @@ public: if (m_type.type != thing_type::Ref || *m_type.value.typeRef != thing.type()) throw bad_thing_access(); m_data = thing.m_data; } + + /** + * @brief Self-explainatory. + * + * TODO: Document + */ + void assign(thing&& thing) { + class thing rhs = std::move(thing); + if (true_type() != rhs.true_type()) throw std::runtime_error("thing type mismatch"); + // TODO: Move this to another function + switch (true_type().type) { + case thing_type::S8: + case thing_type::S16: + case thing_type::S32: + case thing_type::S64: + case thing_type::U8: + case thing_type::U16: + case thing_type::U32: + case thing_type::U64: std::memcpy(m_data, rhs.m_data, m_size); return; + case thing_type::Ptr: + case thing_type::Ref: + case thing_type::Array: throw std::runtime_error("unimplemented"); + case thing_type::Count: break; + } + throw std::runtime_error("unreachable"); + } private: static void copy_list(const thing_type& arrayType, array& dst, const array& src) { if (arrayType.type != thing_type::Array || arrayType.value.array.type == nullptr) diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 332030e..0263315 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace furvm { @@ -122,7 +123,7 @@ void executor::store_thing(variable_t variable, thing_h&& thing) { thing_h executor::load_thing(variable_t variable) const { const auto& frame = m_frames.top(); - return frame.variables[variable]; + return { frame.variables[variable] }; } void executor::step() { @@ -186,10 +187,10 @@ void executor::step() { push_thing(array->at(index->integer())); } break; case instruction_t::Set: { - auto index = pop_thing(); - auto array = pop_thing(); - auto element = pop_thing(); - array->at(index->integer()) = std::move(element->clone()); + auto element = pop_thing(); + auto index = pop_thing(); + auto array = pop_thing(); + array->at(index->integer()).assign(std::move(element->clone())); } break; case instruction_t::Drop: { pop_thing(); @@ -197,6 +198,12 @@ void executor::step() { case instruction_t::Duplicate: { push_thing(thing()); } break; + case instruction_t::Swap: { + auto thing1 = pop_thing(); + auto thing2 = pop_thing(); + push_thing(std::move(thing1)); + push_thing(std::move(thing2)); + } break; case instruction_t::Clone: { push_thing(std::move(thing()->clone())); } break; @@ -316,7 +323,8 @@ void executor::step() { push_frame(frame.mod, *frame.mod->function_at(funcId)); } break; case instruction_t::Jump: { - frame.position += ((std::int8_t)frame.mod->byte(frame.position)) + 1; + std::int8_t offset = static_cast(frame.mod->byte(frame.position++)); + frame.position += offset; } break; case instruction_t::JumpNotZero: { byte offset = frame.mod->byte(frame.position++); diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 96a49f6..b954d03 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -75,8 +75,8 @@ int main(int argc, char** argv) { mod->emplace_function(furvm::function_sig{ { u64Type }, u64Type }, "print").dispatch(); #endif mod->set_native_function("println", [](furvm::executor& executor) { - auto arg = std::move(*executor.load_thing(0)); - print_thing(arg); + auto arg = executor.load_thing(0); + print_thing(*arg); std::cout << '\n'; });