authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-05-30 11:53:08-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-05-30 11:53:08-04:00
log5954d5235fd0d029034d68f82bb7831ff47506f8
tree1f7244a8d83e96f1f69b1fb9f5fc0f7ded69ac4a
parent8ca294c430ecc4e878d9e5cfb178c20c07b83514
parent2975bdc684b74b013dc4d45c39535b872ac46a0a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #2182 from mikdusan/issue.2046

new .d file parser for stage1 compiler

6 files changed, 1240 insertions(+), 55 deletions(-)

CMakeLists.txt+1
......@@ -6728,6 +6728,7 @@ add_custom_command(
67286728 "-Doutput-dir=${CMAKE_BINARY_DIR}"
67296729 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
67306730 DEPENDS
6731 "${CMAKE_SOURCE_DIR}/src-self-hosted/dep_tokenizer.zig"
67316732 "${CMAKE_SOURCE_DIR}/src-self-hosted/stage1.zig"
67326733 "${CMAKE_SOURCE_DIR}/src-self-hosted/translate_c.zig"
67336734 "${CMAKE_SOURCE_DIR}/build.zig"
src-self-hosted/dep_tokenizer.zig created+1140
......@@ -0,0 +1,1140 @@
1const std = @import("std");
2const testing = std.testing;
3
4pub const Tokenizer = struct {
5 arena: std.heap.ArenaAllocator,
6 index: usize,
7 bytes: []const u8,
8 error_text: []const u8,
9 state: State,
10
11 pub fn init(allocator: *std.mem.Allocator, bytes: []const u8) Tokenizer {
12 return Tokenizer{
13 .arena = std.heap.ArenaAllocator.init(allocator),
14 .index = 0,
15 .bytes = bytes,
16 .error_text = "",
17 .state = State{ .lhs = {} },
18 };
19 }
20
21 pub fn deinit(self: *Tokenizer) void {
22 self.arena.deinit();
23 }
24
25 pub fn next(self: *Tokenizer) Error!?Token {
26 while (self.index < self.bytes.len) {
27 const char = self.bytes[self.index];
28 while (true) {
29 switch (self.state) {
30 .lhs => switch (char) {
31 '\t', '\n', '\r', ' ' => {
32 // silently ignore whitespace
33 break; // advance
34 },
35 else => {
36 self.state = State{ .target = try std.Buffer.initSize(&self.arena.allocator, 0) };
37 },
38 },
39 .target => |*target| switch (char) {
40 '\t', '\n', '\r', ' ' => {
41 return self.errorIllegalChar(self.index, char, "invalid target");
42 },
43 '$' => {
44 self.state = State{ .target_dollar_sign = target.* };
45 break; // advance
46 },
47 '\\' => {
48 self.state = State{ .target_reverse_solidus = target.* };
49 break; // advance
50 },
51 ':' => {
52 self.state = State{ .target_colon = target.* };
53 break; // advance
54 },
55 else => {
56 try target.appendByte(char);
57 break; // advance
58 },
59 },
60 .target_reverse_solidus => |*target| switch (char) {
61 '\t', '\n', '\r' => {
62 return self.errorIllegalChar(self.index, char, "bad target escape");
63 },
64 ' ', '#', '\\' => {
65 try target.appendByte(char);
66 self.state = State{ .target = target.* };
67 break; // advance
68 },
69 '$' => {
70 try target.append(self.bytes[self.index - 1 .. self.index]);
71 self.state = State{ .target_dollar_sign = target.* };
72 break; // advance
73 },
74 else => {
75 try target.append(self.bytes[self.index - 1 .. self.index + 1]);
76 self.state = State{ .target = target.* };
77 break; // advance
78 },
79 },
80 .target_dollar_sign => |*target| switch (char) {
81 '$' => {
82 try target.appendByte(char);
83 self.state = State{ .target = target.* };
84 break; // advance
85 },
86 else => {
87 return self.errorIllegalChar(self.index, char, "expecting '$'");
88 },
89 },
90 .target_colon => |*target| switch (char) {
91 '\n', '\r' => {
92 const bytes = target.toSlice();
93 if (bytes.len != 0) {
94 self.state = State{ .lhs = {} };
95 return Token{ .id = .target, .bytes = bytes };
96 }
97 // silently ignore null target
98 self.state = State{ .lhs = {} };
99 continue;
100 },
101 '\\' => {
102 self.state = State{ .target_colon_reverse_solidus = target.* };
103 break; // advance
104 },
105 else => {
106 const bytes = target.toSlice();
107 if (bytes.len != 0) {
108 self.state = State{ .rhs = {} };
109 return Token{ .id = .target, .bytes = bytes };
110 }
111 // silently ignore null target
112 self.state = State{ .lhs = {} };
113 continue;
114 },
115 },
116 .target_colon_reverse_solidus => |*target| switch (char) {
117 '\n', '\r' => {
118 const bytes = target.toSlice();
119 if (bytes.len != 0) {
120 self.state = State{ .lhs = {} };
121 return Token{ .id = .target, .bytes = bytes };
122 }
123 // silently ignore null target
124 self.state = State{ .lhs = {} };
125 continue;
126 },
127 else => {
128 try target.append(self.bytes[self.index - 2 .. self.index + 1]);
129 self.state = State{ .target = target.* };
130 break;
131 },
132 },
133 .rhs => switch (char) {
134 '\t', ' ' => {
135 // silently ignore horizontal whitespace
136 break; // advance
137 },
138 '\n', '\r' => {
139 self.state = State{ .lhs = {} };
140 continue;
141 },
142 '\\' => {
143 self.state = State{ .rhs_continuation = {} };
144 break; // advance
145 },
146 '"' => {
147 self.state = State{ .prereq_quote = try std.Buffer.initSize(&self.arena.allocator, 0) };
148 break; // advance
149 },
150 else => {
151 self.state = State{ .prereq = try std.Buffer.initSize(&self.arena.allocator, 0) };
152 },
153 },
154 .rhs_continuation => switch (char) {
155 '\n' => {
156 self.state = State{ .rhs = {} };
157 break; // advance
158 },
159 '\r' => {
160 self.state = State{ .rhs_continuation_linefeed = {} };
161 break; // advance
162 },
163 else => {
164 return self.errorIllegalChar(self.index, char, "continuation expecting end-of-line");
165 },
166 },
167 .rhs_continuation_linefeed => switch (char) {
168 '\n' => {
169 self.state = State{ .rhs = {} };
170 break; // advance
171 },
172 else => {
173 return self.errorIllegalChar(self.index, char, "continuation expecting end-of-line");
174 },
175 },
176 .prereq_quote => |*prereq| switch (char) {
177 '"' => {
178 const bytes = prereq.toSlice();
179 self.index += 1;
180 self.state = State{ .rhs = {} };
181 return Token{ .id = .prereq, .bytes = bytes };
182 },
183 else => {
184 try prereq.appendByte(char);
185 break; // advance
186 },
187 },
188 .prereq => |*prereq| switch (char) {
189 '\t', ' ' => {
190 const bytes = prereq.toSlice();
191 self.state = State{ .rhs = {} };
192 return Token{ .id = .prereq, .bytes = bytes };
193 },
194 '\n', '\r' => {
195 const bytes = prereq.toSlice();
196 self.state = State{ .lhs = {} };
197 return Token{ .id = .prereq, .bytes = bytes };
198 },
199 '\\' => {
200 self.state = State{ .prereq_continuation = prereq.* };
201 break; // advance
202 },
203 else => {
204 try prereq.appendByte(char);
205 break; // advance
206 },
207 },
208 .prereq_continuation => |*prereq| switch (char) {
209 '\n' => {
210 const bytes = prereq.toSlice();
211 self.index += 1;
212 self.state = State{ .rhs = {} };
213 return Token{ .id = .prereq, .bytes = bytes };
214 },
215 '\r' => {
216 self.state = State{ .prereq_continuation_linefeed = prereq.* };
217 break; // advance
218 },
219 else => {
220 // not continuation
221 try prereq.append(self.bytes[self.index - 1 .. self.index + 1]);
222 self.state = State{ .prereq = prereq.* };
223 break; // advance
224 },
225 },
226 .prereq_continuation_linefeed => |prereq| switch (char) {
227 '\n' => {
228 const bytes = prereq.toSlice();
229 self.index += 1;
230 self.state = State{ .rhs = {} };
231 return Token{ .id = .prereq, .bytes = bytes };
232 },
233 else => {
234 return self.errorIllegalChar(self.index, char, "continuation expecting end-of-line");
235 },
236 },
237 }
238 }
239 self.index += 1;
240 }
241
242 // eof, handle maybe incomplete token
243 if (self.index == 0) return null;
244 const idx = self.index - 1;
245 switch (self.state) {
246 .lhs,
247 .rhs,
248 .rhs_continuation,
249 .rhs_continuation_linefeed,
250 => {},
251 .target => |target| {
252 return self.errorPosition(idx, target.toSlice(), "incomplete target");
253 },
254 .target_reverse_solidus,
255 .target_dollar_sign,
256 => {
257 const index = self.index - 1;
258 return self.errorIllegalChar(idx, self.bytes[idx], "incomplete escape");
259 },
260 .target_colon => |target| {
261 const bytes = target.toSlice();
262 if (bytes.len != 0) {
263 self.index += 1;
264 self.state = State{ .rhs = {} };
265 return Token{ .id = .target, .bytes = bytes };
266 }
267 // silently ignore null target
268 self.state = State{ .lhs = {} };
269 },
270 .target_colon_reverse_solidus => |target| {
271 const bytes = target.toSlice();
272 if (bytes.len != 0) {
273 self.index += 1;
274 self.state = State{ .rhs = {} };
275 return Token{ .id = .target, .bytes = bytes };
276 }
277 // silently ignore null target
278 self.state = State{ .lhs = {} };
279 },
280 .prereq_quote => |prereq| {
281 return self.errorPosition(idx, prereq.toSlice(), "incomplete quoted prerequisite");
282 },
283 .prereq => |prereq| {
284 const bytes = prereq.toSlice();
285 self.state = State{ .lhs = {} };
286 return Token{ .id = .prereq, .bytes = bytes };
287 },
288 .prereq_continuation => |prereq| {
289 const bytes = prereq.toSlice();
290 self.state = State{ .lhs = {} };
291 return Token{ .id = .prereq, .bytes = bytes };
292 },
293 .prereq_continuation_linefeed => |prereq| {
294 const bytes = prereq.toSlice();
295 self.state = State{ .lhs = {} };
296 return Token{ .id = .prereq, .bytes = bytes };
297 },
298 }
299 return null;
300 }
301
302 fn errorf(self: *Tokenizer, comptime fmt: []const u8, args: ...) Error {
303 self.error_text = (try std.Buffer.allocPrint(&self.arena.allocator, fmt, args)).toSlice();
304 return Error.InvalidInput;
305 }
306
307 fn errorPosition(self: *Tokenizer, position: usize, bytes: []const u8, comptime fmt: []const u8, args: ...) Error {
308 var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
309 std.fmt.format(&buffer, anyerror, std.Buffer.append, fmt, args) catch {};
310 try buffer.append(" '");
311 var out = makeOutput(std.Buffer.append, &buffer);
312 try printCharValues(&out, bytes);
313 try buffer.append("'");
314 std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", position - (bytes.len - 1)) catch {};
315 self.error_text = buffer.toSlice();
316 return Error.InvalidInput;
317 }
318
319 fn errorIllegalChar(self: *Tokenizer, position: usize, char: u8, comptime fmt: []const u8, args: ...) Error {
320 var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
321 try buffer.append("illegal char ");
322 var out = makeOutput(std.Buffer.append, &buffer);
323 try printUnderstandableChar(&out, char);
324 std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", position) catch {};
325 if (fmt.len != 0) std.fmt.format(&buffer, anyerror, std.Buffer.append, ": " ++ fmt, args) catch {};
326 self.error_text = buffer.toSlice();
327 return Error.InvalidInput;
328 }
329
330 const Error = error{
331 OutOfMemory,
332 InvalidInput,
333 };
334
335 const State = union(enum) {
336 lhs: void,
337 target: std.Buffer,
338 target_reverse_solidus: std.Buffer,
339 target_dollar_sign: std.Buffer,
340 target_colon: std.Buffer,
341 target_colon_reverse_solidus: std.Buffer,
342 rhs: void,
343 rhs_continuation: void,
344 rhs_continuation_linefeed: void,
345 prereq_quote: std.Buffer,
346 prereq: std.Buffer,
347 prereq_continuation: std.Buffer,
348 prereq_continuation_linefeed: std.Buffer,
349 };
350
351 const Token = struct {
352 id: ID,
353 bytes: []const u8,
354
355 const ID = enum {
356 target,
357 prereq,
358 };
359 };
360};
361
362export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer {
363 const t = std.heap.c_allocator.create(Tokenizer) catch @panic("failed to create .d tokenizer");
364 t.* = Tokenizer.init(std.heap.c_allocator, input[0..len]);
365 return stage2_DepTokenizer{
366 .handle = t,
367 };
368}
369
370export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void {
371 self.handle.deinit();
372}
373
374export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult {
375 const otoken = self.handle.next() catch {
376 const textz = std.Buffer.init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text");
377 return stage2_DepNextResult{
378 .type_id = .error_,
379 .textz = textz.toSlice().ptr,
380 };
381 };
382 const token = otoken orelse {
383 return stage2_DepNextResult{
384 .type_id = .null_,
385 .textz = undefined,
386 };
387 };
388 const textz = std.Buffer.init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text");
389 return stage2_DepNextResult{
390 .type_id = switch (token.id) {
391 .target => stage2_DepNextResult.TypeId.target,
392 .prereq => stage2_DepNextResult.TypeId.prereq,
393 },
394 .textz = textz.toSlice().ptr,
395 };
396}
397
398export const stage2_DepTokenizer = extern struct {
399 handle: *Tokenizer,
400};
401
402export const stage2_DepNextResult = extern struct {
403 type_id: TypeId,
404
405 // when type_id == error --> error text
406 // when type_id == null --> undefined
407 // when type_id == target --> target pathname
408 // when type_id == prereq --> prereq pathname
409 textz: [*]const u8,
410
411 export const TypeId = extern enum {
412 error_,
413 null_,
414 target,
415 prereq,
416 };
417};
418
419test "empty file" {
420 try depTokenizer("", "");
421}
422
423test "empty whitespace" {
424 try depTokenizer("\n", "");
425 try depTokenizer("\r", "");
426 try depTokenizer("\r\n", "");
427 try depTokenizer(" ", "");
428}
429
430test "empty colon" {
431 try depTokenizer(":", "");
432 try depTokenizer("\n:", "");
433 try depTokenizer("\r:", "");
434 try depTokenizer("\r\n:", "");
435 try depTokenizer(" :", "");
436}
437
438test "empty target" {
439 try depTokenizer("foo.o:", "target = {foo.o}");
440 try depTokenizer(
441 \\foo.o:
442 \\bar.o:
443 \\abcd.o:
444 ,
445 \\target = {foo.o}
446 \\target = {bar.o}
447 \\target = {abcd.o}
448 );
449}
450
451test "whitespace empty target" {
452 try depTokenizer("\nfoo.o:", "target = {foo.o}");
453 try depTokenizer("\rfoo.o:", "target = {foo.o}");
454 try depTokenizer("\r\nfoo.o:", "target = {foo.o}");
455 try depTokenizer(" foo.o:", "target = {foo.o}");
456}
457
458test "escape empty target" {
459 try depTokenizer("\\ foo.o:", "target = { foo.o}");
460 try depTokenizer("\\#foo.o:", "target = {#foo.o}");
461 try depTokenizer("\\\\foo.o:", "target = {\\foo.o}");
462 try depTokenizer("$$foo.o:", "target = {$foo.o}");
463}
464
465test "empty target linefeeds" {
466 try depTokenizer("\n", "");
467 try depTokenizer("\r\n", "");
468
469 const expect = "target = {foo.o}";
470 try depTokenizer(
471 \\foo.o:
472 ,
473 expect
474 );
475 try depTokenizer(
476 \\foo.o:
477 \\
478 ,
479 expect
480 );
481 try depTokenizer(
482 \\foo.o:
483 ,
484 expect
485 );
486 try depTokenizer(
487 \\foo.o:
488 \\
489 ,
490 expect
491 );
492}
493
494test "empty target linefeeds + continuations" {
495 const expect = "target = {foo.o}";
496 try depTokenizer(
497 \\foo.o:\
498 ,
499 expect
500 );
501 try depTokenizer(
502 \\foo.o:\
503 \\
504 ,
505 expect
506 );
507 try depTokenizer(
508 \\foo.o:\
509 ,
510 expect
511 );
512 try depTokenizer(
513 \\foo.o:\
514 \\
515 ,
516 expect
517 );
518}
519
520test "empty target linefeeds + hspace + continuations" {
521 const expect = "target = {foo.o}";
522 try depTokenizer(
523 \\foo.o: \
524 ,
525 expect
526 );
527 try depTokenizer(
528 \\foo.o: \
529 \\
530 ,
531 expect
532 );
533 try depTokenizer(
534 \\foo.o: \
535 ,
536 expect
537 );
538 try depTokenizer(
539 \\foo.o: \
540 \\
541 ,
542 expect
543 );
544}
545
546test "prereq" {
547 const expect =
548 \\target = {foo.o}
549 \\prereq = {foo.c}
550 ;
551 try depTokenizer("foo.o: foo.c", expect);
552 try depTokenizer(
553 \\foo.o: \
554 \\foo.c
555 , expect);
556 try depTokenizer(
557 \\foo.o: \
558 \\ foo.c
559 , expect);
560 try depTokenizer(
561 \\foo.o: \
562 \\ foo.c
563 , expect);
564}
565
566test "prereq continuation" {
567 const expect =
568 \\target = {foo.o}
569 \\prereq = {foo.h}
570 \\prereq = {bar.h}
571 ;
572 try depTokenizer(
573 \\foo.o: foo.h\
574 \\bar.h
575 ,
576 expect
577 );
578 try depTokenizer(
579 \\foo.o: foo.h\
580 \\bar.h
581 ,
582 expect
583 );
584}
585
586test "multiple prereqs" {
587 const expect =
588 \\target = {foo.o}
589 \\prereq = {foo.c}
590 \\prereq = {foo.h}
591 \\prereq = {bar.h}
592 ;
593 try depTokenizer("foo.o: foo.c foo.h bar.h", expect);
594 try depTokenizer(
595 \\foo.o: \
596 \\foo.c foo.h bar.h
597 , expect);
598 try depTokenizer(
599 \\foo.o: foo.c foo.h bar.h\
600 , expect);
601 try depTokenizer(
602 \\foo.o: foo.c foo.h bar.h\
603 \\
604 , expect);
605 try depTokenizer(
606 \\foo.o: \
607 \\foo.c \
608 \\ foo.h\
609 \\bar.h
610 \\
611 , expect);
612 try depTokenizer(
613 \\foo.o: \
614 \\foo.c \
615 \\ foo.h\
616 \\bar.h\
617 \\
618 , expect);
619 try depTokenizer(
620 \\foo.o: \
621 \\foo.c \
622 \\ foo.h\
623 \\bar.h\
624 , expect);
625}
626
627test "multiple targets and prereqs" {
628 try depTokenizer(
629 \\foo.o: foo.c
630 \\bar.o: bar.c a.h b.h c.h
631 \\abc.o: abc.c \
632 \\ one.h two.h \
633 \\ three.h four.h
634 ,
635 \\target = {foo.o}
636 \\prereq = {foo.c}
637 \\target = {bar.o}
638 \\prereq = {bar.c}
639 \\prereq = {a.h}
640 \\prereq = {b.h}
641 \\prereq = {c.h}
642 \\target = {abc.o}
643 \\prereq = {abc.c}
644 \\prereq = {one.h}
645 \\prereq = {two.h}
646 \\prereq = {three.h}
647 \\prereq = {four.h}
648 );
649 try depTokenizer(
650 \\ascii.o: ascii.c
651 \\base64.o: base64.c stdio.h
652 \\elf.o: elf.c a.h b.h c.h
653 \\macho.o: \
654 \\ macho.c\
655 \\ a.h b.h c.h
656 ,
657 \\target = {ascii.o}
658 \\prereq = {ascii.c}
659 \\target = {base64.o}
660 \\prereq = {base64.c}
661 \\prereq = {stdio.h}
662 \\target = {elf.o}
663 \\prereq = {elf.c}
664 \\prereq = {a.h}
665 \\prereq = {b.h}
666 \\prereq = {c.h}
667 \\target = {macho.o}
668 \\prereq = {macho.c}
669 \\prereq = {a.h}
670 \\prereq = {b.h}
671 \\prereq = {c.h}
672 );
673 try depTokenizer(
674 \\a$$scii.o: ascii.c
675 \\\\base64.o: "\base64.c" "s t#dio.h"
676 \\e\\lf.o: "e\lf.c" "a.h$$" "$$b.h c.h$$"
677 \\macho.o: \
678 \\ "macho!.c" \
679 \\ a.h b.h c.h
680 ,
681 \\target = {a$scii.o}
682 \\prereq = {ascii.c}
683 \\target = {\base64.o}
684 \\prereq = {\base64.c}
685 \\prereq = {s t#dio.h}
686 \\target = {e\lf.o}
687 \\prereq = {e\lf.c}
688 \\prereq = {a.h$$}
689 \\prereq = {$$b.h c.h$$}
690 \\target = {macho.o}
691 \\prereq = {macho!.c}
692 \\prereq = {a.h}
693 \\prereq = {b.h}
694 \\prereq = {c.h}
695 );
696}
697
698test "windows quoted prereqs" {
699 try depTokenizer(
700 \\c:\foo.o: "C:\Program Files (x86)\Microsoft Visual Studio\foo.c"
701 \\c:\foo2.o: "C:\Program Files (x86)\Microsoft Visual Studio\foo2.c" \
702 \\ "C:\Program Files (x86)\Microsoft Visual Studio\foo1.h" \
703 \\ "C:\Program Files (x86)\Microsoft Visual Studio\foo2.h"
704 ,
705 \\target = {c:\foo.o}
706 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\foo.c}
707 \\target = {c:\foo2.o}
708 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\foo2.c}
709 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\foo1.h}
710 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\foo2.h}
711 );
712}
713
714test "windows mixed prereqs" {
715 try depTokenizer(
716 \\cimport.o: \
717 \\ C:\msys64\home\anon\project\zig\master\zig-cache\o\qhvhbUo7GU5iKyQ5mpA8TcQpncCYaQu0wwvr3ybiSTj_Dtqi1Nmcb70kfODJ2Qlg\cimport.h \
718 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\stdio.h" \
719 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt.h" \
720 \\ "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vcruntime.h" \
721 \\ "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\sal.h" \
722 \\ "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\concurrencysal.h" \
723 \\ C:\msys64\opt\zig\lib\zig\include\vadefs.h \
724 \\ "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vadefs.h" \
725 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_wstdio.h" \
726 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_stdio_config.h" \
727 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\string.h" \
728 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_memory.h" \
729 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_memcpy_s.h" \
730 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\errno.h" \
731 \\ "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vcruntime_string.h" \
732 \\ "C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_wstring.h"
733 ,
734 \\target = {cimport.o}
735 \\prereq = {C:\msys64\home\anon\project\zig\master\zig-cache\o\qhvhbUo7GU5iKyQ5mpA8TcQpncCYaQu0wwvr3ybiSTj_Dtqi1Nmcb70kfODJ2Qlg\cimport.h}
736 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\stdio.h}
737 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt.h}
738 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vcruntime.h}
739 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\sal.h}
740 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\concurrencysal.h}
741 \\prereq = {C:\msys64\opt\zig\lib\zig\include\vadefs.h}
742 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vadefs.h}
743 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_wstdio.h}
744 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_stdio_config.h}
745 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\string.h}
746 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_memory.h}
747 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_memcpy_s.h}
748 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\errno.h}
749 \\prereq = {C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.21.27702\lib\x64\\..\..\include\vcruntime_string.h}
750 \\prereq = {C:\Program Files (x86)\Windows Kits\10\\Include\10.0.17763.0\ucrt\corecrt_wstring.h}
751 );
752}
753
754test "funky targets" {
755 try depTokenizer(
756 \\C:\Users\anon\foo.o:
757 \\C:\Users\anon\foo\ .o:
758 \\C:\Users\anon\foo\#.o:
759 \\C:\Users\anon\foo$$.o:
760 \\C:\Users\anon\\\ foo.o:
761 \\C:\Users\anon\\#foo.o:
762 \\C:\Users\anon\$$foo.o:
763 \\C:\Users\anon\\\ \ \ \ \ foo.o:
764 ,
765 \\target = {C:\Users\anon\foo.o}
766 \\target = {C:\Users\anon\foo .o}
767 \\target = {C:\Users\anon\foo#.o}
768 \\target = {C:\Users\anon\foo$.o}
769 \\target = {C:\Users\anon\ foo.o}
770 \\target = {C:\Users\anon\#foo.o}
771 \\target = {C:\Users\anon\$foo.o}
772 \\target = {C:\Users\anon\ foo.o}
773 );
774}
775
776test "error incomplete escape - reverse_solidus" {
777 try depTokenizer("\\",
778 \\ERROR: illegal char '\' at position 0: incomplete escape
779 );
780 try depTokenizer("\t\\",
781 \\ERROR: illegal char '\' at position 1: incomplete escape
782 );
783 try depTokenizer("\n\\",
784 \\ERROR: illegal char '\' at position 1: incomplete escape
785 );
786 try depTokenizer("\r\\",
787 \\ERROR: illegal char '\' at position 1: incomplete escape
788 );
789 try depTokenizer("\r\n\\",
790 \\ERROR: illegal char '\' at position 2: incomplete escape
791 );
792 try depTokenizer(" \\",
793 \\ERROR: illegal char '\' at position 1: incomplete escape
794 );
795}
796
797test "error incomplete escape - dollar_sign" {
798 try depTokenizer("$",
799 \\ERROR: illegal char '$' at position 0: incomplete escape
800 );
801 try depTokenizer("\t$",
802 \\ERROR: illegal char '$' at position 1: incomplete escape
803 );
804 try depTokenizer("\n$",
805 \\ERROR: illegal char '$' at position 1: incomplete escape
806 );
807 try depTokenizer("\r$",
808 \\ERROR: illegal char '$' at position 1: incomplete escape
809 );
810 try depTokenizer("\r\n$",
811 \\ERROR: illegal char '$' at position 2: incomplete escape
812 );
813 try depTokenizer(" $",
814 \\ERROR: illegal char '$' at position 1: incomplete escape
815 );
816}
817
818test "error incomplete target" {
819 try depTokenizer("foo.o",
820 \\ERROR: incomplete target 'foo.o' at position 0
821 );
822 try depTokenizer("\tfoo.o",
823 \\ERROR: incomplete target 'foo.o' at position 1
824 );
825 try depTokenizer("\nfoo.o",
826 \\ERROR: incomplete target 'foo.o' at position 1
827 );
828 try depTokenizer("\rfoo.o",
829 \\ERROR: incomplete target 'foo.o' at position 1
830 );
831 try depTokenizer("\r\nfoo.o",
832 \\ERROR: incomplete target 'foo.o' at position 2
833 );
834 try depTokenizer(" foo.o",
835 \\ERROR: incomplete target 'foo.o' at position 1
836 );
837
838 try depTokenizer("\\ foo.o",
839 \\ERROR: incomplete target ' foo.o' at position 1
840 );
841 try depTokenizer("\\#foo.o",
842 \\ERROR: incomplete target '#foo.o' at position 1
843 );
844 try depTokenizer("\\\\foo.o",
845 \\ERROR: incomplete target '\foo.o' at position 1
846 );
847 try depTokenizer("$$foo.o",
848 \\ERROR: incomplete target '$foo.o' at position 1
849 );
850}
851
852test "error illegal char at position - bad target escape" {
853 try depTokenizer("\\\t",
854 \\ERROR: illegal char \x09 at position 1: bad target escape
855 );
856 try depTokenizer("\\\n",
857 \\ERROR: illegal char \x0A at position 1: bad target escape
858 );
859 try depTokenizer("\\\r",
860 \\ERROR: illegal char \x0D at position 1: bad target escape
861 );
862 try depTokenizer("\\\r\n",
863 \\ERROR: illegal char \x0D at position 1: bad target escape
864 );
865}
866
867test "error illegal char at position - execting dollar_sign" {
868 try depTokenizer("$\t",
869 \\ERROR: illegal char \x09 at position 1: expecting '$'
870 );
871 try depTokenizer("$\n",
872 \\ERROR: illegal char \x0A at position 1: expecting '$'
873 );
874 try depTokenizer("$\r",
875 \\ERROR: illegal char \x0D at position 1: expecting '$'
876 );
877 try depTokenizer("$\r\n",
878 \\ERROR: illegal char \x0D at position 1: expecting '$'
879 );
880}
881
882test "error illegal char at position - invalid target" {
883 try depTokenizer("foo\t.o",
884 \\ERROR: illegal char \x09 at position 3: invalid target
885 );
886 try depTokenizer("foo\n.o",
887 \\ERROR: illegal char \x0A at position 3: invalid target
888 );
889 try depTokenizer("foo\r.o",
890 \\ERROR: illegal char \x0D at position 3: invalid target
891 );
892 try depTokenizer("foo\r\n.o",
893 \\ERROR: illegal char \x0D at position 3: invalid target
894 );
895}
896
897test "error target - continuation expecting end-of-line" {
898 try depTokenizer("foo.o: \\\t",
899 \\target = {foo.o}
900 \\ERROR: illegal char \x09 at position 8: continuation expecting end-of-line
901 );
902 try depTokenizer("foo.o: \\ ",
903 \\target = {foo.o}
904 \\ERROR: illegal char \x20 at position 8: continuation expecting end-of-line
905 );
906 try depTokenizer("foo.o: \\x",
907 \\target = {foo.o}
908 \\ERROR: illegal char 'x' at position 8: continuation expecting end-of-line
909 );
910 try depTokenizer("foo.o: \\ x",
911 \\target = {foo.o}
912 \\ERROR: illegal char 'x' at position 9: continuation expecting end-of-line
913 );
914}
915
916test "error prereq - continuation expecting end-of-line" {
917 try depTokenizer("foo.o: foo.h\\ x",
918 \\target = {foo.o}
919 \\ERROR: illegal char 'x' at position 14: continuation expecting end-of-line
920 );
921}
922
923// - tokenize input, emit textual representation, and compare to expect
924fn depTokenizer(input: []const u8, expect: []const u8) !void {
925 var direct_allocator = std.heap.DirectAllocator.init();
926 var arena_allocator = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
927 const arena = &arena_allocator.allocator;
928 defer arena_allocator.deinit();
929
930 var it = Tokenizer.init(&direct_allocator.allocator, input);
931 var buffer = try std.Buffer.initSize(arena, 0);
932 var i: usize = 0;
933 while (true) {
934 const r = it.next() catch |err| {
935 switch (err) {
936 Tokenizer.Error.InvalidInput => {
937 if (i != 0) try buffer.append("\n");
938 try buffer.append("ERROR: ");
939 try buffer.append(it.error_text);
940 },
941 else => return err,
942 }
943 break;
944 };
945 const token = r orelse break;
946 if (i != 0) try buffer.append("\n");
947 try buffer.append(@tagName(token.id));
948 try buffer.append(" = {");
949 for (token.bytes) |b| {
950 try buffer.appendByte(printable_char_tab[b]);
951 }
952 try buffer.append("}");
953 i += 1;
954 }
955 const got: []const u8 = buffer.toSlice();
956
957 if (std.mem.eql(u8, expect, got)) {
958 testing.expect(true);
959 return;
960 }
961
962 var out = makeOutput(std.fs.File.write, try std.io.getStdErr());
963
964 try out.write("\n");
965 try printSection(&out, "<<<< input", input);
966 try printSection(&out, "==== expect", expect);
967 try printSection(&out, ">>>> got", got);
968 try printRuler(&out);
969
970 testing.expect(false);
971}
972
973fn printSection(out: var, label: []const u8, bytes: []const u8) !void {
974 try printLabel(out, label, bytes);
975 try hexDump(out, bytes);
976 try printRuler(out);
977 try out.write(bytes);
978 try out.write("\n");
979}
980
981fn printLabel(out: var, label: []const u8, bytes: []const u8) !void {
982 var buf: [80]u8 = undefined;
983 var text = try std.fmt.bufPrint(buf[0..], "{} {} bytes ", label, bytes.len);
984 try out.write(text);
985 var i: usize = text.len;
986 const end = 79;
987 while (i < 79) : (i += 1) {
988 try out.write([]const u8{label[0]});
989 }
990 try out.write("\n");
991}
992
993fn printRuler(out: var) !void {
994 var i: usize = 0;
995 const end = 79;
996 while (i < 79) : (i += 1) {
997 try out.write("-");
998 }
999 try out.write("\n");
1000}
1001
1002fn hexDump(out: var, bytes: []const u8) !void {
1003 const n16 = bytes.len >> 4;
1004 var line: usize = 0;
1005 var offset: usize = 0;
1006 while (line < n16) : (line += 1) {
1007 try hexDump16(out, offset, bytes[offset .. offset + 16]);
1008 offset += 16;
1009 }
1010
1011 const n = bytes.len & 0x0f;
1012 if (n > 0) {
1013 try printDecValue(out, offset, 8);
1014 try out.write(":");
1015 try out.write(" ");
1016 var end1 = std.math.min(offset + n, offset + 8);
1017 for (bytes[offset..end1]) |b| {
1018 try out.write(" ");
1019 try printHexValue(out, b, 2);
1020 }
1021 var end2 = offset + n;
1022 if (end2 > end1) {
1023 try out.write(" ");
1024 for (bytes[end1..end2]) |b| {
1025 try out.write(" ");
1026 try printHexValue(out, b, 2);
1027 }
1028 }
1029 const short = 16 - n;
1030 var i: usize = 0;
1031 while (i < short) : (i += 1) {
1032 try out.write(" ");
1033 }
1034 if (end2 > end1) {
1035 try out.write(" |");
1036 } else {
1037 try out.write(" |");
1038 }
1039 try printCharValues(out, bytes[offset..end2]);
1040 try out.write("|\n");
1041 offset += n;
1042 }
1043
1044 try printDecValue(out, offset, 8);
1045 try out.write(":");
1046 try out.write("\n");
1047}
1048
1049fn hexDump16(out: var, offset: usize, bytes: []const u8) !void {
1050 try printDecValue(out, offset, 8);
1051 try out.write(":");
1052 try out.write(" ");
1053 for (bytes[0..8]) |b| {
1054 try out.write(" ");
1055 try printHexValue(out, b, 2);
1056 }
1057 try out.write(" ");
1058 for (bytes[8..16]) |b| {
1059 try out.write(" ");
1060 try printHexValue(out, b, 2);
1061 }
1062 try out.write(" |");
1063 try printCharValues(out, bytes);
1064 try out.write("|\n");
1065}
1066
1067fn printDecValue(out: var, value: u64, width: u8) !void {
1068 var buffer: [20]u8 = undefined;
1069 const len = std.fmt.formatIntBuf(buffer[0..], value, 10, false, width);
1070 try out.write(buffer[0..len]);
1071}
1072
1073fn printHexValue(out: var, value: u64, width: u8) !void {
1074 var buffer: [16]u8 = undefined;
1075 const len = std.fmt.formatIntBuf(buffer[0..], value, 16, false, width);
1076 try out.write(buffer[0..len]);
1077}
1078
1079fn printCharValues(out: var, bytes: []const u8) !void {
1080 for (bytes) |b| {
1081 try out.write([]const u8{printable_char_tab[b]});
1082 }
1083}
1084
1085fn printUnderstandableChar(out: var, char: u8) !void {
1086 if (!std.ascii.isPrint(char) or char == ' ') {
1087 std.fmt.format(out.context, anyerror, out.output, "\\x{X2}", char) catch {};
1088 } else {
1089 try out.write("'");
1090 try out.write([]const u8{printable_char_tab[char]});
1091 try out.write("'");
1092 }
1093}
1094
1095// zig fmt: off
1096const printable_char_tab: []const u8 =
1097 "................................ !\"#$%&'()*+,-./0123456789:;<=>?" ++
1098 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~." ++
1099 "................................................................" ++
1100 "................................................................";
1101// zig fmt: on
1102comptime {
1103 std.debug.assert(printable_char_tab.len == 256);
1104}
1105
1106// Make an output var that wraps a context and output function.
1107// output: must be a function that takes a `self` idiom parameter
1108// and a bytes parameter
1109// context: must be that self
1110fn makeOutput(output: var, context: var) Output(@typeOf(output)) {
1111 return Output(@typeOf(output)){
1112 .output = output,
1113 .context = context,
1114 };
1115}
1116
1117fn Output(comptime T: type) type {
1118 const args = switch (@typeInfo(T)) {
1119 .Fn => |f| f.args,
1120 else => @compileError("output parameter is not a function"),
1121 };
1122 if (args.len != 2) {
1123 @compileError("output function must take 2 arguments");
1124 }
1125 const at0 = args[0].arg_type orelse @compileError("output arg[0] does not have a type");
1126 const at1 = args[1].arg_type orelse @compileError("output arg[1] does not have a type");
1127 const arg1p = switch (@typeInfo(at1)) {
1128 .Pointer => |p| p,
1129 else => @compileError("output arg[1] is not a slice"),
1130 };
1131 if (arg1p.child != u8) @compileError("output arg[1] is not a u8 slice");
1132 return struct {
1133 output: T,
1134 context: at0,
1135
1136 fn write(self: *@This(), bytes: []const u8) !void {
1137 try self.output(self.context, bytes);
1138 }
1139 };
1140}
src-self-hosted/stage1.zig+4
......@@ -20,6 +20,10 @@ var stderr_file: fs.File = undefined;
2020var stderr: *io.OutStream(fs.File.WriteError) = undefined;
2121var stdout: *io.OutStream(fs.File.WriteError) = undefined;
2222
23comptime {
24 _ = @import("dep_tokenizer.zig");
25}
26
2327// ABI warning
2428export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
2529 const info_zen = @import("main.zig").info_zen;
src/cache_hash.cpp+47-55
......@@ -5,6 +5,7 @@
55 * See http://opensource.org/licenses/MIT
66 */
77
8#include "userland.h"
89#include "cache_hash.hpp"
910#include "all_types.hpp"
1011#include "buffer.hpp"
......@@ -473,71 +474,62 @@ Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
473474 if (err == ErrorFileNotFound)
474475 return err;
475476 if (verbose) {
476 fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
477 fprintf(stderr, "%s: unable to read .d file: %s\n", err_str(err), buf_ptr(dep_file_path));
477478 }
478479 return ErrorReadingDepFile;
479480 }
480 SplitIterator it = memSplit(buf_to_slice(contents), str("\r\n"));
481 // skip first line
482 SplitIterator_next(&it);
483 for (;;) {
484 Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
485 if (!opt_line.is_some)
486 break;
487 if (opt_line.value.len == 0)
488 continue;
489 // skip over indentation
490 while (opt_line.value.len != 0 && (opt_line.value.ptr[0] == ' ' || opt_line.value.ptr[0] == '\t')) {
491 opt_line.value.ptr += 1;
492 opt_line.value.len -= 1;
493 }
494 if (opt_line.value.len == 0)
495 continue;
496
497 if (opt_line.value.ptr[0] == '"') {
498 if (opt_line.value.len < 2) {
481 auto it = stage2_DepTokenizer_init(buf_ptr(contents), buf_len(contents));
482 // skip first token: target
483 {
484 auto result = stage2_DepTokenizer_next(&it);
485 switch (result.type_id) {
486 case stage2_DepNextResult::error:
499487 if (verbose) {
500 fprintf(stderr, "unable to process invalid .d file %s: line too short\n", buf_ptr(dep_file_path));
488 fprintf(stderr, "%s: failed processing .d file: %s\n", result.textz, buf_ptr(dep_file_path));
501489 }
502 return ErrorInvalidDepFile;
503 }
504 opt_line.value.ptr += 1;
505 opt_line.value.len -= 2;
506 while (opt_line.value.len != 0 && opt_line.value.ptr[opt_line.value.len] != '"') {
507 opt_line.value.len -= 1;
508 }
509 if (opt_line.value.len == 0) {
510 if (verbose) {
511 fprintf(stderr, "unable to process invalid .d file %s: missing double quote\n", buf_ptr(dep_file_path));
512 }
513 return ErrorInvalidDepFile;
514 }
515 Buf *filename_buf = buf_create_from_slice(opt_line.value);
516 if ((err = cache_add_file(ch, filename_buf))) {
490 err = ErrorInvalidDepFile;
491 goto finish;
492 case stage2_DepNextResult::null:
493 err = ErrorNone;
494 goto finish;
495 case stage2_DepNextResult::target:
496 case stage2_DepNextResult::prereq:
497 err = ErrorNone;
498 break;
499 }
500 }
501 // Process 0+ preqreqs.
502 // clang is invoked in single-source mode so we never get more targets.
503 for (;;) {
504 auto result = stage2_DepTokenizer_next(&it);
505 switch (result.type_id) {
506 case stage2_DepNextResult::error:
517507 if (verbose) {
518 fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
519 fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
520 }
521 return err;
522 }
523 } else {
524 // sometimes there are multiple files on the same line; we actually need space tokenization.
525 SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
526 Slice<uint8_t> filename;
527 while (SplitIterator_next(&line_it).unwrap(&filename)) {
528 Buf *filename_buf = buf_create_from_slice(filename);
529 if (buf_eql_str(filename_buf, "\\")) continue;
530 if ((err = cache_add_file(ch, filename_buf))) {
531 if (verbose) {
532 fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
533 fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
534 }
535 return err;
508 fprintf(stderr, "%s: failed processing .d file: %s\n", result.textz, buf_ptr(dep_file_path));
536509 }
510 err = ErrorInvalidDepFile;
511 goto finish;
512 case stage2_DepNextResult::null:
513 case stage2_DepNextResult::target:
514 err = ErrorNone;
515 goto finish;
516 case stage2_DepNextResult::prereq:
517 break;
518 }
519 auto textbuf = buf_alloc();
520 buf_init_from_str(textbuf, result.textz);
521 if ((err = cache_add_file(ch, textbuf))) {
522 if (verbose) {
523 fprintf(stderr, "unable to add %s to cache: %s\n", result.textz, err_str(err));
524 fprintf(stderr, "when processing .d file: %s\n", buf_ptr(dep_file_path));
537525 }
526 goto finish;
538527 }
539528 }
540 return ErrorNone;
529
530 finish:
531 stage2_DepTokenizer_deinit(&it);
532 return err;
541533}
542534
543535static Error write_manifest_file(CacheHash *ch) {
src/userland.cpp+15
......@@ -42,3 +42,18 @@ int stage2_fmt(int argc, char **argv) {
4242 const char *msg = "stage0 called stage2_fmt";
4343 stage2_panic(msg, strlen(msg));
4444}
45
46stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len) {
47 const char *msg = "stage0 called stage2_DepTokenizer_init";
48 stage2_panic(msg, strlen(msg));
49}
50
51void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) {
52 const char *msg = "stage0 called stage2_DepTokenizer_deinit";
53 stage2_panic(msg, strlen(msg));
54}
55
56stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self) {
57 const char *msg = "stage0 called stage2_DepTokenizer_next";
58 stage2_panic(msg, strlen(msg));
59}
src/userland.h+33
......@@ -9,6 +9,7 @@
99#define ZIG_USERLAND_H
1010
1111#include <stddef.h>
12#include <stdint.h>
1213#include <stdio.h>
1314
1415#ifdef __cplusplus
......@@ -118,4 +119,36 @@ ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t le
118119// ABI warning
119120ZIG_EXTERN_C int stage2_fmt(int argc, char **argv);
120121
122// ABI warning
123struct stage2_DepTokenizer {
124 void *handle;
125};
126
127// ABI warning
128struct stage2_DepNextResult {
129 enum TypeId {
130 error,
131 null,
132 target,
133 prereq,
134 };
135
136 TypeId type_id;
137
138 // when ent == error --> error text
139 // when ent == null --> undefined
140 // when ent == target --> target pathname
141 // when ent == prereq --> prereq pathname
142 const char *textz;
143};
144
145// ABI warning
146ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len);
147
148// ABI warning
149ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self);
150
151// ABI warning
152ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self);
153
121154#endif