Skip to content

Commit

Permalink
fix(ffi): Allow multiple declaration in a single zdef statement
Browse files Browse the repository at this point in the history
  • Loading branch information
giann committed Aug 30, 2023
1 parent 1c7bdc2 commit 81c9c72
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 109 deletions.
46 changes: 23 additions & 23 deletions examples/sdl.buzz
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import "ffi";
import "buffer";
import "debug";

zdef("SDL2", "const SDL_Window = opaque{};");
zdef("SDL2", "const SDL_Renderer = opaque{};");
zdef("SDL2", "const SDL_Texture = opaque{};");
| Until we know how to use unions, this struct needs to be padded to allocate enough space for an actual SDL_Event (56 bytes)
zdef("SDL2", `
const SDL_Window = opaque{};
const SDL_Renderer = opaque{};
const SDL_Texture = opaque{};

// TODO: union
const SDL_Event = extern struct{
type: u32,
pad01: i32,
Expand All @@ -24,32 +25,31 @@ zdef("SDL2", `
pad12: i32,
pad13: i32,
};
`);
zdef("SDL2", `

const SDL_Rect = extern struct {
x: c_int,
y: c_int,
w: c_int,
h: c_int,
};
`);

zdef("SDL2", "fn SDL_GetError() [*:0]const u8;");
zdef("SDL2", "fn SDL_Init(flags: u32) c_int;");
zdef("SDL2", "fn SDL_CreateWindow(title: [*:0]const u8, x: c_int, y: c_int, w: c_int, h: c_int, flags: u32) ?*SDL_Window;");
zdef("SDL2", "fn SDL_DestroyRenderer(renderer: *SDL_Renderer) void;");
zdef("SDL2", "fn SDL_CreateRenderer(window: *SDL_Window, index: c_int, flags: u32) ?*SDL_Renderer;");
zdef("SDL2", "fn SDL_RenderPresent(renderer: *SDL_Renderer) void;");
zdef("SDL2", "fn SDL_DestroyWindow(window: *SDL_Window) void;");
zdef("SDL2", "fn SDL_Delay(ms: u32) void;");
zdef("SDL2", "fn SDL_Quit() void;");
zdef("SDL2", "fn SDL_RenderFillRect(renderer: *SDL_Renderer, rect: *const SDL_Rect) c_int;");
zdef("SDL2", "fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8) c_int;");
zdef("SDL2", "fn SDL_PollEvent(event: *SDL_Event) c_int;");
zdef("SDL2", "fn SDL_CreateTexture(renderer: *SDL_Renderer, format: u32, access: c_int, w: c_int, h: c_int) ?*SDL_Texture;");
zdef("SDL2", "fn SDL_DestroyTexture(texture: *SDL_Texture) void;");
zdef("SDL2", "fn SDL_SetRenderTarget(renderer: *SDL_Renderer, texture: ?*SDL_Texture) c_int;");
zdef("SDL2", "fn SDL_RenderCopy(renderer: *SDL_Renderer, texture: *SDL_Texture, srcrect: ?*const SDL_Rect, dstrect: ?*const SDL_Rect) c_int;");
fn SDL_GetError() [*:0]const u8;
fn SDL_Init(flags: u32) c_int;
fn SDL_CreateWindow(title: [*:0]const u8, x: c_int, y: c_int, w: c_int, h: c_int, flags: u32) ?*SDL_Window;
fn SDL_DestroyRenderer(renderer: *SDL_Renderer) void;
fn SDL_CreateRenderer(window: *SDL_Window, index: c_int, flags: u32) ?*SDL_Renderer;
fn SDL_RenderPresent(renderer: *SDL_Renderer) void;
fn SDL_DestroyWindow(window: *SDL_Window) void;
fn SDL_Delay(ms: u32) void;
fn SDL_Quit() void;
fn SDL_RenderFillRect(renderer: *SDL_Renderer, rect: *const SDL_Rect) c_int;
fn SDL_SetRenderDrawColor(renderer: *SDL_Renderer, r: u8, g: u8, b: u8, a: u8) c_int;
fn SDL_PollEvent(event: *SDL_Event) c_int;
fn SDL_CreateTexture(renderer: *SDL_Renderer, format: u32, access: c_int, w: c_int, h: c_int) ?*SDL_Texture;
fn SDL_DestroyTexture(texture: *SDL_Texture) void;
fn SDL_SetRenderTarget(renderer: *SDL_Renderer, texture: ?*SDL_Texture) c_int;
fn SDL_RenderCopy(renderer: *SDL_Renderer, texture: *SDL_Texture, srcrect: ?*const SDL_Rect, dstrect: ?*const SDL_Rect) c_int;
`);

