# Implementation Quick Start ## Day 1 Morning: Setup ### 1. Create Directory Structure (5 minutes) ```bash cd /home/sear/Backlog/lib/zargs mkdir -p src tests examples ``` ### 2. Create Initial Files (5 minutes) ```bash touch src/main.zig touch src/ArgumentType.zig touch src/errors.zig touch tests/type_test.zig touch build.zig ``` ### 3. Setup build.zig (15 minutes) ```zig const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // Library module const zargs = b.addModule("zargs", .{ .root_source_file = b.path("src/main.zig"), }); // Tests const tests = b.addTest(.{ .root_source_file = b.path("tests/type_test.zig"), .target = target, .optimize = optimize, }); tests.root_module.addImport("zargs", zargs); const run_tests = b.addRunArtifact(tests); const test_step = b.step("test", "Run tests"); test_step.dependOn(&run_tests.step); } ``` ### 4. Verify Setup (2 minutes) ```bash zig build test # Should compile (no tests yet) ``` --- ## Day 1 Afternoon: ArgumentType (Phase 1.1) ### Step 1: Write Test First (30 minutes) **File:** `tests/type_test.zig` ```zig const std = @import("std"); const testing = std.testing; const ArgumentType = @import("ArgumentType.zig").ArgumentType; test "ArgumentType.fromZigType - bool" { const t = ArgumentType.fromZigType(bool); try testing.expectEqual(.bool, t); } test "ArgumentType.fromZigType - u32" { const t = ArgumentType.fromZigType(u32); try testing.expectEqual(.u32, t); } test "ArgumentType.fromZigType - string" { const t = ArgumentType.fromZigType([]const u8); try testing.expectEqual(.string, t); } test "ArgumentType.fromZigType - optional unwraps" { const t = ArgumentType.fromZigType(?u32); try testing.expectEqual(.u32, t); } test "ArgumentType.matches - same types match" { const t1 = ArgumentType.u32; const t2 = ArgumentType.u32; try testing.expect(t1.matches(t2)); } test "ArgumentType.matches - different types don't match" { const t1 = ArgumentType.u32; const t2 = ArgumentType.bool; try testing.expect(!t1.matches(t2)); } ``` ### Step 2: Implement ArgumentType (1.5 hours) **File:** `src/ArgumentType.zig` ```zig const std = @import("std"); pub const ArgumentType = enum { bool, u8, u16, u32, u64, i8, i16, i32, i64, string, string_list, enum_type, /// Convert a Zig type to ArgumentType at compile time pub fn fromZigType(comptime T: type) ArgumentType { const info = @typeInfo(T); return switch (info) { .Bool => .bool, .Int => |int| { if (int.signedness == .unsigned) { return switch (int.bits) { 8 => .u8, 16 => .u16, 32 => .u32, 64 => .u64, else => @compileError("Unsupported unsigned int size: " ++ @typeName(T)), }; } else { return switch (int.bits) { 8 => .i8, 16 => .i16, 32 => .i32, 64 => .i64, else => @compileError("Unsupported signed int size: " ++ @typeName(T)), }; } }, .Pointer => |ptr| { if (ptr.size == .Slice) { if (ptr.child == u8) return .string; // Check for []const []const u8 (string list) const child_info = @typeInfo(ptr.child); if (child_info == .Pointer) { const inner_ptr = child_info.Pointer; if (inner_ptr.size == .Slice and inner_ptr.child == u8) { return .string_list; } } } @compileError("Unsupported pointer type: " ++ @typeName(T)); }, .Enum => .enum_type, .Optional => |opt| fromZigType(opt.child), else => @compileError("Unsupported argument type: " ++ @typeName(T)), }; } /// Check if two ArgumentTypes are compatible pub fn matches(self: ArgumentType, other: ArgumentType) bool { return self == other; } }; // Compile-time tests comptime { _ = ArgumentType.fromZigType(bool); _ = ArgumentType.fromZigType(u32); _ = ArgumentType.fromZigType([]const u8); _ = ArgumentType.fromZigType(?u32); } ``` ### Step 3: Run Tests (5 minutes) ```bash zig build test # Should pass all tests ``` ### Step 4: Update build.zig for ArgumentType (5 minutes) Add ArgumentType to the tests: ```zig tests.root_module.addAnonymousImport("ArgumentType", .{ .root_source_file = b.path("src/ArgumentType.zig"), }); ``` --- ## Day 1 Success Criteria ✓ At end of Day 1, you should have: - [ ] Project structure created - [ ] build.zig working - [ ] ArgumentType fully implemented - [ ] All type detection tests passing - [ ] Comptime tests verifying common types **Progress:** ~10% complete, on track! --- ## Day 2 Morning: ParsedValue (Phase 1.2) ### Step 1: Write Tests Add to `tests/type_test.zig`: ```zig const ParsedValue = @import("ArgumentType.zig").ParsedValue; test "ParsedValue.fromString - bool true" { const allocator = testing.allocator; const pv = try ParsedValue.fromString(.bool, "true", allocator); defer pv.deinit(allocator); try testing.expectEqual(true, pv.bool_val); } test "ParsedValue.fromString - u32" { const allocator = testing.allocator; const pv = try ParsedValue.fromString(.u32, "42", allocator); defer pv.deinit(allocator); try testing.expectEqual(@as(u32, 42), pv.u32_val); } test "ParsedValue.toTypedValue - u32" { const allocator = testing.allocator; const pv = try ParsedValue.fromString(.u32, "42", allocator); defer pv.deinit(allocator); const val = pv.toTypedValue(u32); try testing.expectEqual(@as(u32, 42), val); } ``` ### Step 2: Implement ParsedValue Add to `src/ArgumentType.zig`: ```zig pub const ParsedValue = union(ArgumentType) { bool: bool, u8: u8, u16: u16, u32: u32, u64: u64, i8: i8, i16: i16, i32: i32, i64: i64, string: []const u8, string_list: []const []const u8, enum_type: []const u8, pub fn fromString( arg_type: ArgumentType, s: []const u8, allocator: std.mem.Allocator, ) !ParsedValue { return switch (arg_type) { .bool => .{ .bool = try parseBool(s) }, .u8 => .{ .u8 = try std.fmt.parseInt(u8, s, 10) }, .u16 => .{ .u16 = try std.fmt.parseInt(u16, s, 10) }, .u32 => .{ .u32 = try std.fmt.parseInt(u32, s, 10) }, .u64 => .{ .u64 = try std.fmt.parseInt(u64, s, 10) }, .i8 => .{ .i8 = try std.fmt.parseInt(i8, s, 10) }, .i16 => .{ .i16 = try std.fmt.parseInt(i16, s, 10) }, .i32 => .{ .i32 = try std.fmt.parseInt(i32, s, 10) }, .i64 => .{ .i64 = try std.fmt.parseInt(i64, s, 10) }, .string => .{ .string = try allocator.dupe(u8, s) }, .string_list => .{ .string_list = try parseList(s, allocator) }, .enum_type => .{ .enum_type = try allocator.dupe(u8, s) }, }; } pub fn toTypedValue(self: ParsedValue, comptime T: type) T { const arg_type = ArgumentType.fromZigType(T); return switch (arg_type) { .bool => self.bool, .u8 => self.u8, .u16 => self.u16, .u32 => self.u32, .u64 => self.u64, .i8 => self.i8, .i16 => self.i16, .i32 => self.i32, .i64 => self.i64, .string => self.string, .string_list => self.string_list, .enum_type => { // For enums, need to convert string to enum at runtime // This is a placeholder - full implementation in Phase 4 @compileError("Enum conversion not yet implemented"); }, }; } pub fn deinit(self: ParsedValue, allocator: std.mem.Allocator) void { switch (self) { .string => |s| allocator.free(s), .string_list => |list| { for (list) |item| allocator.free(item); allocator.free(list); }, .enum_type => |s| allocator.free(s), else => {}, } } }; fn parseBool(s: []const u8) !bool { if (std.mem.eql(u8, s, "true") or std.mem.eql(u8, s, "1") or std.mem.eql(u8, s, "yes")) { return true; } else if (std.mem.eql(u8, s, "false") or std.mem.eql(u8, s, "0") or std.mem.eql(u8, s, "no")) { return false; } return error.InvalidBooleanValue; } fn parseList(s: []const u8, allocator: std.mem.Allocator) ![]const []const u8 { var list = std.ArrayList([]const u8).init(allocator); errdefer { for (list.items) |item| allocator.free(item); list.deinit(); } var iter = std.mem.splitScalar(u8, s, ','); while (iter.next()) |item| { const trimmed = std.mem.trim(u8, item, " \t"); try list.append(try allocator.dupe(u8, trimmed)); } return try list.toOwnedSlice(); } ``` ### Step 3: Run Tests ```bash zig build test ``` --- ## Momentum Tips ### Keep Moving Forward: 1. **If stuck > 30 minutes:** Skip to next task, come back later 2. **If test fails:** Debug immediately, don't move on 3. **If design unclear:** Implement simplest version, refactor later 4. **Commit often:** After each green test ### Daily Review (15 minutes EOD): - What did I accomplish? - What's blocking me? - What's tomorrow's priority? ### Weekly Review (30 minutes Friday): - Am I on schedule? - Do I need to adjust the plan? - What did I learn? --- ## Common Issues and Solutions ### Issue: Comptime too complex **Solution:** Move to runtime, optimize later ### Issue: Memory leaks in tests **Solution:** Add `defer` immediately after allocation ### Issue: Type conversion not working **Solution:** Check ArgumentType.fromZigType() logic ### Issue: Tests not compiling **Solution:** Check imports and build.zig configuration --- ## Morale Boosters - ✅ Each passing test is progress! - ✅ Small commits compound into big features - ✅ Taking breaks prevents burnout - ✅ Asking for help is strength, not weakness - ✅ Perfect is the enemy of done - ship it! **You've got this!** 💪 --- ## Contact/Support - Review design docs in `research/` when unsure - Check `todo/implementation_plan_v2.md` for detailed steps - Run `zig build test` frequently - Trust the process - you planned well! **START WITH DAY 1 MORNING. BUILD INCREMENTALLY. TEST EVERYTHING.** 🚀