diff --git a/src/engines/v8/generate.zig b/src/engines/v8/generate.zig index 5097b5d..04b1fe6 100644 --- a/src/engines/v8/generate.zig +++ b/src/engines/v8/generate.zig @@ -153,7 +153,7 @@ fn getNativeArg( // JS object const ptr = try getNativeObject(nat_ctx, T_refl, js_value.castTo(v8.Object)); - if (arg_T.underPtr() != null) { + if (comptime arg_T.underPtr() != null) { value = ptr; } else { value = ptr.*; @@ -373,13 +373,14 @@ fn getArgs( fn freeArgs(alloc: std.mem.Allocator, comptime func: refl.Func, obj: anytype) !void { inline for (func.args) |arg_T| { + const underT = comptime arg_T.underT(); // free char slices // the API functions will be responsible of copying the slice // in their implementations if they want to keep it afterwards - if (arg_T.underT() == []u8 or arg_T.underT() == []const u8) { + if (underT == []u8 or underT == []const u8) { const val = @field(obj, arg_T.name.?); - if (arg_T.underOpt() != null) { + if (comptime arg_T.underOpt() != null) { // free only if val is non-null if (val) |v| { alloc.free(v); @@ -390,7 +391,7 @@ fn freeArgs(alloc: std.mem.Allocator, comptime func: refl.Func, obj: anytype) !v } // free varidadic slices - if (try refl.Type.variadic(arg_T.underT(), null) != null) { + if (try refl.Type.variadic(underT, null) != null) { const val = @field(obj, arg_T.name.?).?; // NOTE: variadic are optional by design alloc.free(@field(val, "slice")); @@ -885,7 +886,7 @@ fn callFunc( // call native func const function = @field(T_refl.T, func.name); - const res_T = func.return_type.underErr() orelse func.return_type.T; + const res_T = comptime func.return_type.underErr() orelse func.return_type.T; var res: res_T = undefined; if (comptime @typeInfo(func.return_type.T) == .ErrorUnion) { res = @call(.auto, function, args) catch |err| { @@ -912,7 +913,7 @@ fn callFunc( nat_ctx.alloc, nat_ctx, T_refl, - func.return_type.underT(), + comptime func.return_type.underT(), res, cbk_info.getThis(), isolate, diff --git a/src/generate.zig b/src/generate.zig index 55753f9..a145c51 100644 --- a/src/generate.zig +++ b/src/generate.zig @@ -24,15 +24,16 @@ const loadFn = @import("private_api.zig").loadFn; // reflect the user-defined types to obtain type information (T_refl) // This function must be called at comptime by the root file of the project // and stored in a constant named `Types` -pub fn reflect(comptime types: anytype) []refl.Struct { +pub fn reflect(comptime types: anytype) []const refl.Struct { std.debug.assert(@inComptime()); // call types reflection - return refl.do(types) catch unreachable; + const structs: []const refl.Struct = refl.do(types) catch |e| @compileError(@errorName(e)); + return structs; } // Import user-defined types -pub const Types: []refl.Struct = @import("root").Types; +pub const Types: []const refl.Struct = @import("root").Types; // retrieved the reflected type of a user-defined native type pub fn getType(comptime T: type) refl.Struct { @@ -47,7 +48,7 @@ pub fn getType(comptime T: type) refl.Struct { // generate APIs from reflected types // which can be later loaded in JS. -fn generate(comptime types: []refl.Struct) []API { +fn generate(comptime types: []const refl.Struct) []API { std.debug.assert(@inComptime()); var apis: [types.len]API = undefined; diff --git a/src/reflect.zig b/src/reflect.zig index 7a54613..b20270f 100644 --- a/src/reflect.zig +++ b/src/reflect.zig @@ -73,7 +73,7 @@ pub const Type = struct { T_refl_index: ?usize = null, nested_index: ?usize = null, // T_refl_index is mandatory in this case - union_T: ?[]Type, + union_T: ?[]const Type, pub inline fn isNative(comptime self: Type) bool { comptime { @@ -225,7 +225,7 @@ pub const Type = struct { // find if T is a VariadicType // and returns it as a reflect.Type - pub fn variadic(comptime T: type, comptime structs: ?[]Struct) !?Type { + pub fn variadic(comptime T: type, comptime structs: ?[]const Struct) !?Type { std.debug.assert(@inComptime()); const TT = Type._variadic(T) orelse return null; @@ -241,7 +241,7 @@ pub const Type = struct { } // check that user-defined types have been provided as an API - pub fn lookup(comptime self: *Type, comptime structs: []Struct) Error!void { + pub fn lookup(comptime self: *Type, comptime structs: []const Struct) Error!void { std.debug.assert(@inComptime()); // lookup unecessary @@ -258,9 +258,14 @@ pub const Type = struct { // if union, lookup each possible type if (self.union_T) |union_types| { - inline for (union_types) |*tt| { - try tt.lookup(structs); + var uts: [union_types.len]Type = undefined; + inline for (union_types, 0..) |tt, i| { + var t = tt; + try t.lookup(structs); + uts[i] = t; } + const cuts = uts; + self.union_T = &cuts; return; } @@ -300,7 +305,7 @@ pub const Type = struct { } } - fn reflectUnion(comptime T: type, comptime info: std.builtin.Type) Error![]Type { + fn reflectUnion(comptime T: type, comptime info: std.builtin.Type) Error![]const Type { if (info.Union.tag_type == null) { const msg = "union should be a tagged"; fmtErr(msg.len, msg, T); @@ -310,7 +315,9 @@ pub const Type = struct { inline for (info.Union.fields, 0..) |field, i| { union_types[i] = try Type.reflect(field.type, field.name); } - return &union_types; + + const cunion_types = union_types; + return &cunion_types; } pub fn reflect(comptime T: type, comptime name: ?[]const u8) Error!Type { @@ -319,7 +326,7 @@ pub const Type = struct { const info = @typeInfo(Type._underT(T)); // union T - var union_T: ?[]Type = null; + var union_T: ?[]const Type = null; if (info == .Union) { union_T = try reflectUnion(T, info); } @@ -332,17 +339,19 @@ pub const Type = struct { } } + const cunion_T = union_T; + const t = Type{ .T = T, .name = name, - .union_T = union_T, + .union_T = cunion_T, }; return t; } }; const Args = struct { - fn reflect(comptime self_T: ?type, comptime args: []Type) type { + fn reflect(comptime self_T: ?type, comptime args: []const Type) type { var len = args.len; if (self_T != null) { len += 1; @@ -379,10 +388,11 @@ const Args = struct { .alignment = @alignOf(arg.T), }; } - const decls: [0]std.builtin.Type.Declaration = undefined; + const decls = [_]std.builtin.Type.Declaration{}; + const cfields = fields; const s = std.builtin.Type.Struct{ .layout = .auto, - .fields = &fields, + .fields = &cfields, .decls = &decls, .is_tuple = true, }; @@ -445,7 +455,7 @@ pub const Func = struct { name: []const u8, // func signature - args: []Type, + args: []const Type, args_T: type, first_optional_arg: ?usize, @@ -462,10 +472,16 @@ pub const Func = struct { setter_index: ?u8, // TODO: not ideal, is there a cleaner solution? - fn lookupTypes(comptime self: *Func, comptime structs: []Struct) Error!void { - inline for (self.args) |*arg| { - try arg.lookup(structs); + fn lookupTypes(comptime self: *Func, comptime structs: []const Struct) Error!void { + // copy args + var args: [self.args.len]Type = undefined; + inline for (self.args, 0..) |arg, i| { + var a = arg; + try a.lookup(structs); + args[i] = a; } + const cargs = args; + self.args = &cargs; try self.return_type.lookup(structs); } @@ -642,8 +658,8 @@ pub const Func = struct { const js_name = jsName(field_name); // reflect args - const args_slice = args_types[0..]; - const args_T = comptime Args.reflect(self_T, args_slice); + const args_slice = args_types; + const args_T = comptime Args.reflect(self_T, &args_slice); // reflect return type const return_type = try Type.reflect(func.Fn.return_type.?, null); @@ -654,7 +670,7 @@ pub const Func = struct { .name = name, // func signature - .args = args_slice, + .args = &args_slice, .args_T = args_T, .first_optional_arg = first_optional_arg, @@ -676,7 +692,7 @@ pub const Func = struct { pub const StructNested = struct { T: type, - fields: []Type, + fields: []const Type, fn isNested(comptime T: type, comptime decl: std.builtin.Type.Declaration) bool { // special keywords @@ -710,7 +726,8 @@ pub const StructNested = struct { inline for (info.Struct.fields, 0..) |field, i| { fields[i] = try Type.reflect(field.type, field.name); } - return .{ .T = T, .fields = &fields }; + const cfields = fields; + return .{ .T = T, .fields = &cfields }; } }; @@ -738,12 +755,12 @@ pub const Struct = struct { has_constructor: bool, constructor: Func, - getters: []Func, - setters: []Func, - methods: []Func, + getters: []const Func, + setters: []const Func, + methods: []const Func, // nested types - nested: []StructNested, + nested: []const StructNested, pub fn Self(comptime self: Struct) type { comptime { @@ -789,20 +806,54 @@ pub const Struct = struct { if (self.has_constructor) { try self.constructor.lookupTypes(structs); } - inline for (self.getters) |*getter| { - try getter.lookupTypes(structs); - } - inline for (self.setters) |*setter| { - try setter.lookupTypes(structs); - } - inline for (self.methods) |*method| { - try method.lookupTypes(structs); - } - inline for (self.nested) |nested| { - inline for (nested.fields) |*field| { - try field.lookup(structs); + + // copy getters + var getters: [self.getters.len]Func = undefined; + inline for (self.getters, 0..) |getter, i| { + var f = getter; + try f.lookupTypes(structs); + getters[i] = f; + } + const cgetters = getters; + self.getters = &cgetters; + + // copy setters + var setters: [self.setters.len]Func = undefined; + inline for (self.setters, 0..) |setter, i| { + var f = setter; + try f.lookupTypes(structs); + setters[i] = f; + } + const csetters = setters; + self.setters = &csetters; + + // copy methods + var methods: [self.methods.len]Func = undefined; + inline for (self.methods, 0..) |method, i| { + var f = method; + try f.lookupTypes(structs); + methods[i] = f; + } + const cmethods = methods; + self.methods = &cmethods; + + // copy nested + var nesteds: [self.nested.len]StructNested = undefined; + inline for (self.nested, 0..) |nested, i| { + var n = nested; + // copy fields + var fields: [nested.fields.len]Type = undefined; + inline for (nested.fields, 0..) |field, j| { + var f = field; + try f.lookup(structs); + fields[j] = f; } + const cfields = fields; + n.fields = &cfields; + nesteds[i] = n; } + const cnesteds = nesteds; + self.nested = &cnesteds; } fn lessThan(_: void, comptime a: Struct, comptime b: Struct) bool { @@ -905,10 +956,11 @@ pub const Struct = struct { }; attrs_done += 1; } + const cfields = fields; return @Type(.{ .Struct = .{ .layout = .auto, - .fields = &fields, + .fields = &cfields, .decls = &.{}, .is_tuple = false, }, @@ -998,7 +1050,7 @@ pub const Struct = struct { // Retrieve the optional Exception of the API, // including from prototype chain - pub fn exception(comptime self: Struct, comptime all: []Struct) ?Struct { + pub fn exception(comptime self: Struct, comptime all: []const Struct) ?Struct { std.debug.assert(@inComptime()); // errors have already been checked at lookup stage @@ -1323,6 +1375,11 @@ pub const Struct = struct { } } + const cgetters = getters; + const csetters = setters; + const cmethods = methods; + const cnested = nested; + return Struct{ // struct info .name = struct_name, @@ -1343,12 +1400,12 @@ pub const Struct = struct { // struct functions .has_constructor = has_constructor, .constructor = constructor, - .getters = getters[0..], - .setters = setters[0..], - .methods = methods[0..], + .getters = &cgetters, + .setters = &csetters, + .methods = &cmethods, // nested types - .nested = nested[0..], + .nested = &cnested, }; } }; @@ -1432,7 +1489,7 @@ fn lookupException(comptime all: []Struct) Error!void { } } -pub fn do(comptime types: anytype) Error![]Struct { +pub fn do(comptime types: anytype) Error![]const Struct { comptime { // check types provided @@ -1475,7 +1532,9 @@ pub fn do(comptime types: anytype) Error![]Struct { try s.lookupTypes(&all); } - return &all; + // handle comptime var. + const call = all; + return &call; } } @@ -1597,7 +1656,7 @@ fn assertFuncReturnT(comptime func: type, comptime T: type, comptime opts: EqlOp // createTupleT generate a tuple type // with the members passed as fields -fn createTupleT(comptime members: []type) type { +fn createTupleT(comptime members: []const type) type { var fields: [members.len]std.builtin.Type.StructField = undefined; for (members, 0..) |member, i| { fields[i] = std.builtin.Type.StructField{ @@ -1612,9 +1671,10 @@ fn createTupleT(comptime members: []type) type { .alignment = @alignOf(member), }; } + const cfields = fields; const s = std.builtin.Type.Struct{ .layout = .auto, - .fields = &fields, + .fields = &cfields, .decls = &.{}, .is_tuple = true, }; @@ -1631,7 +1691,8 @@ fn argsT(comptime func: type) type { for (info.params, 0..) |param, i| { params[i] = param.type.?; } - return createTupleT(¶ms); + const cparams = params; + return createTupleT(&cparams); } // public functions @@ -1720,7 +1781,8 @@ fn jsName(comptime name: []const u8) []const u8 { } js_name[i] = char; } - return &js_name; + const cname = js_name; + return &cname; } fn shortName(comptime T: type) []const u8 { @@ -1728,9 +1790,11 @@ fn shortName(comptime T: type) []const u8 { return it.first(); } -pub fn itoa(i: u8) ![]u8 { +pub fn itoa(i: u8) ![]const u8 { var buf: [1]u8 = undefined; - return try std.fmt.bufPrint(buf[0..], "{d}", .{i}); + _ = try std.fmt.bufPrint(buf[0..], "{d}", .{i}); + const cbuf = buf; + return &cbuf; } fn isStringLiteral(comptime T: type) bool { diff --git a/src/refs.zig b/src/refs.zig index 75e0dc3..b26c2a4 100644 --- a/src/refs.zig +++ b/src/refs.zig @@ -11,7 +11,7 @@ const refl = internal.refl; // - value is the index of API pub const Map = std.AutoHashMapUnmanaged(usize, usize); -pub fn getObject(map: Map, comptime T: type, comptime types: []refl.Struct, ptr: anytype) !*T { +pub fn getObject(map: Map, comptime T: type, comptime types: []const refl.Struct, ptr: anytype) !*T { // use the object pointer (key) to retrieve the API index (value) in the map const ptr_aligned: *align(@alignOf(usize)) anyopaque = @alignCast(ptr);