Backlog/lib/sdl3/parser/mock_codegen.zig

145 lines
4.5 KiB
Zig

const std = @import("std");
const patterns = @import("patterns.zig");
const Allocator = std.mem.Allocator;
pub const MockCodeGen = struct {
decls: []patterns.Declaration,
allocator: Allocator,
output: std.ArrayList(u8),
pub fn generate(allocator: Allocator, decls: []patterns.Declaration) ![]const u8 {
var gen = MockCodeGen{
.decls = decls,
.allocator = allocator,
.output = try std.ArrayList(u8).initCapacity(allocator, 4096),
};
try gen.writeHeader();
try gen.writeOpaqueDeclarations();
try gen.writeFunctionMocks();
return try gen.output.toOwnedSlice(allocator);
}
fn writeHeader(self: *MockCodeGen) !void {
const header =
\\// Auto-generated C mock implementations
\\// DO NOT EDIT - Generated by sdl-parser --mocks
\\
\\#include <stdint.h>
\\#include <stdbool.h>
\\#include <stddef.h>
\\
\\
;
try self.output.appendSlice(self.allocator, header);
}
fn writeOpaqueDeclarations(self: *MockCodeGen) !void {
var has_opaques = false;
for (self.decls) |decl| {
if (decl == .opaque_type) {
if (!has_opaques) {
try self.output.appendSlice(self.allocator, "// Forward declarations for opaque types\n");
has_opaques = true;
}
const opaque_type = decl.opaque_type;
try self.output.writer(self.allocator).print("typedef struct {s} {s};\n", .{ opaque_type.name, opaque_type.name });
}
}
if (has_opaques) {
try self.output.appendSlice(self.allocator, "\n");
}
}
fn writeFunctionMocks(self: *MockCodeGen) !void {
var has_functions = false;
for (self.decls) |decl| {
if (decl == .function_decl) {
if (!has_functions) {
try self.output.appendSlice(self.allocator, "// Function implementations\n\n");
has_functions = true;
}
try self.writeFunctionMock(decl.function_decl);
}
}
}
fn writeFunctionMock(self: *MockCodeGen, func: patterns.FunctionDecl) !void {
const writer = self.output.writer(self.allocator);
// Write return type and function name
try writer.print("{s} {s}(", .{ func.return_type, func.name });
// Write parameters
if (func.params.len == 0) {
try writer.writeAll("void");
} else {
for (func.params, 0..) |param, i| {
if (i > 0) {
try writer.writeAll(", ");
}
try writer.print("{s}", .{param.type_name});
if (param.name.len > 0) {
try writer.print(" {s}", .{param.name});
}
}
}
try writer.writeAll(") {\n");
// Void all parameters to avoid unused warnings
for (func.params) |param| {
if (param.name.len > 0) {
try writer.print(" (void){s};\n", .{param.name});
}
}
// Return appropriate default value
const return_value = getDefaultReturnValue(func.return_type);
if (return_value.len > 0) {
try writer.print(" return {s};\n", .{return_value});
}
try writer.writeAll("}\n\n");
}
fn getDefaultReturnValue(return_type: []const u8) []const u8 {
const trimmed = std.mem.trim(u8, return_type, " \t");
if (std.mem.eql(u8, trimmed, "void")) {
return "";
}
// Check for pointer types
if (std.mem.indexOf(u8, trimmed, "*") != null) {
return "NULL";
}
// Check for bool
if (std.mem.eql(u8, trimmed, "bool") or std.mem.eql(u8, trimmed, "SDL_bool")) {
return "false";
}
// Check for integer types
if (std.mem.indexOf(u8, trimmed, "int") != null or
std.mem.startsWith(u8, trimmed, "Uint") or
std.mem.startsWith(u8, trimmed, "Sint") or
std.mem.eql(u8, trimmed, "size_t"))
{
return "0";
}
// Check for float types
if (std.mem.eql(u8, trimmed, "float") or std.mem.eql(u8, trimmed, "double")) {
return "0.0";
}
// For enum/struct types, return zero
return "0";
}
};