add comptime for uses of ++ (#53)

* add comptime for uses of ++

* ptrCast instead of bitCast

* don't build i386 windows for now
wch-ch32v003
Matt Knight 2 years ago committed by Matt Knight
parent 43a88c16b3
commit dea71d5272

@ -16,7 +16,8 @@ steps:
- "aarch64-macos" - "aarch64-macos"
- "i386-linux-gnu" - "i386-linux-gnu"
- "i386-linux-musl" - "i386-linux-musl"
- "i386-windows" # TODO: when _tls_index is fixed
#- "i386-windows"
- "x86_64-linux-gnu" - "x86_64-linux-gnu"
- "x86_64-linux-musl" - "x86_64-linux-musl"
- "x86_64-macos" - "x86_64-macos"

@ -7,18 +7,24 @@ pub fn build(b: *Builder) void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const test_all_step = b.step("test", "Run all tests in all modes."); const test_all_step = b.step("test", "Run all tests in all modes.");
inline for (@typeInfo(std.builtin.Mode).Enum.fields) |field| { for ([_]bool{ true, false }) |stage1| {
const test_mode = @field(std.builtin.Mode, field.name); for (std.meta.tags(std.builtin.Mode)) |test_mode| {
const mode_str = @tagName(test_mode); const mode_str = @tagName(test_mode);
const stage1_str = if (stage1) "stage1" else "stage2";
const tests = b.addTest("clap.zig"); const tests = b.addTest("clap.zig");
tests.setBuildMode(test_mode); tests.setBuildMode(test_mode);
tests.setTarget(target); tests.setTarget(target);
tests.use_stage1 = stage1;
const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ "."); const test_step = b.step(
b.fmt("test-{s}-{s}", .{ stage1_str, mode_str }),
b.fmt("Run all tests with {s} compiler in {s}.", .{ stage1_str, mode_str }),
);
test_step.dependOn(&tests.step); test_step.dependOn(&tests.step);
test_all_step.dependOn(test_step); test_all_step.dependOn(test_step);
} }
}
const example_step = b.step("examples", "Build examples"); const example_step = b.step("examples", "Build examples");
inline for (.{ inline for (.{

@ -6,6 +6,7 @@ const heap = std.heap;
const io = std.io; const io = std.io;
const math = std.math; const math = std.math;
const mem = std.mem; const mem = std.mem;
const meta = std.meta;
const process = std.process; const process = std.process;
const testing = std.testing; const testing = std.testing;
@ -25,6 +26,7 @@ pub const Names = struct {
/// '--' prefix /// '--' prefix
long: ?[]const u8 = null, long: ?[]const u8 = null,
/// The longest of the possible names this `Names` struct can represent.
pub fn longest(names: *const Names) Longest { pub fn longest(names: *const Names) Longest {
if (names.long) |long| if (names.long) |long|
return .{ .kind = .long, .name = long }; return .{ .kind = .long, .name = long };
@ -73,7 +75,7 @@ pub const Values = enum {
/// * Positional parameters must take a value. /// * Positional parameters must take a value.
pub fn Param(comptime Id: type) type { pub fn Param(comptime Id: type) type {
return struct { return struct {
id: Id = Id{}, id: Id,
names: Names = Names{}, names: Names = Names{},
takes_value: Values = .none, takes_value: Values = .none,
}; };
@ -199,7 +201,7 @@ pub fn parseParamEx(str: []const u8, end: *usize) !Param(Help) {
// * Someone points out how this is a really bad idea. // * Someone points out how this is a really bad idea.
@setEvalBranchQuota(std.math.maxInt(u32)); @setEvalBranchQuota(std.math.maxInt(u32));
var res = Param(Help){}; var res = Param(Help){ .id = .{} };
var start: usize = 0; var start: usize = 0;
var state: enum { var state: enum {
start, start,
@ -449,11 +451,11 @@ test "parseParams" {
\\--bb This should be a new param \\--bb This should be a new param
\\ \\
, &.{ , &.{
.{ .names = .{ .short = 's' } }, .{ .id = .{}, .names = .{ .short = 's' } },
.{ .names = .{ .long = "str" } }, .{ .id = .{}, .names = .{ .long = "str" } },
.{ .names = .{ .long = "str-str" } }, .{ .id = .{}, .names = .{ .long = "str-str" } },
.{ .names = .{ .long = "str_str" } }, .{ .id = .{}, .names = .{ .long = "str_str" } },
.{ .names = .{ .short = 's', .long = "str" } }, .{ .id = .{}, .names = .{ .short = 's', .long = "str" } },
.{ .{
.id = .{ .val = "str" }, .id = .{ .val = "str" },
.names = .{ .long = "str" }, .names = .{ .long = "str" },
@ -671,6 +673,7 @@ pub fn parse(
}; };
} }
/// The result of `parse`. Is owned by the caller and should be freed with `deinit`.
pub fn Result( pub fn Result(
comptime Id: type, comptime Id: type,
comptime params: []const Param(Id), comptime params: []const Param(Id),
@ -721,14 +724,13 @@ pub fn parseEx(
opt: ParseOptions, opt: ParseOptions,
) !ResultEx(Id, params, value_parsers) { ) !ResultEx(Id, params, value_parsers) {
const allocator = opt.allocator; const allocator = opt.allocator;
var positionals = std.ArrayList( const Positional = FindPositionalType(Id, params, value_parsers);
FindPositionalType(Id, params, value_parsers),
).init(allocator);
var positionals = std.ArrayList(Positional).init(allocator);
var arguments = Arguments(Id, params, value_parsers, .list){}; var arguments = Arguments(Id, params, value_parsers, .list){};
errdefer deinitArgs(Id, params, value_parsers, .list, allocator, &arguments); errdefer deinitArgs(Id, params, allocator, &arguments);
var stream = streaming.Clap(Id, @typeInfo(@TypeOf(iter)).Pointer.child){ var stream = streaming.Clap(Id, meta.Child(@TypeOf(iter))){
.params = params, .params = params,
.iter = iter, .iter = iter,
.diagnostic = opt.diagnostic, .diagnostic = opt.diagnostic,
@ -756,8 +758,10 @@ pub fn parseEx(
try res; try res;
} }
// We are done parsing, but our arguments are stored in lists, and not slices. Map the list
// fields to slices and return that.
var result_args = Arguments(Id, params, value_parsers, .slice){}; var result_args = Arguments(Id, params, value_parsers, .slice){};
inline for (@typeInfo(@TypeOf(arguments)).Struct.fields) |field| { inline for (meta.fields(@TypeOf(arguments))) |field| {
if (@typeInfo(field.field_type) == .Struct and if (@typeInfo(field.field_type) == .Struct and
@hasDecl(field.field_type, "toOwnedSlice")) @hasDecl(field.field_type, "toOwnedSlice"))
{ {
@ -803,6 +807,7 @@ fn parseArg(
} }
} }
/// The result of `parseEx`. Is owned by the caller and should be freed with `deinit`.
pub fn ResultEx( pub fn ResultEx(
comptime Id: type, comptime Id: type,
comptime params: []const Param(Id), comptime params: []const Param(Id),
@ -814,7 +819,7 @@ pub fn ResultEx(
allocator: mem.Allocator, allocator: mem.Allocator,
pub fn deinit(result: *@This()) void { pub fn deinit(result: *@This()) void {
deinitArgs(Id, params, value_parsers, .slice, result.allocator, &result.args); deinitArgs(Id, params, result.allocator, &result.args);
result.allocator.free(result.positionals); result.allocator.free(result.positionals);
} }
}; };
@ -825,15 +830,22 @@ fn FindPositionalType(
comptime params: []const Param(Id), comptime params: []const Param(Id),
comptime value_parsers: anytype, comptime value_parsers: anytype,
) type { ) type {
const pos = findPositional(Id, params) orelse return []const u8;
return ParamType(Id, pos, value_parsers);
}
fn findPositional(comptime Id: type, params: []const Param(Id)) ?Param(Id) {
for (params) |param| { for (params) |param| {
const longest = param.names.longest(); const longest = param.names.longest();
if (longest.kind == .positinal) if (longest.kind == .positinal)
return ParamType(Id, param, value_parsers); return param;
} }
return []const u8; return null;
} }
/// Given a parameter figure out which type that parameter is parsed into when using the correct
/// parser from `value_parsers`.
fn ParamType( fn ParamType(
comptime Id: type, comptime Id: type,
comptime param: Param(Id), comptime param: Param(Id),
@ -846,13 +858,13 @@ fn ParamType(
return parsers.Result(@TypeOf(parser)); return parsers.Result(@TypeOf(parser));
} }
/// Deinitializes a struct of type `Argument`. Since the `Argument` type is generated, and we
/// cannot add the deinit declaration to it, we declare it here instead.
fn deinitArgs( fn deinitArgs(
comptime Id: type, comptime Id: type,
comptime params: []const Param(Id), comptime params: []const Param(Id),
comptime value_parsers: anytype,
comptime multi_arg_kind: MultiArgKind,
allocator: mem.Allocator, allocator: mem.Allocator,
arguments: *Arguments(Id, params, value_parsers, multi_arg_kind), arguments: anytype,
) void { ) void {
inline for (params) |param| { inline for (params) |param| {
const longest = comptime param.names.longest(); const longest = comptime param.names.longest();
@ -861,15 +873,22 @@ fn deinitArgs(
if (param.takes_value != .many) if (param.takes_value != .many)
continue; continue;
switch (multi_arg_kind) { const field = @field(arguments, longest.name);
.slice => allocator.free(@field(arguments, longest.name)),
.list => @field(arguments, longest.name).deinit(allocator), // If the multi value field is a struct, we know it is a list and should be deinited.
// Otherwise, it is a slice that should be freed.
switch (@typeInfo(@TypeOf(field))) {
.Struct => @field(arguments, longest.name).deinit(allocator),
else => allocator.free(@field(arguments, longest.name)),
} }
} }
} }
const MultiArgKind = enum { slice, list }; const MultiArgKind = enum { slice, list };
/// Turn a list of parameters into a struct with one field for each none positional parameter.
/// The type of each parameter field is determined by `ParamType`. Positional arguments will not
/// havea field in this struct.
fn Arguments( fn Arguments(
comptime Id: type, comptime Id: type,
comptime params: []const Param(Id), comptime params: []const Param(Id),
@ -885,27 +904,21 @@ fn Arguments(
continue; continue;
const T = ParamType(Id, param, value_parsers); const T = ParamType(Id, param, value_parsers);
const FieldType = switch (param.takes_value) { const default_value = switch (param.takes_value) {
.none => bool, .none => false,
.one => ?T, .one => @as(?T, null),
.many => switch (multi_arg_kind) { .many => switch (multi_arg_kind) {
.slice => []const T, .slice => @as([]const T, &[_]T{}),
.list => std.ArrayListUnmanaged(T), .list => std.ArrayListUnmanaged(T){},
}, },
}; };
fields[i] = .{ fields[i] = .{
.name = longest.name, .name = longest.name,
.field_type = FieldType, .field_type = @TypeOf(default_value),
.default_value = switch (param.takes_value) { .default_value = @ptrCast(*const anyopaque, &default_value),
.none => &false,
.one => &@as(?T, null),
.many => switch (multi_arg_kind) {
.slice => &@as([]const T, &[_]T{}),
.list => &std.ArrayListUnmanaged(T){},
},
},
.is_comptime = false, .is_comptime = false,
.alignment = @alignOf(FieldType), .alignment = @alignOf(@TypeOf(default_value)),
}; };
i += 1; i += 1;
} }

@ -103,10 +103,10 @@ pub fn create(
try flags.appendSlice(&.{ try flags.appendSlice(&.{
// Version info, hardcoded // Version info, hardcoded
"-DLIBXML_VERSION=" ++ Version.number(), comptime "-DLIBXML_VERSION=" ++ Version.number(),
"-DLIBXML_VERSION_STRING=" ++ Version.string(), comptime "-DLIBXML_VERSION_STRING=" ++ Version.string(),
"-DLIBXML_VERSION_EXTRA=\"\"", "-DLIBXML_VERSION_EXTRA=\"\"",
"-DLIBXML_DOTTED_VERSION=" ++ Version.dottedString(), comptime "-DLIBXML_DOTTED_VERSION=" ++ Version.dottedString(),
// These might now always be true (particularly Windows) but for // These might now always be true (particularly Windows) but for
// now we just set them all. We should do some detection later. // now we just set them all. We should do some detection later.
@ -174,7 +174,7 @@ pub fn create(
// C files // C files
ret.addCSourceFiles(srcs, flags.items); ret.addCSourceFiles(srcs, flags.items);
if (opts.sax1) { if (opts.sax1) {
ret.addCSourceFile(root() ++ "libxml2/DOCBparser.c", flags.items); ret.addCSourceFile(comptime root() ++ "libxml2/DOCBparser.c", flags.items);
} }
ret.addIncludeDir(include_dir); ret.addIncludeDir(include_dir);
@ -191,7 +191,7 @@ pub fn create(
} }
fn root() []const u8 { fn root() []const u8 {
return (std.fs.path.dirname(@src().file) orelse unreachable) ++ "/"; return comptime (std.fs.path.dirname(@src().file) orelse unreachable) ++ "/";
} }
/// Directories with our includes. /// Directories with our includes.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save