summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/core.zig340
-rw-r--r--examples/extended.zig2
-rw-r--r--src/core.zig44
3 files changed, 365 insertions, 21 deletions
diff --git a/examples/core.zig b/examples/core.zig
index e69de29..f393e0f 100644
--- a/examples/core.zig
+++ b/examples/core.zig
@@ -0,0 +1,340 @@
1const std = @import("std");
2const clap = @import("clap").core;
3
4const debug = std.debug;
5const mem = std.mem;
6
7const Names = clap.Names;
8const Param = clap.Param;
9
10const Command = enum {
11 Help,
12 Build,
13 BuildExe,
14 BuildLib,
15 BuildObj,
16 Fmt,
17 Run,
18 Targets,
19 Test,
20 Version,
21 Zen,
22};
23
24const params = []Param(Command){
25 Param(Command).init(Command.Help, false, Names.prefix("help")),
26 Param(Command).init(Command.Build, false, Names.bare("build")),
27 Param(Command).init(Command.BuildExe, false, Names.bare("build-exe")),
28 Param(Command).init(Command.BuildLib, false, Names.bare("build-lib")),
29 Param(Command).init(Command.BuildObj, false, Names.bare("build-obj")),
30 Param(Command).init(Command.Fmt, false, Names.bare("fmt")),
31 Param(Command).init(Command.Run, false, Names.bare("run")),
32 Param(Command).init(Command.Targets, false, Names.bare("targets")),
33 Param(Command).init(Command.Test, false, Names.bare("test")),
34 Param(Command).init(Command.Version, false, Names.bare("version")),
35 Param(Command).init(Command.Zen, false, Names.bare("zen")),
36};
37
38const usage =
39 \\usage: zig [command] [options]
40 \\
41 \\Commands:
42 \\
43 \\ build Build project from build.zig
44 \\ build-exe [source] Create executable from source or object files
45 \\ build-lib [source] Create library from source or object files
46 \\ build-obj [source] Create object from source or assembly
47 \\ fmt [source] Parse file and render in canonical zig format
48 \\ run [source] Create executable and run immediately
49 \\ targets List available compilation targets
50 \\ test [source] Create and run a test build
51 \\ translate-c [source] Convert c code to zig code
52 \\ version Print version number and exit
53 \\ zen Print zen of zig and exit
54 \\
55 \\
56;
57
58pub fn main() !void {
59 var direct_allocator = std.heap.DirectAllocator.init();
60 defer direct_allocator.deinit();
61 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
62 defer arena.deinit();
63
64 const allocator = &arena.allocator;
65
66 var args = clap.OsArgIterator.init();
67 var parser = clap.Clap(Command).init(params, &args.iter, allocator);
68 defer parser.deinit();
69
70 const exe = try parser.nextNoParse();
71 const maybe_arg = parser.next() catch |err| b: {
72 debug.warn("{}.\n", @errorName(err));
73 // debug.warn(usage); TODO: error: evaluation exceeded 1000 backwards branches
74 return err;
75 };
76 const arg = maybe_arg ?? {
77 debug.warn("No command found.\n");
78 // debug.warn(usage); TODO: error: evaluation exceeded 1000 backwards branches
79 return error.NoCommandFound;
80 };
81
82 switch (arg.id) {
83 Command.Help => return, // debug.warn(usage), TODO: error: evaluation exceeded 1000 backwards branches
84 Command.Build => try cmdBuild(allocator, parser.iter),
85 Command.BuildExe,
86 Command.BuildLib,
87 Command.BuildObj,
88 Command.Fmt,
89 Command.Run,
90 Command.Targets,
91 Command.Test,
92 Command.Version,
93 Command.Zen => unreachable,
94 }
95}
96
97// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
98
99const BuildArg = enum {
100 Help,
101 Init,
102 BuildFile,
103 CacheDir,
104 Verbose,
105 Prefix,
106 VerboseTokenize,
107 VerboseAst,
108 VerboseLink,
109 VerboseIr,
110 VerboseLlvmIr,
111 VerboseCImport,
112};
113
114const build_params = []Param(BuildArg){
115 Param(BuildArg).init(BuildArg.Help, false, Names.prefix("help")),
116 Param(BuildArg).init(BuildArg.Init, false, Names.long("init")),
117 Param(BuildArg).init(BuildArg.BuildFile, true, Names.long("build-file")),
118 Param(BuildArg).init(BuildArg.CacheDir, true, Names.long("cache-dir")),
119 Param(BuildArg).init(BuildArg.Verbose, false, Names.prefix("verbose")),
120 Param(BuildArg).init(BuildArg.Prefix, true, Names.long("prefix")),
121
122 Param(BuildArg).init(BuildArg.VerboseTokenize, false, Names.prefix("verbose-tokenize")),
123 Param(BuildArg).init(BuildArg.VerboseAst, false, Names.prefix("verbose-ast")),
124 Param(BuildArg).init(BuildArg.VerboseLink, false, Names.prefix("verbose-link")),
125 Param(BuildArg).init(BuildArg.VerboseIr, false, Names.prefix("verbose-ir")),
126 Param(BuildArg).init(BuildArg.VerboseLlvmIr, false, Names.prefix("verbose-llvm-ir")),
127 Param(BuildArg).init(BuildArg.VerboseCImport, false, Names.prefix("verbose-cimport")),
128};
129
130const build_usage =
131 \\usage: zig build <options>
132 \\
133 \\General Options:
134 \\ -h, --help Print this help and exit
135 \\ --init Generate a build.zig template
136 \\ --build-file [file] Override path to build.zig
137 \\ --cache-dir [path] Override path to cache directory
138 \\ -v, --verbose Print commands before executing them
139 \\ --prefix [path] Override default install prefix
140 \\
141 \\Project-Specific Options:
142 \\
143 \\ Project-specific options become available when the build file is found.
144 \\
145 \\Advanced Options:
146 \\ --verbose-tokenize Enable compiler debug output for tokenization
147 \\ --verbose-ast Enable compiler debug output for parsing into an AST
148 \\ --verbose-link Enable compiler debug output for linking
149 \\ --verbose-ir Enable compiler debug output for Zig IR
150 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
151 \\ --verbose-cimport Enable compiler debug output for C imports
152 \\
153 \\
154;
155
156const missing_build_file =
157 \\No 'build.zig' file found.
158 \\
159 \\Initialize a 'build.zig' template file with `zig build --init`,
160 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
161 \\
162 \\See: `zig build --help` or `zig help` for more options.
163 \\
164;
165
166fn cmdBuild(allocator: &mem.Allocator, args: &clap.ArgIterator) !void {
167 var init = false;
168 var build_file: []const u8 = "build.zig";
169 var cache_dir: []const u8 = "zig-cache";
170 var verbose = false;
171 var prefix: []const u8 = "";
172 var verbose_tokenize = false;
173 var verbose_ast = false;
174 var verbose_link = false;
175 var verbose_ir = false;
176 var verbose_llvm_ir = false;
177 var verbose_cimport = false;
178
179 var parser = clap.Clap(BuildArg).init(build_params, args, allocator);
180 defer parser.deinit();
181
182 while (parser.next() catch |err| {
183 debug.warn("{}.\n", @errorName(err));
184 // debug.warn(build_usage); TODO: error: evaluation exceeded 1000 backwards branches
185 return err;
186 }) |arg| switch (arg.id) {
187 BuildArg.Help => return, // debug.warn(build_usage) TODO: error: evaluation exceeded 1000 backwards branches,
188 BuildArg.Init => init = true,
189 BuildArg.BuildFile => build_file = ??arg.value,
190 BuildArg.CacheDir => cache_dir = ??arg.value,
191 BuildArg.Verbose => verbose = true,
192 BuildArg.Prefix => prefix = ??arg.value,
193 BuildArg.VerboseTokenize => verbose_tokenize = true,
194 BuildArg.VerboseAst => verbose_ast = true,
195 BuildArg.VerboseLink => verbose_link = true,
196 BuildArg.VerboseIr => verbose_ir = true,
197 BuildArg.VerboseLlvmIr => verbose_llvm_ir = true,
198 BuildArg.VerboseCImport => verbose_cimport = true,
199 };
200
201 debug.warn("command: build\n");
202 debug.warn("init = {}\n", init);
203 debug.warn("build_file = {}\n", build_file);
204 debug.warn("cache_dir = {}\n", cache_dir);
205 debug.warn("verbose = {}\n", verbose);
206 debug.warn("prefix = {}\n", prefix);
207 debug.warn("verbose_tokenize = {}\n", verbose_tokenize);
208 debug.warn("verbose_ast = {}\n", verbose_ast);
209 debug.warn("verbose_link = {}\n", verbose_link);
210 debug.warn("verbose_ir = {}\n", verbose_ir);
211 debug.warn("verbose_llvm_ir = {}\n", verbose_llvm_ir);
212 debug.warn("verbose_cimport = {}\n", verbose_cimport);
213}
214
215// cmd:build-exe ///////////////////////////////////////////////////////////////////////////////////
216
217const BuildGeneric = enum {
218 File,
219 Help,
220 Color,
221
222 Assembly,
223 CacheDir,
224 Emit,
225 EnableTimingInfo,
226 LibCDir,
227 Name,
228 Output,
229 OutputH,
230 PkgBegin,
231 PkgEnd,
232 ReleaseFast,
233 ReleaseSafe,
234 Static,
235 Strip,
236 TargetArch,
237 TargetEnviron,
238 TargetOs,
239 VerboseTokenize,
240 VerboseAst,
241 VerboseLink,
242 VerboseIr,
243 VerboseLlvmIr,
244 VerboseCImport,
245 DirAfter,
246 ISystem,
247 MLlvm,
248
249 ArPath,
250 DynamicLinker,
251 EachLibRPath,
252 LibcLibDir,
253 LibcStaticLibDir,
254 MsvcLibDir,
255 Kernel32LibDir,
256 Library,
257 ForbidLibrary,
258 LibraryPath,
259 LinkerScript,
260 Object,
261 RDynamic,
262 RPath,
263 MConsole,
264 MWindows,
265 Framework,
266 MiOsVersionMin,
267 MMacOsXVersonMin,
268 VerMajor,
269 VerMinor,
270 VerPatch,
271};
272
273const build_generic_params = []Param(BuildArg){
274 Param(BuildArg).init(BuildArg.Help, false, Names.prefix("help")),
275};
276
277const build_generic_usage =
278 \\usage: zig build-exe <options> [file]
279 \\ zig build-lib <options> [file]
280 \\ zig build-obj <options> [file]
281 \\
282 \\General Options:
283 \\ -h, --help Print this help and exit
284 \\ -c, --color [auto|off|on] Enable or disable colored error messages
285 \\
286 \\Compile Options:
287 \\ --assembly [source] Add assembly file to build
288 \\ --cache-dir [path] Override the cache directory
289 \\ --emit [filetype] Emit a specific file format as compilation output
290 \\ --enable-timing-info Print timing diagnostics
291 \\ --libc-include-dir [path] Directory where libc stdlib.h resides
292 \\ --name [name] Override output name
293 \\ --output [file] Override destination path
294 \\ --output-h [file] Override generated header file path
295 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
296 \\ --pkg-end Pop current pkg
297 \\ --release-fast Build with optimizations on and safety off
298 \\ --release-safe Build with optimizations on and safety on
299 \\ --static Output will be statically linked
300 \\ --strip Exclude debug symbols
301 \\ --target-arch [name] Specify target architecture
302 \\ --target-environ [name] Specify target environment
303 \\ --target-os [name] Specify target operating system
304 \\ --verbose-tokenize Turn on compiler debug output for tokenization
305 \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view)
306 \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source)
307 \\ --verbose-link Turn on compiler debug output for linking
308 \\ --verbose-ir Turn on compiler debug output for Zig IR
309 \\ --verbose-llvm-ir Turn on compiler debug output for LLVM IR
310 \\ --verbose-cimport Turn on compiler debug output for C imports
311 \\ --dirafter [dir] Same as --isystem but do it last
312 \\ --isystem [dir] Add additional search path for other .h files
313 \\ --mllvm [arg] Additional arguments to forward to LLVM's option processing
314 \\
315 \\Link Options:
316 \\ --ar-path [path] Set the path to ar
317 \\ --dynamic-linker [path] Set the path to ld.so
318 \\ --each-lib-rpath Add rpath for each used dynamic library
319 \\ --libc-lib-dir [path] Directory where libc crt1.o resides
320 \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides
321 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
322 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
323 \\ --library [lib] Link against lib
324 \\ --forbid-library [lib] Make it an error to link against lib
325 \\ --library-path [dir] Add a directory to the library search path
326 \\ --linker-script [path] Use a custom linker script
327 \\ --object [obj] Add object file to build
328 \\ --rdynamic Add all symbols to the dynamic symbol table
329 \\ --rpath [path] Add directory to the runtime library search path
330 \\ --mconsole (windows) --subsystem console to the linker
331 \\ --mwindows (windows) --subsystem windows to the linker
332 \\ --framework [name] (darwin) link against framework
333 \\ --mios-version-min [ver] (darwin) set iOS deployment target
334 \\ --mmacosx-version-min [ver] (darwin) set Mac OS X deployment target
335 \\ --ver-major [ver] Dynamic library semver major version
336 \\ --ver-minor [ver] Dynamic library semver minor version
337 \\ --ver-patch [ver] Dynamic library semver patch version
338 \\
339 \\
340;
diff --git a/examples/extended.zig b/examples/extended.zig
index e69de29..c21d254 100644
--- a/examples/extended.zig
+++ b/examples/extended.zig
@@ -0,0 +1,2 @@
1
2pub fn main() void {}
diff --git a/src/core.zig b/src/core.zig
index a3fb44c..22b5df2 100644
--- a/src/core.zig
+++ b/src/core.zig
@@ -217,26 +217,26 @@ pub fn Clap(comptime Id: type) type {
217 217
218 arena: heap.ArenaAllocator, 218 arena: heap.ArenaAllocator,
219 params: []const Param(Id), 219 params: []const Param(Id),
220 inner: &ArgIterator, 220 iter: &ArgIterator,
221 state: State, 221 state: State,
222 222
223 pub fn init(params: []const Param(Id), inner: &ArgIterator, allocator: &mem.Allocator) Self { 223 pub fn init(params: []const Param(Id), iter: &ArgIterator, allocator: &mem.Allocator) Self {
224 var res = Self { 224 var res = Self {
225 .arena = heap.ArenaAllocator.init(allocator), 225 .arena = heap.ArenaAllocator.init(allocator),
226 .params = params, 226 .params = params,
227 .inner = inner, 227 .iter = iter,
228 .state = State.Normal, 228 .state = State.Normal,
229 }; 229 };
230 230
231 return res; 231 return res;
232 } 232 }
233 233
234 pub fn deinit(iter: &Self) void { 234 pub fn deinit(clap: &Self) void {
235 iter.arena.deinit(); 235 clap.arena.deinit();
236 } 236 }
237 237
238 /// Get the next ::Arg that matches a ::Param. 238 /// Get the next ::Arg that matches a ::Param.
239 pub fn next(iter: &Self) !?Arg(Id) { 239 pub fn next(clap: &Self) !?Arg(Id) {
240 const ArgInfo = struct { 240 const ArgInfo = struct {
241 const Kind = enum { Long, Short, Bare }; 241 const Kind = enum { Long, Short, Bare };
242 242
@@ -244,9 +244,9 @@ pub fn Clap(comptime Id: type) type {
244 kind: Kind, 244 kind: Kind,
245 }; 245 };
246 246
247 switch (iter.state) { 247 switch (clap.state) {
248 State.Normal => { 248 State.Normal => {
249 const full_arg = (try iter.innerNext()) ?? return null; 249 const full_arg = (try clap.nextNoParse()) ?? return null;
250 const arg_info = blk: { 250 const arg_info = blk: {
251 var arg = full_arg; 251 var arg = full_arg;
252 var kind = ArgInfo.Kind.Bare; 252 var kind = ArgInfo.Kind.Bare;
@@ -272,7 +272,7 @@ pub fn Clap(comptime Id: type) type {
272 switch (kind) { 272 switch (kind) {
273 ArgInfo.Kind.Bare, 273 ArgInfo.Kind.Bare,
274 ArgInfo.Kind.Long => { 274 ArgInfo.Kind.Long => {
275 for (iter.params) |*param| { 275 for (clap.params) |*param| {
276 const match = switch (kind) { 276 const match = switch (kind) {
277 ArgInfo.Kind.Bare => param.names.bare ?? continue, 277 ArgInfo.Kind.Bare => param.names.bare ?? continue,
278 ArgInfo.Kind.Long => param.names.long ?? continue, 278 ArgInfo.Kind.Long => param.names.long ?? continue,
@@ -294,14 +294,14 @@ pub fn Clap(comptime Id: type) type {
294 if (maybe_value) |v| 294 if (maybe_value) |v|
295 break :blk v; 295 break :blk v;
296 296
297 break :blk (try iter.innerNext()) ?? return error.MissingValue; 297 break :blk (try clap.nextNoParse()) ?? return error.MissingValue;
298 }; 298 };
299 299
300 return Arg(Id).init(param.id, value); 300 return Arg(Id).init(param.id, value);
301 } 301 }
302 }, 302 },
303 ArgInfo.Kind.Short => { 303 ArgInfo.Kind.Short => {
304 return try iter.chainging(State.Chaining { 304 return try clap.chainging(State.Chaining {
305 .arg = full_arg, 305 .arg = full_arg,
306 .index = (full_arg.len - arg.len), 306 .index = (full_arg.len - arg.len),
307 }); 307 });
@@ -310,7 +310,7 @@ pub fn Clap(comptime Id: type) type {
310 310
311 // We do a final pass to look for value parameters matches 311 // We do a final pass to look for value parameters matches
312 if (kind == ArgInfo.Kind.Bare) { 312 if (kind == ArgInfo.Kind.Bare) {
313 for (iter.params) |*param| { 313 for (clap.params) |*param| {
314 if (param.names.bare) |_| continue; 314 if (param.names.bare) |_| continue;
315 if (param.names.short) |_| continue; 315 if (param.names.short) |_| continue;
316 if (param.names.long) |_| continue; 316 if (param.names.long) |_| continue;
@@ -321,26 +321,26 @@ pub fn Clap(comptime Id: type) type {
321 321
322 return error.InvalidArgument; 322 return error.InvalidArgument;
323 }, 323 },
324 @TagType(State).Chaining => |state| return try iter.chainging(state), 324 @TagType(State).Chaining => |state| return try clap.chainging(state),
325 } 325 }
326 } 326 }
327 327
328 fn chainging(iter: &Self, state: &const State.Chaining) !?Arg(Id) { 328 fn chainging(clap: &Self, state: &const State.Chaining) !?Arg(Id) {
329 const arg = state.arg; 329 const arg = state.arg;
330 const index = state.index; 330 const index = state.index;
331 const next_index = index + 1; 331 const next_index = index + 1;
332 332
333 for (iter.params) |param| { 333 for (clap.params) |param| {
334 const short = param.names.short ?? continue; 334 const short = param.names.short ?? continue;
335 if (short != arg[index]) 335 if (short != arg[index])
336 continue; 336 continue;
337 337
338 // Before we return, we have to set the new state of the iterator 338 // Before we return, we have to set the new state of the clap
339 defer { 339 defer {
340 if (arg.len <= next_index or param.takes_value) { 340 if (arg.len <= next_index or param.takes_value) {
341 iter.state = State.Normal; 341 clap.state = State.Normal;
342 } else { 342 } else {
343 iter.state = State { .Chaining = State.Chaining { 343 clap.state = State { .Chaining = State.Chaining {
344 .arg = arg, 344 .arg = arg,
345 .index = next_index, 345 .index = next_index,
346 }}; 346 }};
@@ -351,7 +351,7 @@ pub fn Clap(comptime Id: type) type {
351 return Arg(Id).init(param.id, null); 351 return Arg(Id).init(param.id, null);
352 352
353 if (arg.len <= next_index) { 353 if (arg.len <= next_index) {
354 const value = (try iter.innerNext()) ?? return error.MissingValue; 354 const value = (try clap.nextNoParse()) ?? return error.MissingValue;
355 return Arg(Id).init(param.id, value); 355 return Arg(Id).init(param.id, value);
356 } 356 }
357 357
@@ -365,8 +365,10 @@ pub fn Clap(comptime Id: type) type {
365 return error.InvalidArgument; 365 return error.InvalidArgument;
366 } 366 }
367 367
368 fn innerNext(iter: &Self) !?[]const u8 { 368 // Returns the next arg in the underlying arg iterator
369 return try iter.inner.next(&iter.arena.allocator); 369 pub fn nextNoParse(clap: &Self) !?[]const u8 {
370 clap.state = State.Normal;
371 return try clap.iter.next(&clap.arena.allocator);
370 } 372 }
371 }; 373 };
372} 374}