refactor(furas): use new instructions from furvm

This commit is contained in:
2026-08-11 16:18:17 +02:00
parent 989fcb7199
commit dcefe20d47
2 changed files with 66 additions and 67 deletions
+7
View File
@@ -0,0 +1,7 @@
func println $s32 = native println
public func main = #main
main:
push $s32 69
call $s32 println
ret
+59 -67
View File
@@ -21,48 +21,36 @@ using namespace std::string_literals;
namespace { namespace {
struct instruction {
furvm::instruction_t fur{};
enum arg_type {
None = 0,
Type,
Constant,
Variable,
Function,
Label,
} arg = None;
};
// NOLINTBEGIN // NOLINTBEGIN
std::unordered_map<enum token::type, instruction> instructions = { std::unordered_map<enum token::type, furvm::instruction_t> instructions = {
{ token::Array, { furvm::instruction_t::Array, instruction::Type } }, { token::Array, furvm::instruction_t::Array },
{ token::Get, { furvm::instruction_t::Get } }, { token::Get, furvm::instruction_t::Get },
{ token::Set, { furvm::instruction_t::Set } }, { token::Set, furvm::instruction_t::Set },
{ token::Drop, { furvm::instruction_t::Drop } }, { token::Drop, furvm::instruction_t::Drop },
{ token::Dup, { furvm::instruction_t::Duplicate } }, { token::Dup, furvm::instruction_t::Duplicate },
{ token::Swap, { furvm::instruction_t::Swap } }, { token::Swap, furvm::instruction_t::Swap },
{ token::Clone, { furvm::instruction_t::Clone } }, { token::Clone, furvm::instruction_t::Clone },
{ token::Ref, { furvm::instruction_t::Reference } }, { token::Ref, furvm::instruction_t::Reference },
{ token::Add, { furvm::instruction_t::Add } }, { token::Add, furvm::instruction_t::Add },
{ token::Sub, { furvm::instruction_t::Sub } }, { token::Sub, furvm::instruction_t::Sub },
{ token::Mul, { furvm::instruction_t::Mul } }, { token::Mul, furvm::instruction_t::Mul },
{ token::Div, { furvm::instruction_t::Div } }, { token::Div, furvm::instruction_t::Div },
{ token::Mod, { furvm::instruction_t::Mod } }, { token::Mod, furvm::instruction_t::Mod },
{ token::Eq, { furvm::instruction_t::Equals } }, { token::Eq, furvm::instruction_t::Equals },
{ token::Neq, { furvm::instruction_t::NotEquals } }, { token::Neq, furvm::instruction_t::NotEquals },
{ token::Lt, { furvm::instruction_t::LessThan } }, { token::Lt, furvm::instruction_t::LessThan },
{ token::Gt, { furvm::instruction_t::GreaterThan } }, { token::Gt, furvm::instruction_t::GreaterThan },
{ token::Le, { furvm::instruction_t::LessEqual } }, { token::Le, furvm::instruction_t::LessEqual },
{ token::Ge, { furvm::instruction_t::GreaterEqual } }, { token::Ge, furvm::instruction_t::GreaterEqual },
{ token::Ptrof, { furvm::instruction_t::Pointerof } }, { token::Ptrof, furvm::instruction_t::Pointerof },
{ token::Sizeof, { furvm::instruction_t::Sizeof } }, { token::Sizeof, furvm::instruction_t::Sizeof },
{ token::Lenof, { furvm::instruction_t::Lengthof } }, { token::Lenof, furvm::instruction_t::Lengthof },
{ token::Load, { furvm::instruction_t::Load, instruction::Variable } }, { token::Load, furvm::instruction_t::Load },
{ token::Store, { furvm::instruction_t::Store, instruction::Variable } }, { token::Store, furvm::instruction_t::Store },
{ token::Call, { furvm::instruction_t::Call, instruction::Function } }, { token::Call, furvm::instruction_t::Call },
{ token::Jmp, { furvm::instruction_t::Jump, instruction::Label } }, { token::Jmp, furvm::instruction_t::Jump },
{ token::Jnz, { furvm::instruction_t::JumpNotZero, instruction::Label } }, { token::Jnz, furvm::instruction_t::JumpNotZero },
{ token::Ret, { furvm::instruction_t::Return } }, { token::Ret, furvm::instruction_t::Return },
}; };
// NOLINTEND // NOLINTEND
@@ -214,12 +202,12 @@ struct mod_context {
handle.dispatch(); handle.dispatch();
} }
for (auto unknown : label.unknowns) { for (auto unknown : label.unknowns) {
std::ptrdiff_t jmpOff = static_cast<std::ptrdiff_t>(label.offset - unknown); const auto jmpOff = static_cast<std::ptrdiff_t>(label.offset) - static_cast<std::ptrdiff_t>(unknown);
if (jmpOff < std::numeric_limits<std::int8_t>::min() || if (jmpOff < std::numeric_limits<std::int8_t>::min() ||
jmpOff > std::numeric_limits<std::int8_t>::max()) { jmpOff > std::numeric_limits<std::int8_t>::max()) {
assert(false); // TODO: Further jumps are not implemented assert(false); // TODO: Further jumps are not implemented
} }
mod.bytecode()[unknown - 1] = jmpOff; mod.bytecode()[unknown - 1] = static_cast<std::int8_t>(jmpOff);
} }
label.functions = {}; label.functions = {};
label.unknowns = {}; label.unknowns = {};
@@ -453,10 +441,11 @@ struct mod_context {
case token::Ret: { case token::Ret: {
auto it = instructions.find(result->type); auto it = instructions.find(result->type);
assert(it != instructions.end()); assert(it != instructions.end());
mod.bytecode().push_back(static_cast<furvm::byte>(it->second.fur)); furvm::instruction instr{ it->second };
switch (it->second.arg) { instr.arg.type = furvm::instruction::s_arguments[instr.type];
case instruction::None: break; switch (instr.arg.type) {
case instruction::Type: { case furvm::instruction_argument::None: break;
case furvm::instruction_argument::Type: {
result = eat_token(lexer, token::Dolar); result = eat_token(lexer, token::Dolar);
if (!result) return result.error; if (!result) return result.error;
result = eat_token(lexer, token::Identifier); result = eat_token(lexer, token::Identifier);
@@ -464,25 +453,19 @@ struct mod_context {
auto type = types.find(std::string(result->value.string)); auto type = types.find(std::string(result->value.string));
if (type == types.end()) if (type == types.end())
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) };
auto id = type->second.id(); instr.arg.u32 = type->second.id();
mod.bytecode().push_back((id >> 0) & 0xFF);
mod.bytecode().push_back((id >> 8) & 0xFF);
mod.bytecode().push_back((id >> 16) & 0xFF);
mod.bytecode().push_back((id >> 24) & 0xFF);
} break; } break;
case instruction::Constant: { case furvm::instruction_argument::Constant: {
assert(false); // TODO: Unimplemented assert(false); // TODO: Unimplemented
} break; } break;
case instruction::Variable: { case furvm::instruction_argument::Variable: {
result = eat_token(lexer, token::Percent); result = eat_token(lexer, token::Percent);
if (!result) return result.error; if (!result) return result.error;
result = eat_token(lexer, token::Unsigned); result = eat_token(lexer, token::Unsigned);
if (!result) return result.error; if (!result) return result.error;
std::uint16_t var = result->value.uint; instr.arg.u16 = result->value.uint;
mod.bytecode().push_back((var >> 0) & 0xFF);
mod.bytecode().push_back((var >> 8) & 0xFF);
} break; } break;
case instruction::Function: { case furvm::instruction_argument::Function: {
furvm::function_sig signature; furvm::function_sig signature;
while ((result = next_token(lexer)).error.type == generator_error::Success && while ((result = next_token(lexer)).error.type == generator_error::Success &&
result->type == token::Dolar) { result->type == token::Dolar) {
@@ -499,11 +482,10 @@ struct mod_context {
auto func = functions.find(std::make_pair(name, signature)); auto func = functions.find(std::make_pair(name, signature));
if (func == functions.end()) if (func == functions.end())
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) };
auto id = func->second.id(); auto id = func->second.id();
mod.bytecode().push_back((id >> 0) & 0xFF); instr.arg.u16 = id;
mod.bytecode().push_back((id >> 8) & 0xFF);
} break; } break;
case instruction::Label: { case furvm::instruction_argument::Offset: {
result = eat_token(lexer, token::Sha256); result = eat_token(lexer, token::Sha256);
if (!result) return result.error; if (!result) return result.error;
result = eat_token(lexer, token::Identifier); result = eat_token(lexer, token::Identifier);
@@ -511,18 +493,28 @@ struct mod_context {
auto& label = labels[std::string(result->value.string)]; auto& label = labels[std::string(result->value.string)];
auto offset = label.offset; auto offset = label.offset;
if (offset == label_context::INVALID) { if (offset == label_context::INVALID) {
label.unknowns.push_back(mod.bytecode().size() + 1); label.unknowns.push_back(mod.bytecode().size() + 2);
mod.bytecode().push_back(0); instr.arg.s8 = 0;
return { generator_error::Success }; break;
} }
std::ptrdiff_t jmpOff = static_cast<std::ptrdiff_t>(offset - mod.bytecode().size() - 1); const auto jmpOff =
static_cast<std::ptrdiff_t>(offset) - static_cast<std::ptrdiff_t>(mod.bytecode().size()) - 2;
if (jmpOff < std::numeric_limits<std::int8_t>::min() || if (jmpOff < std::numeric_limits<std::int8_t>::min() ||
jmpOff > std::numeric_limits<std::int8_t>::max()) { jmpOff > std::numeric_limits<std::int8_t>::max()) {
assert(false); // TODO: Further jumps are not implemented assert(false); // TODO: Further jumps are not implemented
} }
mod.bytecode().push_back(jmpOff); instr.arg.s8 = static_cast<std::int8_t>(jmpOff);
} break; } break;
case furvm::instruction_argument::S8:
case furvm::instruction_argument::U8:
case furvm::instruction_argument::S16:
case furvm::instruction_argument::U16:
case furvm::instruction_argument::S32:
case furvm::instruction_argument::U32:
case furvm::instruction_argument::Count:
default: throw std::runtime_error("unreachable");
} }
instr.write(mod.bytecode());
return { generator_error::Success }; return { generator_error::Success };
} }