-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Call arbitrary function with argument struct #2930
Comments
I managed to find a work around for a limited number of arguments: fn call(L: ?*lua.lua_State) (if (Fn.return_type) |rt| rt else noreturn) {
if (Fn.args.len == 0) return @inlineCall(func);
const a1 = check(L, 1, Fn.args[0].arg_type.?);
if (Fn.args.len == 1) return @inlineCall(func, a1);
const a2 = check(L, 2, Fn.args[1].arg_type.?);
if (Fn.args.len == 2) return @inlineCall(func, a1, a2);
const a3 = check(L, 3, Fn.args[2].arg_type.?);
if (Fn.args.len == 3) return @inlineCall(func, a1, a2, a3);
const a4 = check(L, 4, Fn.args[3].arg_type.?);
if (Fn.args.len == 4) return @inlineCall(func, a1, a2, a3, a4);
const a5 = check(L, 5, Fn.args[4].arg_type.?);
if (Fn.args.len == 5) return @inlineCall(func, a1, a2, a3, a4, a5);
const a6 = check(L, 6, Fn.args[5].arg_type.?);
if (Fn.args.len == 6) return @inlineCall(func, a1, a2, a3, a4, a5, a6);
const a7 = check(L, 7, Fn.args[6].arg_type.?);
if (Fn.args.len == 7) return @inlineCall(func, a1, a2, a3, a4, a5, a6, a7);
const a8 = check(L, 8, Fn.args[7].arg_type.?);
if (Fn.args.len == 8) return @inlineCall(func, a1, a2, a3, a4, a5, a6, a7, a8);
const a9 = check(L, 9, Fn.args[8].arg_type.?);
if (Fn.args.len == 9) return @inlineCall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9);
@compileError("NYI: >9 argument functions");
} |
This is now possible with @call. It works with tuple arguments, but not struct arguments yet. There is not an issue open for the latter yet, but the compile error you get points out that this is planned. |
Is this expected? var args = .{};
inline for (Fn.args) |arg, i| {
const a = check(L, i+1, arg.arg_type.?);
args = args ++ .{ a };
}
const result = @call(.{ .modifier = .always_inline }, func, args);
Similar if I write |
Not sure why I closed this earlier without implementing it fully and adding tests. Anyway #2930 (comment) looks like a separate issue having to do with either tuple concatenation, or the type of a comptime variable changing, or both. |
#4573 helped a little here, I was able to do a tail-recursive thing to remove the limit: return struct {
// See https://github.com/ziglang/zig/issues/2930
fn call(L: ?*lua.lua_State, args: var) (if (Fn.return_type) |rt| rt else void) {
if (Fn.args.len == args.len) {
return @call(.{}, func, args);
} else {
const i = args.len;
const a = check(L, i + 1, Fn.args[i].arg_type.?);
return @call(.{ .modifier = .always_inline }, call, .{ L, args ++ .{a} });
}
}
fn thunk(L: ?*lua.lua_State) callconv(.C) c_int {
const result = @call(.{ .modifier = .always_inline }, call, .{ L, .{} });
if (@TypeOf(result) == void) {
return 0;
} else {
push(L, result);
return 1;
}
}
}.thunk; I'd prefer to be able to use the following instead: var args = .{};
inline for (Fn.args) |arg, i| {
var a = check(L, i + 1, arg.arg_type.?);
args = args ++ .{a};
}
const result = @call(.{}, func, args); Which now fails with:
But I understand that it is sort of mutating the type of |
with thanks to @ifreund const std = @import("std");
const ArgTypeMagic = struct {
args: anytype,
};
fn ArgType(func: anytype) type {
const Fn = @typeInfo(@TypeOf(func)).Fn;
const tuple = .{};
comptime var magic = ArgTypeMagic{ .args = tuple };
inline for (Fn.args) |arg, i| {
magic.args = magic.args ++ .{@as(arg.arg_type.?, undefined)};
}
return @TypeOf(magic.args);
}
fn bar(a: u32, b: i32) void {
std.debug.print("{} {}\n", .{a, b});
}
pub fn main() anyerror!void {
const T = ArgType(bar);
@call(.{}, bar, T{1,2});
} edit: trying to use this I get "cannot assign to constant"; so seems like a no-go. |
I think we can close this now with #6415 merged. The following works: const std = @import("std");
fn bar(a: [*:0]const u8, b: i32) void {
std.debug.print("{} {}\n", .{ a, b });
}
pub fn main() anyerror!void {
const T = std.meta.ArgsTuple(@TypeOf(bar));
// argv[0] just to make sure the value is runtime
@call(.{}, bar, T{ std.os.argv[0], 2 });
} |
It worked! daurnimator/zig-autolua@3c71377 |
I would like to be able to construct the arguments for a function and then call it.
e.g.
Example use case:
The text was updated successfully, but these errors were encountered: