fix(furvm, furas): fix function signature matching

This commit is contained in:
2026-08-15 00:32:57 +02:00
parent 4ede6f3476
commit 6737ed86b0
4 changed files with 133 additions and 76 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
type arr = array $s8 10 type arr = array $s8 10
func println $arr = native println func println ref $arr = native println
public func main = #main public func main = #main
main: main:
@@ -30,5 +30,5 @@ body:
end: end:
drop drop
load %0 load %0
call $arr println call ref $arr println
ret ret
+101 -69
View File
@@ -127,11 +127,7 @@ struct mod_context {
}; };
furvm::mod mod; furvm::mod mod;
std::unordered_map<std::pair<std::string, furvm::function_sig>, std::unordered_map<std::string, std::vector<furvm::function_h>> functions;
furvm::function_h,
furlang::utility::
pair_hash<std::string, furvm::function_sig, std::hash<std::string>, furvm::detail::function_sig_hash>>
functions;
std::unordered_map<std::string, furvm::mod_type_h> types; std::unordered_map<std::string, furvm::mod_type_h> types;
std::unordered_map<std::string, std::uint16_t> variables; std::unordered_map<std::string, std::uint16_t> variables;
@@ -147,6 +143,46 @@ struct mod_context {
bool operator!() const { return error.type != generator_error::Success; } 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() { mod_context() {
types.emplace("s8", mod.emplace_type(furvm::mod_type::S8)); types.emplace("s8", mod.emplace_type(furvm::mod_type::S8));
types.emplace("u8", mod.emplace_type(furvm::mod_type::U8)); types.emplace("u8", mod.emplace_type(furvm::mod_type::U8));
@@ -182,6 +218,44 @@ struct mod_context {
return { { generator_error::Success }, token.value }; 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) { generator_error generate(lexer& lexer) {
auto result = next_token(lexer); auto result = next_token(lexer);
if (result.error.type == generator_error::UnexpectedEof) return { generator_error::Eof }; 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) (func.pub ? mod.emplace_function(func.name, std::move(func.signature), label.offset)
: mod.emplace_function(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(); handle.dispatch();
} }
for (auto unknown : label.unknowns) { for (auto unknown : label.unknowns) {
@@ -251,14 +324,8 @@ struct mod_context {
result = next_token(lexer); result = next_token(lexer);
if (!result) return result.error; if (!result) return result.error;
while (result->type == token::Dolar) { while (result->type != token::EqSign) {
result = eat_token(lexer, token::Identifier); signature.params.push_back(eat_type(lexer, result.value));
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) };
}
result = next_token(lexer); result = next_token(lexer);
if (!result) return result.error; if (!result) return result.error;
@@ -280,13 +347,15 @@ struct mod_context {
if (!result) return result.error; 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) { switch (result->type) {
case token::Sha256: { case token::Sha256: {
result = eat_token(lexer, token::Identifier); result = eat_token(lexer, token::Identifier);
if (!result) return result.error; if (!result) return result.error;
std::string name = std::string(nameRes->value.string);
std::string labelName = std::string(result->value.string); std::string labelName = std::string(result->value.string);
std::size_t offset = 0; std::size_t offset = 0;
if (auto it = labels.find(labelName); it != labels.end()) { if (auto it = labels.find(labelName); it != labels.end()) {
@@ -299,10 +368,9 @@ struct mod_context {
furvm::function_h handle = furvm::function_h handle =
(pub ? mod.emplace_function(name, signature, offset) : mod.emplace_function(signature, offset)); (pub ? mod.emplace_function(name, signature, offset) : mod.emplace_function(signature, offset));
functions[name].push_back(handle);
functions.emplace(std::make_pair(name, std::move(signature)), handle);
handle.dispatch(); handle.dispatch();
return { generator_error::Success }; return { generator_error::Success };
} }
case token::Native: { case token::Native: {
@@ -315,10 +383,9 @@ struct mod_context {
furvm::function_h handle = (pub ? mod.emplace_function(name, signature, std::move(nativeName)) furvm::function_h handle = (pub ? mod.emplace_function(name, signature, std::move(nativeName))
: mod.emplace_function(signature, std::move(nativeName))); : mod.emplace_function(signature, std::move(nativeName)));
functions[name].push_back(handle);
functions.emplace(std::make_pair(name, std::move(signature)), handle);
handle.dispatch(); handle.dispatch();
return { generator_error::Success }; return { generator_error::Success };
} }
case token::Import: { case token::Import: {
@@ -340,42 +407,11 @@ struct mod_context {
result = next_token(lexer); result = next_token(lexer);
if (!result) return result.error; if (!result) return result.error;
switch (result->type) {
case token::Import: { auto type = eat_type(lexer, result.value);
auto typeNameRes = eat_token(lexer, token::Identifier); types.emplace(std::string(nameRes->value.string), std::move(type));
if (!typeNameRes) return typeNameRes.error;
return { generator_error::Success }; 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`" };
}
}
return { generator_error::UnexpectedToken, return { generator_error::UnexpectedToken,
"Unexpected token "s + token_type(result->type) + ", expected either `func` or `type`" }; "Unexpected token "s + token_type(result->type) + ", expected either `func` or `type`" };
@@ -450,6 +486,8 @@ struct mod_context {
case token::Lenof: case token::Lenof:
case token::Load: case token::Load:
case token::Store: case token::Store:
case token::LoadGlobal:
case token::StoreGlobal:
case token::Call: case token::Call:
case token::Jmp: case token::Jmp:
case token::Jnz: case token::Jnz:
@@ -493,22 +531,16 @@ struct mod_context {
case furvm::instruction_argument::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::Identifier) {
result = eat_token(lexer, token::Identifier); signature.params.push_back(eat_type(lexer, result.value));
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);
} }
if (!result || result->type != token::Identifier) return result.error; if (!result || result->type != token::Identifier) return result.error;
std::string name(result->value.string); std::string name(result->value.string);
auto func = functions.find(std::make_pair(name, signature)); auto func = find_function(name, signature);
if (func == functions.end()) if (func.empty())
return { generator_error::UnknownType, "Unknown type "s + std::string(result->value.string) }; return { generator_error::UnknownType, "Unknown function "s + std::string(result->value.string) };
auto id = func->second.id(); instr.arg.u16 = func.id();
instr.arg.u16 = id;
} break; } break;
case furvm::instruction_argument::Offset: { case furvm::instruction_argument::Offset: {
result = eat_token(lexer, token::Sha256); result = eat_token(lexer, token::Sha256);
+2
View File
@@ -173,6 +173,8 @@ private:
thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const; thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const;
thing<> make_reference(const thing<>& thing) const; thing<> make_reference(const thing<>& thing) const;
private:
static bool compare_thing_types(const thing_type& lhs, const thing_type& rhs);
private: private:
executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization)
context* m_context; context* m_context;
+25 -2
View File
@@ -33,12 +33,14 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const {
case thing_type::U32: case thing_type::U32:
case thing_type::U64: return { static_cast<enum thing_type::type>(type.type) }; case thing_type::U64: return { static_cast<enum thing_type::type>(type.type) };
case thing_type::Ptr: return { thing_type::Ptr, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) }; 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: { case thing_type::Array: {
return { static_cast<enum thing_type::type>(type.type), return { static_cast<enum thing_type::type>(type.type),
{ mod_to_thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; { 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 { 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); 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) { void executor::push_frame(const mod_h& mod, function function) {
mod_h modInst = mod; mod_h modInst = mod;
while (function.type() == function_t::Import) { 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()); args.reserve(signature.params.size());
for (const auto& param : signature.params) { for (const auto& param : signature.params) {
auto arg = pop_thing(); 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"); throw std::runtime_error("function argument type mismatch");
args.push_back(std::move(arg)); args.push_back(std::move(arg));
} }