diff --git a/furas/examples/simple.furas b/furas/examples/simple.furas index e69de29..708ab13 100644 --- a/furas/examples/simple.furas +++ b/furas/examples/simple.furas @@ -0,0 +1,7 @@ +func println $s32 = native println + +public func main = #main +main: + push $s32 69 + call $s32 println + ret diff --git a/furas/src/gen.cpp b/furas/src/gen.cpp index c39aa9d..43c3548 100644 --- a/furas/src/gen.cpp +++ b/furas/src/gen.cpp @@ -21,48 +21,36 @@ using namespace std::string_literals; namespace { -struct instruction { - furvm::instruction_t fur{}; - enum arg_type { - None = 0, - Type, - Constant, - Variable, - Function, - Label, - } arg = None; -}; - // NOLINTBEGIN -std::unordered_map instructions = { - { token::Array, { furvm::instruction_t::Array, instruction::Type } }, - { token::Get, { furvm::instruction_t::Get } }, - { 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 } }, - { token::Sub, { furvm::instruction_t::Sub } }, - { token::Mul, { furvm::instruction_t::Mul } }, - { token::Div, { furvm::instruction_t::Div } }, - { token::Mod, { furvm::instruction_t::Mod } }, - { token::Eq, { furvm::instruction_t::Equals } }, - { token::Neq, { furvm::instruction_t::NotEquals } }, - { token::Lt, { furvm::instruction_t::LessThan } }, - { token::Gt, { furvm::instruction_t::GreaterThan } }, - { token::Le, { furvm::instruction_t::LessEqual } }, - { token::Ge, { furvm::instruction_t::GreaterEqual } }, - { token::Ptrof, { furvm::instruction_t::Pointerof } }, - { token::Sizeof, { furvm::instruction_t::Sizeof } }, - { token::Lenof, { furvm::instruction_t::Lengthof } }, - { token::Load, { furvm::instruction_t::Load, instruction::Variable } }, - { token::Store, { furvm::instruction_t::Store, instruction::Variable } }, - { token::Call, { furvm::instruction_t::Call, instruction::Function } }, - { token::Jmp, { furvm::instruction_t::Jump, instruction::Label } }, - { token::Jnz, { furvm::instruction_t::JumpNotZero, instruction::Label } }, - { token::Ret, { furvm::instruction_t::Return } }, +std::unordered_map instructions = { + { token::Array, furvm::instruction_t::Array }, + { token::Get, furvm::instruction_t::Get }, + { 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 }, + { token::Sub, furvm::instruction_t::Sub }, + { token::Mul, furvm::instruction_t::Mul }, + { token::Div, furvm::instruction_t::Div }, + { token::Mod, furvm::instruction_t::Mod }, + { token::Eq, furvm::instruction_t::Equals }, + { token::Neq, furvm::instruction_t::NotEquals }, + { token::Lt, furvm::instruction_t::LessThan }, + { token::Gt, furvm::instruction_t::GreaterThan }, + { token::Le, furvm::instruction_t::LessEqual }, + { token::Ge, furvm::instruction_t::GreaterEqual }, + { token::Ptrof, furvm::instruction_t::Pointerof }, + { token::Sizeof, furvm::instruction_t::Sizeof }, + { token::Lenof, furvm::instruction_t::Lengthof }, + { token::Load, furvm::instruction_t::Load }, + { token::Store, furvm::instruction_t::Store }, + { token::Call, furvm::instruction_t::Call }, + { token::Jmp, furvm::instruction_t::Jump }, + { token::Jnz, furvm::instruction_t::JumpNotZero }, + { token::Ret, furvm::instruction_t::Return }, }; // NOLINTEND @@ -214,12 +202,12 @@ struct mod_context { handle.dispatch(); } for (auto unknown : label.unknowns) { - std::ptrdiff_t jmpOff = static_cast(label.offset - unknown); + const auto jmpOff = static_cast(label.offset) - static_cast(unknown); if (jmpOff < std::numeric_limits::min() || jmpOff > std::numeric_limits::max()) { assert(false); // TODO: Further jumps are not implemented } - mod.bytecode()[unknown - 1] = jmpOff; + mod.bytecode()[unknown - 1] = static_cast(jmpOff); } label.functions = {}; label.unknowns = {}; @@ -453,10 +441,11 @@ struct mod_context { case token::Ret: { auto it = instructions.find(result->type); assert(it != instructions.end()); - mod.bytecode().push_back(static_cast(it->second.fur)); - switch (it->second.arg) { - case instruction::None: break; - case instruction::Type: { + furvm::instruction instr{ it->second }; + instr.arg.type = furvm::instruction::s_arguments[instr.type]; + switch (instr.arg.type) { + case furvm::instruction_argument::None: break; + case furvm::instruction_argument::Type: { result = eat_token(lexer, token::Dolar); if (!result) return result.error; result = eat_token(lexer, token::Identifier); @@ -464,25 +453,19 @@ struct mod_context { auto type = types.find(std::string(result->value.string)); if (type == types.end()) return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; - auto id = 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); + instr.arg.u32 = type->second.id(); } break; - case instruction::Constant: { + case furvm::instruction_argument::Constant: { assert(false); // TODO: Unimplemented } break; - case instruction::Variable: { + case furvm::instruction_argument::Variable: { result = eat_token(lexer, token::Percent); if (!result) return result.error; result = eat_token(lexer, token::Unsigned); if (!result) return result.error; - std::uint16_t var = result->value.uint; - mod.bytecode().push_back((var >> 0) & 0xFF); - mod.bytecode().push_back((var >> 8) & 0xFF); + instr.arg.u16 = result->value.uint; } break; - case instruction::Function: { + case furvm::instruction_argument::Function: { furvm::function_sig signature; while ((result = next_token(lexer)).error.type == generator_error::Success && result->type == token::Dolar) { @@ -499,11 +482,10 @@ struct mod_context { auto func = functions.find(std::make_pair(name, signature)); if (func == functions.end()) return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; - auto id = func->second.id(); - mod.bytecode().push_back((id >> 0) & 0xFF); - mod.bytecode().push_back((id >> 8) & 0xFF); + auto id = func->second.id(); + instr.arg.u16 = id; } break; - case instruction::Label: { + case furvm::instruction_argument::Offset: { result = eat_token(lexer, token::Sha256); if (!result) return result.error; result = eat_token(lexer, token::Identifier); @@ -511,18 +493,28 @@ struct mod_context { auto& label = labels[std::string(result->value.string)]; auto offset = label.offset; if (offset == label_context::INVALID) { - label.unknowns.push_back(mod.bytecode().size() + 1); - mod.bytecode().push_back(0); - return { generator_error::Success }; + label.unknowns.push_back(mod.bytecode().size() + 2); + instr.arg.s8 = 0; + break; } - std::ptrdiff_t jmpOff = static_cast(offset - mod.bytecode().size() - 1); + const auto jmpOff = + static_cast(offset) - static_cast(mod.bytecode().size()) - 2; if (jmpOff < std::numeric_limits::min() || jmpOff > std::numeric_limits::max()) { assert(false); // TODO: Further jumps are not implemented } - mod.bytecode().push_back(jmpOff); + instr.arg.s8 = static_cast(jmpOff); } 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 }; }