From 6737ed86b08cbf26de78942147774a7b6827ae1d Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sat, 15 Aug 2026 00:32:57 +0200 Subject: [PATCH] fix(furvm, furas): fix function signature matching --- furas/examples/array2.furas | 4 +- furas/src/gen.cpp | 176 ++++++++++++++++++------------- furvm/include/furvm/executor.hpp | 2 + furvm/src/executor.cpp | 27 ++++- 4 files changed, 133 insertions(+), 76 deletions(-) diff --git a/furas/examples/array2.furas b/furas/examples/array2.furas index e2d268c..7f6cec9 100644 --- a/furas/examples/array2.furas +++ b/furas/examples/array2.furas @@ -1,6 +1,6 @@ type arr = array $s8 10 -func println $arr = native println +func println ref $arr = native println public func main = #main main: @@ -30,5 +30,5 @@ body: end: drop load %0 - call $arr println + call ref $arr println ret diff --git a/furas/src/gen.cpp b/furas/src/gen.cpp index e6d1245..6d6c9ee 100644 --- a/furas/src/gen.cpp +++ b/furas/src/gen.cpp @@ -126,14 +126,10 @@ struct mod_context { std::vector unknowns; }; - furvm::mod mod; - std::unordered_map, - furvm::function_h, - furlang::utility:: - pair_hash, furvm::detail::function_sig_hash>> - functions; - std::unordered_map types; - std::unordered_map variables; + furvm::mod mod; + std::unordered_map> functions; + std::unordered_map types; + std::unordered_map variables; std::unordered_map labels; @@ -147,6 +143,46 @@ struct mod_context { bool operator!() const { return error.type != generator_error::Success; } }; + bool compare_types(const furvm::mod_type_h& lhs, const furvm::mod_type_h& rhs) const { + if (lhs->type != rhs->type) return false; + switch (lhs->type) { + case furvm::mod_type::S8: + case furvm::mod_type::S16: + case furvm::mod_type::S32: + case furvm::mod_type::S64: + case furvm::mod_type::U8: + case furvm::mod_type::U16: + case furvm::mod_type::U32: + case furvm::mod_type::U64: return true; + case furvm::mod_type::Ptr: + case furvm::mod_type::Ref: + return compare_types(mod.type_at(lhs->value.typeRef), mod.type_at(rhs->value.typeRef)); + case furvm::mod_type::Array: + return lhs->value.array.size == rhs->value.array.size && + compare_types(mod.type_at(lhs->value.array.typeId), mod.type_at(rhs->value.array.typeId)); + case furvm::mod_type::Import: + return lhs->value.imprt.modId == rhs->value.imprt.modId && + lhs->value.imprt.typeId == rhs->value.imprt.typeId; + case furvm::mod_type::Count: break; + } + throw std::runtime_error("unreachable"); + } + + furvm::function_h find_function(const std::string& name, const furvm::function_sig& signature) const { + if (auto it = functions.find(name); it != functions.end()) { + for (const auto& func : it->second) { + if (func->signature().params.size() != signature.params.size()) continue; + std::size_t idx = 0; + while (idx < signature.params.size()) { + if (!compare_types(func->signature().params[idx], signature.params[idx])) break; + ++idx; + } + if (idx == signature.params.size()) return func; + } + } + return {}; + } + mod_context() { types.emplace("s8", mod.emplace_type(furvm::mod_type::S8)); types.emplace("u8", mod.emplace_type(furvm::mod_type::U8)); @@ -182,6 +218,44 @@ struct mod_context { return { { generator_error::Success }, token.value }; } + furvm::mod_type_h eat_type(lexer& lexer, const token& tok) { + switch (tok.type) { + case token::Dolar: { + auto result = eat_token(lexer, token::Identifier); + if (auto it = types.find(std::string(result->value.string)); it != types.end()) { + return it->second; + } + throw std::runtime_error("unknown type"); + } + case token::Import: { + throw std::runtime_error("unimplemented"); + // auto typeNameRes = eat_token(lexer, token::Identifier); + // if (!typeNameRes) return typeNameRes.error; + // return { generator_error::Success }; + } + case token::Ref: { + auto result = next_token(lexer); + if (!result) throw std::runtime_error("error"); + + auto inner = eat_type(lexer, result.value); + + return mod.emplace_type(furvm::mod_type::Ref, inner.id()); + } + case token::Array: { + auto result = next_token(lexer); + if (!result) throw std::runtime_error("error"); + + auto inner = eat_type(lexer, result.value); + + auto size = eat_token(lexer, token::Unsigned); + if (!size) throw std::runtime_error("error"); + + return mod.emplace_type(inner.id(), size->value.uint); + } + default: throw std::runtime_error("error"); + } + } + generator_error generate(lexer& lexer) { auto result = next_token(lexer); if (result.error.type == generator_error::UnexpectedEof) return { generator_error::Eof }; @@ -203,8 +277,7 @@ struct mod_context { (func.pub ? mod.emplace_function(func.name, std::move(func.signature), label.offset) : mod.emplace_function(std::move(func.signature), label.offset)); - functions.emplace(std::make_pair(std::move(func.name), std::move(func.signature)), handle); - + functions[std::move(func.name)].push_back(handle); handle.dispatch(); } for (auto unknown : label.unknowns) { @@ -251,14 +324,8 @@ struct mod_context { result = next_token(lexer); if (!result) return result.error; - while (result->type == token::Dolar) { - result = eat_token(lexer, token::Identifier); - if (!result) return result.error; - if (auto it = types.find(std::string(result->value.string)); it != types.end()) { - signature.params.push_back(it->second); - } else { - return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; - } + while (result->type != token::EqSign) { + signature.params.push_back(eat_type(lexer, result.value)); result = next_token(lexer); if (!result) return result.error; @@ -280,13 +347,15 @@ struct mod_context { if (!result) return result.error; } + std::string name = std::string(nameRes->value.string); + + if (!find_function(name, signature).empty()) throw std::runtime_error("function already defined"); + switch (result->type) { case token::Sha256: { result = eat_token(lexer, token::Identifier); if (!result) return result.error; - std::string name = std::string(nameRes->value.string); - std::string labelName = std::string(result->value.string); std::size_t offset = 0; if (auto it = labels.find(labelName); it != labels.end()) { @@ -299,10 +368,9 @@ struct mod_context { furvm::function_h handle = (pub ? mod.emplace_function(name, signature, offset) : mod.emplace_function(signature, offset)); - - functions.emplace(std::make_pair(name, std::move(signature)), handle); - + functions[name].push_back(handle); handle.dispatch(); + return { generator_error::Success }; } case token::Native: { @@ -315,10 +383,9 @@ struct mod_context { furvm::function_h handle = (pub ? mod.emplace_function(name, signature, std::move(nativeName)) : mod.emplace_function(signature, std::move(nativeName))); - - functions.emplace(std::make_pair(name, std::move(signature)), handle); - + functions[name].push_back(handle); handle.dispatch(); + return { generator_error::Success }; } case token::Import: { @@ -340,41 +407,10 @@ struct mod_context { result = next_token(lexer); if (!result) return result.error; - switch (result->type) { - case token::Import: { - auto typeNameRes = eat_token(lexer, token::Identifier); - if (!typeNameRes) return typeNameRes.error; - return { generator_error::Success }; - } - case token::Array: { - result = eat_token(lexer, token::Dolar); - if (!result) return result.error; - auto typeNameRes = eat_token(lexer, token::Identifier); - if (!typeNameRes) return typeNameRes.error; - - auto size = eat_token(lexer, token::Unsigned); - if (!size) return size.error; - - furvm::mod_type_id innerId = 0; - if (auto it = types.find(std::string(typeNameRes->value.string)); it != types.end()) { - innerId = it->second.id(); - } else { - return { generator_error::UnknownType, - "Unknown type "s + std::string(typeNameRes->value.string) }; - } - - auto type = mod.emplace_type(innerId, size->value.uint); - types.emplace(std::string(nameRes->value.string), type); - type.dispatch(); - - return { generator_error::Success }; - } - default: - return { generator_error::UnexpectedToken, - "Unexpected token "s + token_type(result->type) + - ", expected either type, `import`, or `array`" }; - } + auto type = eat_type(lexer, result.value); + types.emplace(std::string(nameRes->value.string), std::move(type)); + return { generator_error::Success }; } return { generator_error::UnexpectedToken, @@ -450,6 +486,8 @@ struct mod_context { case token::Lenof: case token::Load: case token::Store: + case token::LoadGlobal: + case token::StoreGlobal: case token::Call: case token::Jmp: case token::Jnz: @@ -493,22 +531,16 @@ struct mod_context { case furvm::instruction_argument::Function: { furvm::function_sig signature; while ((result = next_token(lexer)).error.type == generator_error::Success && - result->type == token::Dolar) { - result = eat_token(lexer, token::Identifier); - if (!result) return result.error; - 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) }; - signature.params.push_back(type->second); + result->type != token::Identifier) { + signature.params.push_back(eat_type(lexer, result.value)); } if (!result || result->type != token::Identifier) return result.error; std::string name(result->value.string); - 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(); - instr.arg.u16 = id; + auto func = find_function(name, signature); + if (func.empty()) + return { generator_error::UnknownType, "Unknown function "s + std::string(result->value.string) }; + instr.arg.u16 = func.id(); } break; case furvm::instruction_argument::Offset: { result = eat_token(lexer, token::Sha256); diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 3fb36e4..b9f4ca5 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -173,6 +173,8 @@ private: thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const; thing<> make_reference(const thing<>& thing) const; +private: + static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs); private: executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) context* m_context; diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index f18e434..1e70809 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -33,12 +33,14 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const { case thing_type::U32: case thing_type::U64: return { static_cast(type.type) }; case thing_type::Ptr: return { thing_type::Ptr, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) }; + case thing_type::Ref: return { thing_type::Ref, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) }; case thing_type::Array: { return { static_cast(type.type), { mod_to_thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; } - default: throw std::runtime_error("invalid thing type"); + case thing_type::Count: break; } + throw std::runtime_error("invalid thing type"); } thing_type* executor::mod_to_thing_type(const mod_h& mod, const mod_type& type) const { @@ -53,6 +55,27 @@ thing<> executor::make_reference(const thing<>& thing) const { return std::move(ref); } +bool executor::compare_thing_types(const thing_type& lhs, const thing_type& rhs) { + if (lhs.type != rhs.type) return false; + switch (lhs.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: return true; + case thing_type::Ptr: + case thing_type::Ref: return compare_thing_types(*lhs.value.typeRef, *rhs.value.typeRef); + case thing_type::Array: + return lhs.value.array.size == rhs.value.array.size && + compare_thing_types(*lhs.value.array.type, *rhs.value.array.type); + case thing_type::Count: break; + } + throw std::runtime_error("unreachable"); +} + void executor::push_frame(const mod_h& mod, function function) { mod_h modInst = mod; while (function.type() == function_t::Import) { @@ -65,7 +88,7 @@ void executor::push_frame(const mod_h& mod, function function) { args.reserve(signature.params.size()); for (const auto& param : signature.params) { auto arg = pop_thing(); - if (arg.true_type() != *mod_to_thing_type(mod, *param)) + if (compare_thing_types(arg.type(), *mod_to_thing_type(mod, *param))) throw std::runtime_error("function argument type mismatch"); args.push_back(std::move(arg)); }