const float SDL_INIT_VIDEO = 32.0;
const int SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000;
Expand Down
4 changes: 2 additions & 2 deletions src/buzz_api.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1300,7 +1300,7 @@ export fn dumpInt(value: u64) void {
std.debug.print("-> {x}\n", .{value});
}

export fn bz_zigType(vm: *VM, ztype: [*]const u8, len: usize, expected_type: *Value) ?*ZigType {
export fn bz_zigType(vm: *VM, ztype: [*]const u8, len: usize, expected_type: *Value) ?*const ZigType {
const zdef = vm.ffi.parseTypeExpr(ztype[0..len]) catch return null;

if (zdef) |uzdef| {
Expand Down Expand Up @@ -1508,7 +1508,7 @@ export fn bz_readZigValueFromBuffer(
export fn bz_writeZigValueToBuffer(
vm: *VM,
value: Value,
ztype: *ZigType,
ztype: *const ZigType,
at: usize,
buf: [*]u8,
capacity: usize,
Expand Down
75 changes: 52 additions & 23 deletions src/ffi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ pub const State = struct {
ast: Ast,
parser: ?*p.Parser,
parsing_type_expr: bool = false,
structs: std.StringHashMap(*Zdef),
};

gc: *m.GarbageCollector,
Expand Down Expand Up @@ -220,12 +221,17 @@ pub fn parseTypeExpr(self: *Self, ztype: []const u8) !?*Zdef {
true,
);

self.type_expr_cache.put(ztype, zdef) catch @panic("Out of memory");
std.debug.assert(zdef == null or zdef.?.len == 1);

return zdef;
self.type_expr_cache.put(
ztype,
if (zdef) |z| z[0] else null,
) catch @panic("Out of memory");

return if (zdef) |z| z[0] else null;
}

pub fn parse(self: *Self, parser: ?*p.Parser, source: t.Token, parsing_type_expr: bool) !?*Zdef {
pub fn parse(self: *Self, parser: ?*p.Parser, source: t.Token, parsing_type_expr: bool) !?[]*Zdef {
// TODO: maybe an Arena allocator for those kinds of things that can live for the whole process lifetime
const duped = self.gc.allocator.dupeZ(u8, source.literal_string.?) catch @panic("Out of memory");
// defer self.gc.allocator.free(duped);
Expand All @@ -239,8 +245,12 @@ pub fn parse(self: *Self, parser: ?*p.Parser, source: t.Token, parsing_type_expr
duped,
.zig,
) catch @panic("Could not parse zdef"),
.structs = std.StringHashMap(*Zdef).init(self.gc.allocator),
};
defer self.state = null;
defer {
self.state.?.structs.deinit();
self.state = null;
}

for (self.state.?.ast.errors) |err| {
if (!err.is_note) {
Expand All @@ -254,13 +264,7 @@ pub fn parse(self: *Self, parser: ?*p.Parser, source: t.Token, parsing_type_expr

const root_decls = self.state.?.ast.rootDecls();

if (root_decls.len > 1) {
self.reporter.report(
.zdef,
self.state.?.source,
"Only one declaration is allowed in zdef",
);
} else if (root_decls.len == 0) {
if (root_decls.len == 0) {
self.reporter.report(
.zdef,
self.state.?.source,
Expand All @@ -270,7 +274,17 @@ pub fn parse(self: *Self, parser: ?*p.Parser, source: t.Token, parsing_type_expr
return null;
}

return self.getZdef(root_decls[0]);
var zdefs = std.ArrayList(*Zdef).init(self.gc.allocator);

for (root_decls) |decl| {
if (try self.getZdef(decl)) |zdef| {
try zdefs.append(zdef);
}
}

zdefs.shrinkAndFree(zdefs.items.len);

return zdefs.items;
}

fn getZdef(self: *Self, decl_index: Ast.Node.Index) !?*Zdef {
Expand Down Expand Up @@ -304,12 +318,21 @@ fn getZdef(self: *Self, decl_index: Ast.Node.Index) !?*Zdef {
.container_decl_two_trailing,
.container_decl_arg,
.container_decl_arg_trailing,
=> break :var_decl try self.containerDecl(
ast.tokenSlice(
=> {
const name = ast.tokenSlice(
ast.simpleVarDecl(decl_index).ast.mut_token + 1,
),
ast.simpleVarDecl(decl_index).ast.init_node,
),
);
const zdef = try self.containerDecl(
ast.tokenSlice(
ast.simpleVarDecl(decl_index).ast.mut_token + 1,
),
ast.simpleVarDecl(decl_index).ast.init_node,
);

try self.state.?.structs.put(name, zdef);

break :var_decl zdef;
},
else => {},
}

Expand All @@ -330,7 +353,7 @@ fn getZdef(self: *Self, decl_index: Ast.Node.Index) !?*Zdef {

if (zdef) |uzdef| {
var opt_zdef = try self.gc.allocator.create(Zdef);
opt_zdef.* = .{
opt_zdef.* = Zdef{
.zig_type = .{
.Optional = .{
.child = &uzdef.zig_type,
Expand Down Expand Up @@ -479,7 +502,7 @@ fn containerDecl(self: *Self, name: []const u8, decl_index: Ast.Node.Index) anye
.resolved_type = .{ .ForeignStruct = foreign_def },
};

var zdef = try self.gc.allocator.create(Zdef);
const zdef = try self.gc.allocator.create(Zdef);
zdef.* = .{
.type_def = try self.gc.type_registry.getTypeDef(type_def),
.zig_type = zig_type,
Expand Down Expand Up @@ -521,6 +544,13 @@ fn identifier(self: *Self, decl_index: Ast.Node.Index) anyerror!*Zdef {
type_def = global.?.type_def.*;
zig_type = global.?.type_def.resolved_type.?.ForeignStruct.zig_type;
}

if (global == null) {
if (self.state.?.structs.get(id)) |fstruct| {
type_def = fstruct.type_def.*;
zig_type = fstruct.zig_type;
}
}
}

if (type_def == null or zig_type == null) {
Expand All @@ -533,7 +563,7 @@ fn identifier(self: *Self, decl_index: Ast.Node.Index) anyerror!*Zdef {
);
}

var zdef = try self.gc.allocator.create(Zdef);
const zdef = try self.gc.allocator.create(Zdef);
zdef.* = .{
.type_def = try self.gc.type_registry.getTypeDef(type_def orelse .{ .def_type = .Void }),
.zig_type = zig_type orelse ZigType{ .Void = {} },
Expand All @@ -551,14 +581,13 @@ fn ptrType(self: *Self, tag: Ast.Node.Tag, decl_index: Ast.Node.Index) anyerror!
else => unreachable,
};

var zdef = try self.gc.allocator.create(Zdef);

const child_type = (try self.getZdef(ptr_type.ast.child_type)).?;
const sentinel_node = self.state.?.ast.nodes.get(ptr_type.ast.sentinel);

// Is it a null terminated string?
// zig fmt: off
zdef.* = if (ptr_type.const_token != null
var zdef = try self.gc.allocator.create(Zdef);
zdef.* = if (ptr_type.const_token != null
and child_type.zig_type == .Int
and child_type.zig_type.Int.bits == 8
and sentinel_node.tag == .number_literal
Expand Down
32 changes: 16 additions & 16 deletions src/mirjit.zig
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,11 @@ fn reset(self: *Self) void {
self.state = null;
}

pub fn compileZdefStruct(self: *Self, zdef_node: *n.ZdefNode) Error!void {
pub fn compileZdefStruct(self: *Self, zdef_element: *const n.ZdefNode.ZdefElement) Error!void {
var wrapper_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer wrapper_name.deinit();

try wrapper_name.writer().print("zdef_{s}\x00", .{zdef_node.symbol});
try wrapper_name.writer().print("zdef_{s}\x00", .{zdef_element.zdef.name});

const module = m.MIR_new_module(self.ctx, @ptrCast(wrapper_name.items.ptr));
defer m.MIR_finish_module(self.ctx);
Expand All @@ -300,8 +300,8 @@ pub fn compileZdefStruct(self: *Self, zdef_node: *n.ZdefNode) Error!void {
std.debug.print(
"Compiling zdef struct getters/setters for `{s}` of type `{s}`\n",
.{
zdef_node.symbol,
(zdef_node.node.type_def.?.toStringAlloc(self.vm.gc.allocator) catch unreachable).items,
zdef_element.symbol,
(zdef_element.node.type_def.?.toStringAlloc(self.vm.gc.allocator) catch unreachable).items,
},
);
}
Expand All @@ -316,7 +316,7 @@ pub fn compileZdefStruct(self: *Self, zdef_node: *n.ZdefNode) Error!void {
};
defer self.reset();

const foreign_def = zdef_node.node.type_def.?.resolved_type.?.ForeignStruct;
const foreign_def = zdef_element.zdef.type_def.resolved_type.?.ForeignStruct;

var getters = std.ArrayList(m.MIR_item_t).init(self.vm.gc.allocator);
defer getters.deinit();
Expand Down Expand Up @@ -402,7 +402,7 @@ fn buildZdefStructGetter(
struct_name: []const u8,
field_name: []const u8,
buzz_type: *o.ObjTypeDef,
zig_type: *ZigType,
zig_type: *const ZigType,
) Error!m.MIR_item_t {
var getter_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer getter_name.deinit();
Expand Down Expand Up @@ -490,7 +490,7 @@ fn buildZdefStructSetter(
struct_name: []const u8,
field_name: []const u8,
buzz_type: *o.ObjTypeDef,
zig_type: *ZigType,
zig_type: *const ZigType,
) Error!m.MIR_item_t {
var setter_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer setter_name.deinit();
Expand Down Expand Up @@ -682,13 +682,13 @@ fn buildZigValueToBuzzValue(self: *Self, buzz_type: *o.ObjTypeDef, zig_type: Zig
}
}

pub fn compileZdef(self: *Self, zdef: *n.ZdefNode) Error!*o.ObjNative {
pub fn compileZdef(self: *Self, zdef: *const n.ZdefNode.ZdefElement) Error!*o.ObjNative {
var wrapper_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer wrapper_name.deinit();

try wrapper_name.writer().print("zdef_{s}\x00", .{zdef.symbol});
try wrapper_name.writer().print("zdef_{s}\x00", .{zdef.zdef.name});

var dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef.symbol) catch @panic("Out of memory");
var dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef.zdef.name) catch @panic("Out of memory");
defer self.vm.gc.allocator.free(dupped_symbol);

const module = m.MIR_new_module(self.ctx, @ptrCast(wrapper_name.items.ptr));
Expand Down Expand Up @@ -817,18 +817,18 @@ fn zigToMIRRegType(zig_type: ZigType) m.MIR_type_t {
};
}

fn buildZdefWrapper(self: *Self, zdef: *n.ZdefNode) Error!m.MIR_item_t {
fn buildZdefWrapper(self: *Self, zdef_element: *const n.ZdefNode.ZdefElement) Error!m.MIR_item_t {
var wrapper_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer wrapper_name.deinit();

try wrapper_name.writer().print("zdef_{s}\x00", .{zdef.symbol});
try wrapper_name.writer().print("zdef_{s}\x00", .{zdef_element.zdef.name});

var wrapper_protocol_name = std.ArrayList(u8).init(self.vm.gc.allocator);
defer wrapper_protocol_name.deinit();

try wrapper_protocol_name.writer().print("p_zdef_{s}\x00", .{zdef.symbol});
try wrapper_protocol_name.writer().print("p_zdef_{s}\x00", .{zdef_element.zdef.name});

var dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef.symbol) catch @panic("Out of memory");
var dupped_symbol = self.vm.gc.allocator.dupeZ(u8, zdef_element.zdef.name) catch @panic("Out of memory");
defer self.vm.gc.allocator.free(dupped_symbol);

// FIXME: I don't get why we need this: a simple constant becomes rubbish as soon as we enter MIR_new_func_arr if we don't
Expand Down Expand Up @@ -872,8 +872,8 @@ fn buildZdefWrapper(self: *Self, zdef: *n.ZdefNode) Error!m.MIR_item_t {
),
);

const function_def = zdef.node.type_def.?.resolved_type.?.Function;
const zig_function_def = zdef.zdef.zig_type;
const function_def = zdef_element.zdef.type_def.resolved_type.?.Function;
const zig_function_def = zdef_element.zdef.zig_type;

// Get arguments from stack
var full_args = std.ArrayList(m.MIR_op_t).init(self.vm.gc.allocator);
Expand Down
Loading

0 comments on commit 81c9c72

Please sign in to comment.