authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-11-24 20:11:11+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-11-25 12:28:19+02:00
log74010fecc7bbeaf9de77c28dda5906c3c1f4a6df
tree52c184214f084bea4a1cd354ab91151cdc43de2b
parentd2a8660d0467c024790c7dcdeb9366d993723fd7

translate-c: use Aro's tokenizer


9 files changed, 320 insertions(+), 1868 deletions(-)

CMakeLists.txt-1
......@@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES
218218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
219219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"
220220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
221 "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig"
222221 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"
223222 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"
224223 "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"
lib/std/c.zig-8
......@@ -5,14 +5,6 @@ const page_size = std.mem.page_size;
55const iovec = std.os.iovec;
66const iovec_const = std.os.iovec_const;
77
8test {
9 _ = tokenizer;
10}
11
12pub const tokenizer = @import("c/tokenizer.zig");
13pub const Token = tokenizer.Token;
14pub const Tokenizer = tokenizer.Tokenizer;
15
168/// The return type is `type` to force comptime function call execution.
179/// TODO: https://github.com/ziglang/zig/issues/425
1810/// If not linking libc, returns struct{pub const ok = false;}
lib/std/c/tokenizer.zig deleted-1585
......@@ -1,1585 +0,0 @@
1const std = @import("std");
2
3pub const Token = struct {
4 id: Id,
5 start: usize,
6 end: usize,
7
8 pub const Id = union(enum) {
9 Invalid,
10 Eof,
11 Nl,
12 Identifier,
13
14 /// special case for #include <...>
15 MacroString,
16 StringLiteral: StrKind,
17 CharLiteral: StrKind,
18 IntegerLiteral: NumSuffix,
19 FloatLiteral: NumSuffix,
20 Bang,
21 BangEqual,
22 Pipe,
23 PipePipe,
24 PipeEqual,
25 Equal,
26 EqualEqual,
27 LParen,
28 RParen,
29 LBrace,
30 RBrace,
31 LBracket,
32 RBracket,
33 Period,
34 Ellipsis,
35 Caret,
36 CaretEqual,
37 Plus,
38 PlusPlus,
39 PlusEqual,
40 Minus,
41 MinusMinus,
42 MinusEqual,
43 Asterisk,
44 AsteriskEqual,
45 Percent,
46 PercentEqual,
47 Arrow,
48 Colon,
49 Semicolon,
50 Slash,
51 SlashEqual,
52 Comma,
53 Ampersand,
54 AmpersandAmpersand,
55 AmpersandEqual,
56 QuestionMark,
57 AngleBracketLeft,
58 AngleBracketLeftEqual,
59 AngleBracketAngleBracketLeft,
60 AngleBracketAngleBracketLeftEqual,
61 AngleBracketRight,
62 AngleBracketRightEqual,
63 AngleBracketAngleBracketRight,
64 AngleBracketAngleBracketRightEqual,
65 Tilde,
66 LineComment,
67 MultiLineComment,
68 Hash,
69 HashHash,
70
71 Keyword_auto,
72 Keyword_break,
73 Keyword_case,
74 Keyword_char,
75 Keyword_const,
76 Keyword_continue,
77 Keyword_default,
78 Keyword_do,
79 Keyword_double,
80 Keyword_else,
81 Keyword_enum,
82 Keyword_extern,
83 Keyword_float,
84 Keyword_for,
85 Keyword_goto,
86 Keyword_if,
87 Keyword_int,
88 Keyword_long,
89 Keyword_register,
90 Keyword_return,
91 Keyword_short,
92 Keyword_signed,
93 Keyword_sizeof,
94 Keyword_static,
95 Keyword_struct,
96 Keyword_switch,
97 Keyword_typedef,
98 Keyword_union,
99 Keyword_unsigned,
100 Keyword_void,
101 Keyword_volatile,
102 Keyword_while,
103
104 // ISO C99
105 Keyword_bool,
106 Keyword_complex,
107 Keyword_imaginary,
108 Keyword_inline,
109 Keyword_restrict,
110
111 // ISO C11
112 Keyword_alignas,
113 Keyword_alignof,
114 Keyword_atomic,
115 Keyword_generic,
116 Keyword_noreturn,
117 Keyword_static_assert,
118 Keyword_thread_local,
119
120 // Preprocessor directives
121 Keyword_include,
122 Keyword_define,
123 Keyword_ifdef,
124 Keyword_ifndef,
125 Keyword_error,
126 Keyword_pragma,
127
128 pub fn symbol(id: Id) []const u8 {
129 return symbolName(id);
130 }
131
132 pub fn symbolName(id: std.meta.Tag(Id)) []const u8 {
133 return switch (id) {
134 .Invalid => "Invalid",
135 .Eof => "Eof",
136 .Nl => "NewLine",
137 .Identifier => "Identifier",
138 .MacroString => "MacroString",
139 .StringLiteral => "StringLiteral",
140 .CharLiteral => "CharLiteral",
141 .IntegerLiteral => "IntegerLiteral",
142 .FloatLiteral => "FloatLiteral",
143 .LineComment => "LineComment",
144 .MultiLineComment => "MultiLineComment",
145
146 .Bang => "!",
147 .BangEqual => "!=",
148 .Pipe => "|",
149 .PipePipe => "||",
150 .PipeEqual => "|=",
151 .Equal => "=",
152 .EqualEqual => "==",
153 .LParen => "(",
154 .RParen => ")",
155 .LBrace => "{",
156 .RBrace => "}",
157 .LBracket => "[",
158 .RBracket => "]",
159 .Period => ".",
160 .Ellipsis => "...",
161 .Caret => "^",
162 .CaretEqual => "^=",
163 .Plus => "+",
164 .PlusPlus => "++",
165 .PlusEqual => "+=",
166 .Minus => "-",
167 .MinusMinus => "--",
168 .MinusEqual => "-=",
169 .Asterisk => "*",
170 .AsteriskEqual => "*=",
171 .Percent => "%",
172 .PercentEqual => "%=",
173 .Arrow => "->",
174 .Colon => ":",
175 .Semicolon => ";",
176 .Slash => "/",
177 .SlashEqual => "/=",
178 .Comma => ",",
179 .Ampersand => "&",
180 .AmpersandAmpersand => "&&",
181 .AmpersandEqual => "&=",
182 .QuestionMark => "?",
183 .AngleBracketLeft => "<",
184 .AngleBracketLeftEqual => "<=",
185 .AngleBracketAngleBracketLeft => "<<",
186 .AngleBracketAngleBracketLeftEqual => "<<=",
187 .AngleBracketRight => ">",
188 .AngleBracketRightEqual => ">=",
189 .AngleBracketAngleBracketRight => ">>",
190 .AngleBracketAngleBracketRightEqual => ">>=",
191 .Tilde => "~",
192 .Hash => "#",
193 .HashHash => "##",
194 .Keyword_auto => "auto",
195 .Keyword_break => "break",
196 .Keyword_case => "case",
197 .Keyword_char => "char",
198 .Keyword_const => "const",
199 .Keyword_continue => "continue",
200 .Keyword_default => "default",
201 .Keyword_do => "do",
202 .Keyword_double => "double",
203 .Keyword_else => "else",
204 .Keyword_enum => "enum",
205 .Keyword_extern => "extern",
206 .Keyword_float => "float",
207 .Keyword_for => "for",
208 .Keyword_goto => "goto",
209 .Keyword_if => "if",
210 .Keyword_int => "int",
211 .Keyword_long => "long",
212 .Keyword_register => "register",
213 .Keyword_return => "return",
214 .Keyword_short => "short",
215 .Keyword_signed => "signed",
216 .Keyword_sizeof => "sizeof",
217 .Keyword_static => "static",
218 .Keyword_struct => "struct",
219 .Keyword_switch => "switch",
220 .Keyword_typedef => "typedef",
221 .Keyword_union => "union",
222 .Keyword_unsigned => "unsigned",
223 .Keyword_void => "void",
224 .Keyword_volatile => "volatile",
225 .Keyword_while => "while",
226 .Keyword_bool => "_Bool",
227 .Keyword_complex => "_Complex",
228 .Keyword_imaginary => "_Imaginary",
229 .Keyword_inline => "inline",
230 .Keyword_restrict => "restrict",
231 .Keyword_alignas => "_Alignas",
232 .Keyword_alignof => "_Alignof",
233 .Keyword_atomic => "_Atomic",
234 .Keyword_generic => "_Generic",
235 .Keyword_noreturn => "_Noreturn",
236 .Keyword_static_assert => "_Static_assert",
237 .Keyword_thread_local => "_Thread_local",
238 .Keyword_include => "include",
239 .Keyword_define => "define",
240 .Keyword_ifdef => "ifdef",
241 .Keyword_ifndef => "ifndef",
242 .Keyword_error => "error",
243 .Keyword_pragma => "pragma",
244 };
245 }
246 };
247
248 // TODO extensions
249 pub const keywords = std.ComptimeStringMap(Id, .{
250 .{ "auto", .Keyword_auto },
251 .{ "break", .Keyword_break },
252 .{ "case", .Keyword_case },
253 .{ "char", .Keyword_char },
254 .{ "const", .Keyword_const },
255 .{ "continue", .Keyword_continue },
256 .{ "default", .Keyword_default },
257 .{ "do", .Keyword_do },
258 .{ "double", .Keyword_double },
259 .{ "else", .Keyword_else },
260 .{ "enum", .Keyword_enum },
261 .{ "extern", .Keyword_extern },
262 .{ "float", .Keyword_float },
263 .{ "for", .Keyword_for },
264 .{ "goto", .Keyword_goto },
265 .{ "if", .Keyword_if },
266 .{ "int", .Keyword_int },
267 .{ "long", .Keyword_long },
268 .{ "register", .Keyword_register },
269 .{ "return", .Keyword_return },
270 .{ "short", .Keyword_short },
271 .{ "signed", .Keyword_signed },
272 .{ "sizeof", .Keyword_sizeof },
273 .{ "static", .Keyword_static },
274 .{ "struct", .Keyword_struct },
275 .{ "switch", .Keyword_switch },
276 .{ "typedef", .Keyword_typedef },
277 .{ "union", .Keyword_union },
278 .{ "unsigned", .Keyword_unsigned },
279 .{ "void", .Keyword_void },
280 .{ "volatile", .Keyword_volatile },
281 .{ "while", .Keyword_while },
282
283 // ISO C99
284 .{ "_Bool", .Keyword_bool },
285 .{ "_Complex", .Keyword_complex },
286 .{ "_Imaginary", .Keyword_imaginary },
287 .{ "inline", .Keyword_inline },
288 .{ "restrict", .Keyword_restrict },
289
290 // ISO C11
291 .{ "_Alignas", .Keyword_alignas },
292 .{ "_Alignof", .Keyword_alignof },
293 .{ "_Atomic", .Keyword_atomic },
294 .{ "_Generic", .Keyword_generic },
295 .{ "_Noreturn", .Keyword_noreturn },
296 .{ "_Static_assert", .Keyword_static_assert },
297 .{ "_Thread_local", .Keyword_thread_local },
298
299 // Preprocessor directives
300 .{ "include", .Keyword_include },
301 .{ "define", .Keyword_define },
302 .{ "ifdef", .Keyword_ifdef },
303 .{ "ifndef", .Keyword_ifndef },
304 .{ "error", .Keyword_error },
305 .{ "pragma", .Keyword_pragma },
306 });
307
308 // TODO do this in the preprocessor
309 pub fn getKeyword(bytes: []const u8, pp_directive: bool) ?Id {
310 if (keywords.get(bytes)) |id| {
311 switch (id) {
312 .Keyword_include,
313 .Keyword_define,
314 .Keyword_ifdef,
315 .Keyword_ifndef,
316 .Keyword_error,
317 .Keyword_pragma,
318 => if (!pp_directive) return null,
319 else => {},
320 }
321 return id;
322 }
323 return null;
324 }
325
326 pub const NumSuffix = enum {
327 none,
328 f,
329 l,
330 u,
331 lu,
332 ll,
333 llu,
334 };
335
336 pub const StrKind = enum {
337 none,
338 wide,
339 utf_8,
340 utf_16,
341 utf_32,
342 };
343};
344
345pub const Tokenizer = struct {
346 buffer: []const u8,
347 index: usize = 0,
348 prev_tok_id: std.meta.Tag(Token.Id) = .Invalid,
349 pp_directive: bool = false,
350
351 pub fn next(self: *Tokenizer) Token {
352 var result = Token{
353 .id = .Eof,
354 .start = self.index,
355 .end = undefined,
356 };
357 var state: enum {
358 Start,
359 Cr,
360 BackSlash,
361 BackSlashCr,
362 u,
363 u8,
364 U,
365 L,
366 StringLiteral,
367 CharLiteralStart,
368 CharLiteral,
369 EscapeSequence,
370 CrEscape,
371 OctalEscape,
372 HexEscape,
373 UnicodeEscape,
374 Identifier,
375 Equal,
376 Bang,
377 Pipe,
378 Percent,
379 Asterisk,
380 Plus,
381
382 /// special case for #include <...>
383 MacroString,
384 AngleBracketLeft,
385 AngleBracketAngleBracketLeft,
386 AngleBracketRight,
387 AngleBracketAngleBracketRight,
388 Caret,
389 Period,
390 Period2,
391 Minus,
392 Slash,
393 Ampersand,
394 Hash,
395 LineComment,
396 MultiLineComment,
397 MultiLineCommentAsterisk,
398 Zero,
399 IntegerLiteralOct,
400 IntegerLiteralBinary,
401 IntegerLiteralBinaryFirst,
402 IntegerLiteralHex,
403 IntegerLiteralHexFirst,
404 IntegerLiteral,
405 IntegerSuffix,
406 IntegerSuffixU,
407 IntegerSuffixL,
408 IntegerSuffixLL,
409 IntegerSuffixUL,
410 FloatFraction,
411 FloatFractionHex,
412 FloatExponent,
413 FloatExponentDigits,
414 FloatSuffix,
415 } = .Start;
416 var string = false;
417 var counter: u32 = 0;
418 while (self.index < self.buffer.len) : (self.index += 1) {
419 const c = self.buffer[self.index];
420 switch (state) {
421 .Start => switch (c) {
422 '\n' => {
423 self.pp_directive = false;
424 result.id = .Nl;
425 self.index += 1;
426 break;
427 },
428 '\r' => {
429 state = .Cr;
430 },
431 '"' => {
432 result.id = .{ .StringLiteral = .none };
433 state = .StringLiteral;
434 },
435 '\'' => {
436 result.id = .{ .CharLiteral = .none };
437 state = .CharLiteralStart;
438 },
439 'u' => {
440 state = .u;
441 },
442 'U' => {
443 state = .U;
444 },
445 'L' => {
446 state = .L;
447 },
448 'a'...'t', 'v'...'z', 'A'...'K', 'M'...'T', 'V'...'Z', '_', '$' => {
449 state = .Identifier;
450 },
451 '=' => {
452 state = .Equal;
453 },
454 '!' => {
455 state = .Bang;
456 },
457 '|' => {
458 state = .Pipe;
459 },
460 '(' => {
461 result.id = .LParen;
462 self.index += 1;
463 break;
464 },
465 ')' => {
466 result.id = .RParen;
467 self.index += 1;
468 break;
469 },
470 '[' => {
471 result.id = .LBracket;
472 self.index += 1;
473 break;
474 },
475 ']' => {
476 result.id = .RBracket;
477 self.index += 1;
478 break;
479 },
480 ';' => {
481 result.id = .Semicolon;
482 self.index += 1;
483 break;
484 },
485 ',' => {
486 result.id = .Comma;
487 self.index += 1;
488 break;
489 },
490 '?' => {
491 result.id = .QuestionMark;
492 self.index += 1;
493 break;
494 },
495 ':' => {
496 result.id = .Colon;
497 self.index += 1;
498 break;
499 },
500 '%' => {
501 state = .Percent;
502 },
503 '*' => {
504 state = .Asterisk;
505 },
506 '+' => {
507 state = .Plus;
508 },
509 '<' => {
510 if (self.prev_tok_id == .Keyword_include)
511 state = .MacroString
512 else
513 state = .AngleBracketLeft;
514 },
515 '>' => {
516 state = .AngleBracketRight;
517 },
518 '^' => {
519 state = .Caret;
520 },
521 '{' => {
522 result.id = .LBrace;
523 self.index += 1;
524 break;
525 },
526 '}' => {
527 result.id = .RBrace;
528 self.index += 1;
529 break;
530 },
531 '~' => {
532 result.id = .Tilde;
533 self.index += 1;
534 break;
535 },
536 '.' => {
537 state = .Period;
538 },
539 '-' => {
540 state = .Minus;
541 },
542 '/' => {
543 state = .Slash;
544 },
545 '&' => {
546 state = .Ampersand;
547 },
548 '#' => {
549 state = .Hash;
550 },
551 '0' => {
552 state = .Zero;
553 },
554 '1'...'9' => {
555 state = .IntegerLiteral;
556 },
557 '\\' => {
558 state = .BackSlash;
559 },
560 '\t', '\x0B', '\x0C', ' ' => {
561 result.start = self.index + 1;
562 },
563 else => {
564 // TODO handle invalid bytes better
565 result.id = .Invalid;
566 self.index += 1;
567 break;
568 },
569 },
570 .Cr => switch (c) {
571 '\n' => {
572 self.pp_directive = false;
573 result.id = .Nl;
574 self.index += 1;
575 break;
576 },
577 else => {
578 result.id = .Invalid;
579 break;
580 },
581 },
582 .BackSlash => switch (c) {
583 '\n' => {
584 result.start = self.index + 1;
585 state = .Start;
586 },
587 '\r' => {
588 state = .BackSlashCr;
589 },
590 '\t', '\x0B', '\x0C', ' ' => {
591 // TODO warn
592 },
593 else => {
594 result.id = .Invalid;
595 break;
596 },
597 },
598 .BackSlashCr => switch (c) {
599 '\n' => {
600 result.start = self.index + 1;
601 state = .Start;
602 },
603 else => {
604 result.id = .Invalid;
605 break;
606 },
607 },
608 .u => switch (c) {
609 '8' => {
610 state = .u8;
611 },
612 '\'' => {
613 result.id = .{ .CharLiteral = .utf_16 };
614 state = .CharLiteralStart;
615 },
616 '\"' => {
617 result.id = .{ .StringLiteral = .utf_16 };
618 state = .StringLiteral;
619 },
620 else => {
621 self.index -= 1;
622 state = .Identifier;
623 },
624 },
625 .u8 => switch (c) {
626 '\"' => {
627 result.id = .{ .StringLiteral = .utf_8 };
628 state = .StringLiteral;
629 },
630 else => {
631 self.index -= 1;
632 state = .Identifier;
633 },
634 },
635 .U => switch (c) {
636 '\'' => {
637 result.id = .{ .CharLiteral = .utf_32 };
638 state = .CharLiteralStart;
639 },
640 '\"' => {
641 result.id = .{ .StringLiteral = .utf_32 };
642 state = .StringLiteral;
643 },
644 else => {
645 self.index -= 1;
646 state = .Identifier;
647 },
648 },
649 .L => switch (c) {
650 '\'' => {
651 result.id = .{ .CharLiteral = .wide };
652 state = .CharLiteralStart;
653 },
654 '\"' => {
655 result.id = .{ .StringLiteral = .wide };
656 state = .StringLiteral;
657 },
658 else => {
659 self.index -= 1;
660 state = .Identifier;
661 },
662 },
663 .StringLiteral => switch (c) {
664 '\\' => {
665 string = true;
666 state = .EscapeSequence;
667 },
668 '"' => {
669 self.index += 1;
670 break;
671 },
672 '\n', '\r' => {
673 result.id = .Invalid;
674 break;
675 },
676 else => {},
677 },
678 .CharLiteralStart => switch (c) {
679 '\\' => {
680 string = false;
681 state = .EscapeSequence;
682 },
683 '\'', '\n' => {
684 result.id = .Invalid;
685 break;
686 },
687 else => {
688 state = .CharLiteral;
689 },
690 },
691 .CharLiteral => switch (c) {
692 '\\' => {
693 string = false;
694 state = .EscapeSequence;
695 },
696 '\'' => {
697 self.index += 1;
698 break;
699 },
700 '\n' => {
701 result.id = .Invalid;
702 break;
703 },
704 else => {},
705 },
706 .EscapeSequence => switch (c) {
707 '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v', '\n' => {
708 state = if (string) .StringLiteral else .CharLiteral;
709 },
710 '\r' => {
711 state = .CrEscape;
712 },
713 '0'...'7' => {
714 counter = 1;
715 state = .OctalEscape;
716 },
717 'x' => {
718 state = .HexEscape;
719 },
720 'u' => {
721 counter = 4;
722 state = .OctalEscape;
723 },
724 'U' => {
725 counter = 8;
726 state = .OctalEscape;
727 },
728 else => {
729 result.id = .Invalid;
730 break;
731 },
732 },
733 .CrEscape => switch (c) {
734 '\n' => {
735 state = if (string) .StringLiteral else .CharLiteral;
736 },
737 else => {
738 result.id = .Invalid;
739 break;
740 },
741 },
742 .OctalEscape => switch (c) {
743 '0'...'7' => {
744 counter += 1;
745 if (counter == 3) {
746 state = if (string) .StringLiteral else .CharLiteral;
747 }
748 },
749 else => {
750 self.index -= 1;
751 state = if (string) .StringLiteral else .CharLiteral;
752 },
753 },
754 .HexEscape => switch (c) {
755 '0'...'9', 'a'...'f', 'A'...'F' => {},
756 else => {
757 self.index -= 1;
758 state = if (string) .StringLiteral else .CharLiteral;
759 },
760 },
761 .UnicodeEscape => switch (c) {
762 '0'...'9', 'a'...'f', 'A'...'F' => {
763 counter -= 1;
764 if (counter == 0) {
765 state = if (string) .StringLiteral else .CharLiteral;
766 }
767 },
768 else => {
769 if (counter != 0) {
770 result.id = .Invalid;
771 break;
772 }
773 self.index -= 1;
774 state = if (string) .StringLiteral else .CharLiteral;
775 },
776 },
777 .Identifier => switch (c) {
778 'a'...'z', 'A'...'Z', '_', '0'...'9', '$' => {},
779 else => {
780 result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier;
781 if (self.prev_tok_id == .Hash)
782 self.pp_directive = true;
783 break;
784 },
785 },
786 .Equal => switch (c) {
787 '=' => {
788 result.id = .EqualEqual;
789 self.index += 1;
790 break;
791 },
792 else => {
793 result.id = .Equal;
794 break;
795 },
796 },
797 .Bang => switch (c) {
798 '=' => {
799 result.id = .BangEqual;
800 self.index += 1;
801 break;
802 },
803 else => {
804 result.id = .Bang;
805 break;
806 },
807 },
808 .Pipe => switch (c) {
809 '=' => {
810 result.id = .PipeEqual;
811 self.index += 1;
812 break;
813 },
814 '|' => {
815 result.id = .PipePipe;
816 self.index += 1;
817 break;
818 },
819 else => {
820 result.id = .Pipe;
821 break;
822 },
823 },
824 .Percent => switch (c) {
825 '=' => {
826 result.id = .PercentEqual;
827 self.index += 1;
828 break;
829 },
830 else => {
831 result.id = .Percent;
832 break;
833 },
834 },
835 .Asterisk => switch (c) {
836 '=' => {
837 result.id = .AsteriskEqual;
838 self.index += 1;
839 break;
840 },
841 else => {
842 result.id = .Asterisk;
843 break;
844 },
845 },
846 .Plus => switch (c) {
847 '=' => {
848 result.id = .PlusEqual;
849 self.index += 1;
850 break;
851 },
852 '+' => {
853 result.id = .PlusPlus;
854 self.index += 1;
855 break;
856 },
857 else => {
858 result.id = .Plus;
859 break;
860 },
861 },
862 .MacroString => switch (c) {
863 '>' => {
864 result.id = .MacroString;
865 self.index += 1;
866 break;
867 },
868 else => {},
869 },
870 .AngleBracketLeft => switch (c) {
871 '<' => {
872 state = .AngleBracketAngleBracketLeft;
873 },
874 '=' => {
875 result.id = .AngleBracketLeftEqual;
876 self.index += 1;
877 break;
878 },
879 else => {
880 result.id = .AngleBracketLeft;
881 break;
882 },
883 },
884 .AngleBracketAngleBracketLeft => switch (c) {
885 '=' => {
886 result.id = .AngleBracketAngleBracketLeftEqual;
887 self.index += 1;
888 break;
889 },
890 else => {
891 result.id = .AngleBracketAngleBracketLeft;
892 break;
893 },
894 },
895 .AngleBracketRight => switch (c) {
896 '>' => {
897 state = .AngleBracketAngleBracketRight;
898 },
899 '=' => {
900 result.id = .AngleBracketRightEqual;
901 self.index += 1;
902 break;
903 },
904 else => {
905 result.id = .AngleBracketRight;
906 break;
907 },
908 },
909 .AngleBracketAngleBracketRight => switch (c) {
910 '=' => {
911 result.id = .AngleBracketAngleBracketRightEqual;
912 self.index += 1;
913 break;
914 },
915 else => {
916 result.id = .AngleBracketAngleBracketRight;
917 break;
918 },
919 },
920 .Caret => switch (c) {
921 '=' => {
922 result.id = .CaretEqual;
923 self.index += 1;
924 break;
925 },
926 else => {
927 result.id = .Caret;
928 break;
929 },
930 },
931 .Period => switch (c) {
932 '.' => {
933 state = .Period2;
934 },
935 '0'...'9' => {
936 state = .FloatFraction;
937 },
938 else => {
939 result.id = .Period;
940 break;
941 },
942 },
943 .Period2 => switch (c) {
944 '.' => {
945 result.id = .Ellipsis;
946 self.index += 1;
947 break;
948 },
949 else => {
950 result.id = .Period;
951 self.index -= 1;
952 break;
953 },
954 },
955 .Minus => switch (c) {
956 '>' => {
957 result.id = .Arrow;
958 self.index += 1;
959 break;
960 },
961 '=' => {
962 result.id = .MinusEqual;
963 self.index += 1;
964 break;
965 },
966 '-' => {
967 result.id = .MinusMinus;
968 self.index += 1;
969 break;
970 },
971 else => {
972 result.id = .Minus;
973 break;
974 },
975 },
976 .Slash => switch (c) {
977 '/' => {
978 state = .LineComment;
979 },
980 '*' => {
981 state = .MultiLineComment;
982 },
983 '=' => {
984 result.id = .SlashEqual;
985 self.index += 1;
986 break;
987 },
988 else => {
989 result.id = .Slash;
990 break;
991 },
992 },
993 .Ampersand => switch (c) {
994 '&' => {
995 result.id = .AmpersandAmpersand;
996 self.index += 1;
997 break;
998 },
999 '=' => {
1000 result.id = .AmpersandEqual;
1001 self.index += 1;
1002 break;
1003 },
1004 else => {
1005 result.id = .Ampersand;
1006 break;
1007 },
1008 },
1009 .Hash => switch (c) {
1010 '#' => {
1011 result.id = .HashHash;
1012 self.index += 1;
1013 break;
1014 },
1015 else => {
1016 result.id = .Hash;
1017 break;
1018 },
1019 },
1020 .LineComment => switch (c) {
1021 '\n' => {
1022 result.id = .LineComment;
1023 break;
1024 },
1025 else => {},
1026 },
1027 .MultiLineComment => switch (c) {
1028 '*' => {
1029 state = .MultiLineCommentAsterisk;
1030 },
1031 else => {},
1032 },
1033 .MultiLineCommentAsterisk => switch (c) {
1034 '/' => {
1035 result.id = .MultiLineComment;
1036 self.index += 1;
1037 break;
1038 },
1039 else => {
1040 state = .MultiLineComment;
1041 },
1042 },
1043 .Zero => switch (c) {
1044 '0'...'9' => {
1045 state = .IntegerLiteralOct;
1046 },
1047 'b', 'B' => {
1048 state = .IntegerLiteralBinaryFirst;
1049 },
1050 'x', 'X' => {
1051 state = .IntegerLiteralHexFirst;
1052 },
1053 '.' => {
1054 state = .FloatFraction;
1055 },
1056 else => {
1057 state = .IntegerSuffix;
1058 self.index -= 1;
1059 },
1060 },
1061 .IntegerLiteralOct => switch (c) {
1062 '0'...'7' => {},
1063 else => {
1064 state = .IntegerSuffix;
1065 self.index -= 1;
1066 },
1067 },
1068 .IntegerLiteralBinaryFirst => switch (c) {
1069 '0'...'7' => state = .IntegerLiteralBinary,
1070 else => {
1071 result.id = .Invalid;
1072 break;
1073 },
1074 },
1075 .IntegerLiteralBinary => switch (c) {
1076 '0', '1' => {},
1077 else => {
1078 state = .IntegerSuffix;
1079 self.index -= 1;
1080 },
1081 },
1082 .IntegerLiteralHexFirst => switch (c) {
1083 '0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex,
1084 '.' => {
1085 state = .FloatFractionHex;
1086 },
1087 'p', 'P' => {
1088 state = .FloatExponent;
1089 },
1090 else => {
1091 result.id = .Invalid;
1092 break;
1093 },
1094 },
1095 .IntegerLiteralHex => switch (c) {
1096 '0'...'9', 'a'...'f', 'A'...'F' => {},
1097 '.' => {
1098 state = .FloatFractionHex;
1099 },
1100 'p', 'P' => {
1101 state = .FloatExponent;
1102 },
1103 else => {
1104 state = .IntegerSuffix;
1105 self.index -= 1;
1106 },
1107 },
1108 .IntegerLiteral => switch (c) {
1109 '0'...'9' => {},
1110 '.' => {
1111 state = .FloatFraction;
1112 },
1113 'e', 'E' => {
1114 state = .FloatExponent;
1115 },
1116 else => {
1117 state = .IntegerSuffix;
1118 self.index -= 1;
1119 },
1120 },
1121 .IntegerSuffix => switch (c) {
1122 'u', 'U' => {
1123 state = .IntegerSuffixU;
1124 },
1125 'l', 'L' => {
1126 state = .IntegerSuffixL;
1127 },
1128 else => {
1129 result.id = .{ .IntegerLiteral = .none };
1130 break;
1131 },
1132 },
1133 .IntegerSuffixU => switch (c) {
1134 'l', 'L' => {
1135 state = .IntegerSuffixUL;
1136 },
1137 else => {
1138 result.id = .{ .IntegerLiteral = .u };
1139 break;
1140 },
1141 },
1142 .IntegerSuffixL => switch (c) {
1143 'l', 'L' => {
1144 state = .IntegerSuffixLL;
1145 },
1146 'u', 'U' => {
1147 result.id = .{ .IntegerLiteral = .lu };
1148 self.index += 1;
1149 break;
1150 },
1151 else => {
1152 result.id = .{ .IntegerLiteral = .l };
1153 break;
1154 },
1155 },
1156 .IntegerSuffixLL => switch (c) {
1157 'u', 'U' => {
1158 result.id = .{ .IntegerLiteral = .llu };
1159 self.index += 1;
1160 break;
1161 },
1162 else => {
1163 result.id = .{ .IntegerLiteral = .ll };
1164 break;
1165 },
1166 },
1167 .IntegerSuffixUL => switch (c) {
1168 'l', 'L' => {
1169 result.id = .{ .IntegerLiteral = .llu };
1170 self.index += 1;
1171 break;
1172 },
1173 else => {
1174 result.id = .{ .IntegerLiteral = .lu };
1175 break;
1176 },
1177 },
1178 .FloatFraction => switch (c) {
1179 '0'...'9' => {},
1180 'e', 'E' => {
1181 state = .FloatExponent;
1182 },
1183 else => {
1184 self.index -= 1;
1185 state = .FloatSuffix;
1186 },
1187 },
1188 .FloatFractionHex => switch (c) {
1189 '0'...'9', 'a'...'f', 'A'...'F' => {},
1190 'p', 'P' => {
1191 state = .FloatExponent;
1192 },
1193 else => {
1194 result.id = .Invalid;
1195 break;
1196 },
1197 },
1198 .FloatExponent => switch (c) {
1199 '+', '-' => {
1200 state = .FloatExponentDigits;
1201 },
1202 else => {
1203 self.index -= 1;
1204 state = .FloatExponentDigits;
1205 },
1206 },
1207 .FloatExponentDigits => switch (c) {
1208 '0'...'9' => {
1209 counter += 1;
1210 },
1211 else => {
1212 if (counter == 0) {
1213 result.id = .Invalid;
1214 break;
1215 }
1216 self.index -= 1;
1217 state = .FloatSuffix;
1218 },
1219 },
1220 .FloatSuffix => switch (c) {
1221 'l', 'L' => {
1222 result.id = .{ .FloatLiteral = .l };
1223 self.index += 1;
1224 break;
1225 },
1226 'f', 'F' => {
1227 result.id = .{ .FloatLiteral = .f };
1228 self.index += 1;
1229 break;
1230 },
1231 else => {
1232 result.id = .{ .FloatLiteral = .none };
1233 break;
1234 },
1235 },
1236 }
1237 } else if (self.index == self.buffer.len) {
1238 switch (state) {
1239 .Start => {},
1240 .u, .u8, .U, .L, .Identifier => {
1241 result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier;
1242 },
1243
1244 .Cr,
1245 .BackSlash,
1246 .BackSlashCr,
1247 .Period2,
1248 .StringLiteral,
1249 .CharLiteralStart,
1250 .CharLiteral,
1251 .EscapeSequence,
1252 .CrEscape,
1253 .OctalEscape,
1254 .HexEscape,
1255 .UnicodeEscape,
1256 .MultiLineComment,
1257 .MultiLineCommentAsterisk,
1258 .FloatExponent,
1259 .MacroString,
1260 .IntegerLiteralBinaryFirst,
1261 .IntegerLiteralHexFirst,
1262 => result.id = .Invalid,
1263
1264 .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none },
1265
1266 .FloatFraction,
1267 .FloatFractionHex,
1268 => result.id = .{ .FloatLiteral = .none },
1269
1270 .IntegerLiteralOct,
1271 .IntegerLiteralBinary,
1272 .IntegerLiteralHex,
1273 .IntegerLiteral,
1274 .IntegerSuffix,
1275 .Zero,
1276 => result.id = .{ .IntegerLiteral = .none },
1277 .IntegerSuffixU => result.id = .{ .IntegerLiteral = .u },
1278 .IntegerSuffixL => result.id = .{ .IntegerLiteral = .l },
1279 .IntegerSuffixLL => result.id = .{ .IntegerLiteral = .ll },
1280 .IntegerSuffixUL => result.id = .{ .IntegerLiteral = .lu },
1281
1282 .FloatSuffix => result.id = .{ .FloatLiteral = .none },
1283 .Equal => result.id = .Equal,
1284 .Bang => result.id = .Bang,
1285 .Minus => result.id = .Minus,
1286 .Slash => result.id = .Slash,
1287 .Ampersand => result.id = .Ampersand,
1288 .Hash => result.id = .Hash,
1289 .Period => result.id = .Period,
1290 .Pipe => result.id = .Pipe,
1291 .AngleBracketAngleBracketRight => result.id = .AngleBracketAngleBracketRight,
1292 .AngleBracketRight => result.id = .AngleBracketRight,
1293 .AngleBracketAngleBracketLeft => result.id = .AngleBracketAngleBracketLeft,
1294 .AngleBracketLeft => result.id = .AngleBracketLeft,
1295 .Plus => result.id = .Plus,
1296 .Percent => result.id = .Percent,
1297 .Caret => result.id = .Caret,
1298 .Asterisk => result.id = .Asterisk,
1299 .LineComment => result.id = .LineComment,
1300 }
1301 }
1302
1303 self.prev_tok_id = result.id;
1304 result.end = self.index;
1305 return result;
1306 }
1307};
1308
1309test "operators" {
1310 try expectTokens(
1311 \\ ! != | || |= = ==
1312 \\ ( ) { } [ ] . .. ...
1313 \\ ^ ^= + ++ += - -- -=
1314 \\ * *= % %= -> : ; / /=
1315 \\ , & && &= ? < <= <<
1316 \\ <<= > >= >> >>= ~ # ##
1317 \\
1318 , &[_]Token.Id{
1319 .Bang,
1320 .BangEqual,
1321 .Pipe,
1322 .PipePipe,
1323 .PipeEqual,
1324 .Equal,
1325 .EqualEqual,
1326 .Nl,
1327 .LParen,
1328 .RParen,
1329 .LBrace,
1330 .RBrace,
1331 .LBracket,
1332 .RBracket,
1333 .Period,
1334 .Period,
1335 .Period,
1336 .Ellipsis,
1337 .Nl,
1338 .Caret,
1339 .CaretEqual,
1340 .Plus,
1341 .PlusPlus,
1342 .PlusEqual,
1343 .Minus,
1344 .MinusMinus,
1345 .MinusEqual,
1346 .Nl,
1347 .Asterisk,
1348 .AsteriskEqual,
1349 .Percent,
1350 .PercentEqual,
1351 .Arrow,
1352 .Colon,
1353 .Semicolon,
1354 .Slash,
1355 .SlashEqual,
1356 .Nl,
1357 .Comma,
1358 .Ampersand,
1359 .AmpersandAmpersand,
1360 .AmpersandEqual,
1361 .QuestionMark,
1362 .AngleBracketLeft,
1363 .AngleBracketLeftEqual,
1364 .AngleBracketAngleBracketLeft,
1365 .Nl,
1366 .AngleBracketAngleBracketLeftEqual,
1367 .AngleBracketRight,
1368 .AngleBracketRightEqual,
1369 .AngleBracketAngleBracketRight,
1370 .AngleBracketAngleBracketRightEqual,
1371 .Tilde,
1372 .Hash,
1373 .HashHash,
1374 .Nl,
1375 });
1376}
1377
1378test "keywords" {
1379 try expectTokens(
1380 \\auto break case char const continue default do
1381 \\double else enum extern float for goto if int
1382 \\long register return short signed sizeof static
1383 \\struct switch typedef union unsigned void volatile
1384 \\while _Bool _Complex _Imaginary inline restrict _Alignas
1385 \\_Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local
1386 \\
1387 , &[_]Token.Id{
1388 .Keyword_auto,
1389 .Keyword_break,
1390 .Keyword_case,
1391 .Keyword_char,
1392 .Keyword_const,
1393 .Keyword_continue,
1394 .Keyword_default,
1395 .Keyword_do,
1396 .Nl,
1397 .Keyword_double,
1398 .Keyword_else,
1399 .Keyword_enum,
1400 .Keyword_extern,
1401 .Keyword_float,
1402 .Keyword_for,
1403 .Keyword_goto,
1404 .Keyword_if,
1405 .Keyword_int,
1406 .Nl,
1407 .Keyword_long,
1408 .Keyword_register,
1409 .Keyword_return,
1410 .Keyword_short,
1411 .Keyword_signed,
1412 .Keyword_sizeof,
1413 .Keyword_static,
1414 .Nl,
1415 .Keyword_struct,
1416 .Keyword_switch,
1417 .Keyword_typedef,
1418 .Keyword_union,
1419 .Keyword_unsigned,
1420 .Keyword_void,
1421 .Keyword_volatile,
1422 .Nl,
1423 .Keyword_while,
1424 .Keyword_bool,
1425 .Keyword_complex,
1426 .Keyword_imaginary,
1427 .Keyword_inline,
1428 .Keyword_restrict,
1429 .Keyword_alignas,
1430 .Nl,
1431 .Keyword_alignof,
1432 .Keyword_atomic,
1433 .Keyword_generic,
1434 .Keyword_noreturn,
1435 .Keyword_static_assert,
1436 .Keyword_thread_local,
1437 .Nl,
1438 });
1439}
1440
1441test "preprocessor keywords" {
1442 try expectTokens(
1443 \\#include <test>
1444 \\#define #include <1
1445 \\#ifdef
1446 \\#ifndef
1447 \\#error
1448 \\#pragma
1449 \\
1450 , &[_]Token.Id{
1451 .Hash,
1452 .Keyword_include,
1453 .MacroString,
1454 .Nl,
1455 .Hash,
1456 .Keyword_define,
1457 .Hash,
1458 .Identifier,
1459 .AngleBracketLeft,
1460 .{ .IntegerLiteral = .none },
1461 .Nl,
1462 .Hash,
1463 .Keyword_ifdef,
1464 .Nl,
1465 .Hash,
1466 .Keyword_ifndef,
1467 .Nl,
1468 .Hash,
1469 .Keyword_error,
1470 .Nl,
1471 .Hash,
1472 .Keyword_pragma,
1473 .Nl,
1474 });
1475}
1476
1477test "line continuation" {
1478 try expectTokens(
1479 \\#define foo \
1480 \\ bar
1481 \\"foo\
1482 \\ bar"
1483 \\#define "foo"
1484 \\ "bar"
1485 \\#define "foo" \
1486 \\ "bar"
1487 , &[_]Token.Id{
1488 .Hash,
1489 .Keyword_define,
1490 .Identifier,
1491 .Identifier,
1492 .Nl,
1493 .{ .StringLiteral = .none },
1494 .Nl,
1495 .Hash,
1496 .Keyword_define,
1497 .{ .StringLiteral = .none },
1498 .Nl,
1499 .{ .StringLiteral = .none },
1500 .Nl,
1501 .Hash,
1502 .Keyword_define,
1503 .{ .StringLiteral = .none },
1504 .{ .StringLiteral = .none },
1505 });
1506}
1507
1508test "string prefix" {
1509 try expectTokens(
1510 \\"foo"
1511 \\u"foo"
1512 \\u8"foo"
1513 \\U"foo"
1514 \\L"foo"
1515 \\'foo'
1516 \\u'foo'
1517 \\U'foo'
1518 \\L'foo'
1519 \\
1520 , &[_]Token.Id{
1521 .{ .StringLiteral = .none },
1522 .Nl,
1523 .{ .StringLiteral = .utf_16 },
1524 .Nl,
1525 .{ .StringLiteral = .utf_8 },
1526 .Nl,
1527 .{ .StringLiteral = .utf_32 },
1528 .Nl,
1529 .{ .StringLiteral = .wide },
1530 .Nl,
1531 .{ .CharLiteral = .none },
1532 .Nl,
1533 .{ .CharLiteral = .utf_16 },
1534 .Nl,
1535 .{ .CharLiteral = .utf_32 },
1536 .Nl,
1537 .{ .CharLiteral = .wide },
1538 .Nl,
1539 });
1540}
1541
1542test "num suffixes" {
1543 try expectTokens(
1544 \\ 1.0f 1.0L 1.0 .0 1.
1545 \\ 0l 0lu 0ll 0llu 0
1546 \\ 1u 1ul 1ull 1
1547 \\ 0x 0b
1548 \\
1549 , &[_]Token.Id{
1550 .{ .FloatLiteral = .f },
1551 .{ .FloatLiteral = .l },
1552 .{ .FloatLiteral = .none },
1553 .{ .FloatLiteral = .none },
1554 .{ .FloatLiteral = .none },
1555 .Nl,
1556 .{ .IntegerLiteral = .l },
1557 .{ .IntegerLiteral = .lu },
1558 .{ .IntegerLiteral = .ll },
1559 .{ .IntegerLiteral = .llu },
1560 .{ .IntegerLiteral = .none },
1561 .Nl,
1562 .{ .IntegerLiteral = .u },
1563 .{ .IntegerLiteral = .lu },
1564 .{ .IntegerLiteral = .llu },
1565 .{ .IntegerLiteral = .none },
1566 .Nl,
1567 .Invalid,
1568 .Invalid,
1569 .Nl,
1570 });
1571}
1572
1573fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) !void {
1574 var tokenizer = Tokenizer{
1575 .buffer = source,
1576 };
1577 for (expected_tokens) |expected_token_id| {
1578 const token = tokenizer.next();
1579 if (!std.meta.eql(token.id, expected_token_id)) {
1580 std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
1581 }
1582 }
1583 const last_token = tokenizer.next();
1584 try std.testing.expect(last_token.id == .Eof);
1585}
lib/std/zig/c_translation.zig+3-3
......@@ -252,7 +252,7 @@ test "sizeof" {
252252 try testing.expect(sizeof(anyopaque) == 1);
253253}
254254
255pub const CIntLiteralBase = enum { decimal, octal, hexadecimal };
255pub const CIntLiteralBase = enum { decimal, octal, hex };
256256
257257/// Deprecated: use `CIntLiteralBase`
258258pub const CIntLiteralRadix = CIntLiteralBase;
......@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(
289289}
290290
291291test "promoteIntLiteral" {
292 const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal);
292 const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hex);
293293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));
294294
295295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;
296296
297297 const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal);
298 const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal);
298 const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hex);
299299
300300 if (math.maxInt(c_long) > math.maxInt(c_int)) {
301301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));
src/Compilation.zig+1-1
......@@ -4194,7 +4194,7 @@ pub const CImportResult = struct {
41944194/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
41954195/// a bit when we want to start using it from self-hosted.
41964196pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
4197 if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping
4197 if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build");
41984198 const tracy_trace = trace(@src());
41994199 defer tracy_trace.end();
42004200
src/main.zig+1-1
......@@ -4286,7 +4286,7 @@ fn updateModule(comp: *Compilation) !void {
42864286}
42874287
42884288fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {
4289 if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping
4289 if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build");
42904290 assert(comp.c_source_files.len == 1);
42914291 const c_source_file = comp.c_source_files[0];
42924292
src/stubs/aro_builtins.zig+3-1
......@@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type {
2222 return .{};
2323 }
2424 pub fn tagFromName(name: []const u8) ?Tag {
25 return @enumFromInt(name.len);
25 var res: u16 = 0;
26 for (name) |c| res +%= c;
27 return @enumFromInt(res);
2628 }
2729 pub const NameBuf = struct {
2830 pub fn span(_: *const NameBuf) []const u8 {
src/translate_c.zig+305-261
......@@ -1,13 +1,13 @@
11const std = @import("std");
22const testing = std.testing;
33const assert = std.debug.assert;
4const clang = @import("clang.zig");
5const ctok = std.c.tokenizer;
6const CToken = std.c.Token;
74const mem = std.mem;
85const math = std.math;
96const meta = std.meta;
107const CallingConvention = std.builtin.CallingConvention;
8const clang = @import("clang.zig");
9const aro = @import("aro");
10const CToken = aro.Tokenizer.Token;
1111const ast = @import("translate_c/ast.zig");
1212const Node = ast.Node;
1313const Tag = Node.Tag;
......@@ -190,19 +190,21 @@ pub fn translate(
190190
191191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
192192/// Macros of this form will not be translated.
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {
194 const source = getMacroText(unit, c, macro);
195 var tokenizer = std.c.Tokenizer{
196 .buffer = source,
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool {
194 const source = try getMacroText(unit, c, macro);
195 var tokenizer: aro.Tokenizer = .{
196 .buf = source,
197 .source = .unused,
198 .langopts = .{},
197199 };
198 const name_tok = tokenizer.next();
200 const name_tok = tokenizer.nextNoWS();
199201 const name = source[name_tok.start..name_tok.end];
200202
201 const first_tok = tokenizer.next();
203 const first_tok = tokenizer.nextNoWS();
202204 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
203205 // the tokenizer.
204206 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)
205 if (first_tok.id == .Eof) return false;
207 if (first_tok.id == .eof) return false;
206208 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
207209}
208210
......@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
223225 const raw_name = macro.getName_getNameStart();
224226 const name = try c.str(raw_name);
225227
226 if (!isSelfDefinedMacro(ast_unit, c, macro)) {
228 if (!try isSelfDefinedMacro(ast_unit, c, macro)) {
227229 try c.global_names.put(c.gpa, name, {});
228230 }
229231 },
......@@ -5159,16 +5161,16 @@ pub const PatternList = struct {
51595161 /// Assumes that `ms` represents a tokenized function-like macro.
51605162 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {
51615163 assert(ms.tokens.len > 2);
5162 assert(ms.tokens[0].id == .Identifier);
5163 assert(ms.tokens[1].id == .LParen);
5164 assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier);
5165 assert(ms.tokens[1].id == .l_paren);
51645166
51655167 var i: usize = 2;
51665168 while (true) : (i += 1) {
51675169 const token = ms.tokens[i];
51685170 switch (token.id) {
5169 .RParen => break,
5170 .Comma => continue,
5171 .Identifier => {
5171 .r_paren => break,
5172 .comma => continue,
5173 .identifier, .extended_identifier => {
51725174 const identifier = ms.slice(token);
51735175 try hash.put(allocator, identifier, i);
51745176 },
......@@ -5220,18 +5222,18 @@ pub const PatternList = struct {
52205222 if (args_hash.count() != self.args_hash.count()) return false;
52215223
52225224 var i: usize = 2;
5223 while (self.tokens[i].id != .RParen) : (i += 1) {}
5225 while (self.tokens[i].id != .r_paren) : (i += 1) {}
52245226
52255227 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };
52265228 while (i < self.tokens.len) : (i += 1) {
52275229 const pattern_token = self.tokens[i];
52285230 const macro_token = ms.tokens[i];
5229 if (meta.activeTag(pattern_token.id) != meta.activeTag(macro_token.id)) return false;
5231 if (pattern_token.id != macro_token.id) return false;
52305232
52315233 const pattern_bytes = pattern_slicer.slice(pattern_token);
52325234 const macro_bytes = ms.slice(macro_token);
52335235 switch (pattern_token.id) {
5234 .Identifier => {
5236 .identifier, .extended_identifier => {
52355237 const pattern_arg_index = self.args_hash.get(pattern_bytes);
52365238 const macro_arg_index = args_hash.get(macro_bytes);
52375239
......@@ -5243,7 +5245,7 @@ pub const PatternList = struct {
52435245 return false;
52445246 }
52455247 },
5246 .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => {
5248 .string_literal, .char_literal, .pp_num => {
52475249 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
52485250 },
52495251 else => {
......@@ -5359,13 +5361,13 @@ const MacroCtx = struct {
53595361 return self.list[self.i].id;
53605362 }
53615363
5362 fn skip(self: *MacroCtx, c: *Context, expected_id: std.meta.Tag(CToken.Id)) ParseError!void {
5364 fn skip(self: *MacroCtx, c: *Context, expected_id: CToken.Id) ParseError!void {
53635365 const next_id = self.next().?;
5364 if (next_id != expected_id) {
5366 if (next_id != expected_id and !(expected_id == .identifier and next_id == .extended_identifier)) {
53655367 try self.fail(
53665368 c,
53675369 "unable to translate C expr: expected '{s}' instead got '{s}'",
5368 .{ CToken.Id.symbolName(expected_id), next_id.symbol() },
5370 .{ expected_id.symbol(), next_id.symbol() },
53695371 );
53705372 return error.ParseError;
53715373 }
......@@ -5396,12 +5398,12 @@ const MacroCtx = struct {
53965398 while (i < self.list.len) : (i += 1) {
53975399 const token = self.list[i];
53985400 switch (token.id) {
5399 .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown
5400 .Keyword_struct, .Keyword_union, .Keyword_enum => if (!last_is_type_kw) {
5401 .period, .arrow => i += 1, // skip next token since field identifiers can be unknown
5402 .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) {
54015403 last_is_type_kw = true;
54025404 continue;
54035405 },
5404 .Identifier => {
5406 .identifier, .extended_identifier => {
54055407 const identifier = slicer.slice(token);
54065408 const is_param = for (params) |param| {
54075409 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;
......@@ -5422,31 +5424,38 @@ const MacroCtx = struct {
54225424};
54235425
54245426fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {
5425 var tokenizer = std.c.Tokenizer{
5426 .buffer = source,
5427 var tokenizer: aro.Tokenizer = .{
5428 .buf = source,
5429 .source = .unused,
5430 .langopts = .{},
54275431 };
54285432 while (true) {
54295433 const tok = tokenizer.next();
54305434 switch (tok.id) {
5431 .Nl, .Eof => {
5435 .whitespace => continue,
5436 .nl, .eof => {
54325437 try tok_list.append(tok);
54335438 break;
54345439 },
5435 .LineComment, .MultiLineComment => continue,
54365440 else => {},
54375441 }
54385442 try tok_list.append(tok);
54395443 }
54405444}
54415445
5442fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 {
5446fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 {
54435447 const begin_loc = macro.getSourceRange_getBegin();
54445448 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54455449
54465450 const begin_c = c.source_manager.getCharacterData(begin_loc);
54475451 const end_c = c.source_manager.getCharacterData(end_loc);
54485452 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);
5449 return begin_c[0..slice_len];
5453
5454 var comp = aro.Compilation.init(c.gpa);
5455 defer comp.deinit();
5456 const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory;
5457
5458 return c.arena.dupe(u8, result.buf);
54505459}
54515460
54525461fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
......@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54715480 continue;
54725481 }
54735482
5474 const source = getMacroText(unit, c, macro);
5483 const source = try getMacroText(unit, c, macro);
54755484
54765485 try tokenizeMacro(source, &tok_list);
54775486
......@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54855494
54865495 var macro_fn = false;
54875496 switch (macro_ctx.peek().?) {
5488 .Identifier => {
5497 .identifier, .extended_identifier => {
54895498 // if it equals itself, ignore. for example, from stdio.h:
54905499 // #define stdin stdin
54915500 const tok = macro_ctx.list[1];
......@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54945503 continue;
54955504 }
54965505 },
5497 .Nl, .Eof => {
5506 .nl, .eof => {
54985507 // this means it is a macro without a value
54995508 // We define it as an empty string so that it can still be used with ++
55005509 const str_node = try Tag.string_literal.create(c.arena, "\"\"");
......@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
55035512 try c.global_scope.blank_macros.put(name, {});
55045513 continue;
55055514 },
5506 .LParen => {
5515 .l_paren => {
55075516 // if the name is immediately followed by a '(' then it is a function
55085517 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;
55095518 },
......@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55345543 // Check if the macro only uses other blank macros.
55355544 while (true) {
55365545 switch (m.peek().?) {
5537 .Identifier => {
5546 .identifier, .extended_identifier => {
55385547 const tok = m.list[m.i + 1];
55395548 const slice = m.source[tok.start..tok.end];
55405549 if (c.global_scope.blank_macros.contains(slice)) {
......@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55425551 continue;
55435552 }
55445553 },
5545 .Eof, .Nl => {
5554 .eof, .nl => {
55465555 try c.global_scope.blank_macros.put(m.name, {});
55475556 const init_node = try Tag.string_literal.create(c.arena, "\"\"");
55485557 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
......@@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55565565
55575566 const init_node = try parseCExpr(c, m, scope);
55585567 const last = m.next().?;
5559 if (last != .Eof and last != .Nl)
5568 if (last != .eof and last != .nl)
55605569 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
55615570
55625571 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
......@@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55785587 defer block_scope.deinit();
55795588 const scope = &block_scope.base;
55805589
5581 try m.skip(c, .LParen);
5590 try m.skip(c, .l_paren);
55825591
55835592 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
55845593 defer fn_params.deinit();
55855594
55865595 while (true) {
5587 if (m.peek().? != .Identifier) break;
5588 _ = m.next();
5596 switch (m.peek().?) {
5597 .identifier, .extended_identifier => _ = m.next(),
5598 else => break,
5599 }
55895600
55905601 const mangled_name = try block_scope.makeMangledName(c, m.slice());
55915602 try fn_params.append(.{
......@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55945605 .type = Tag.@"anytype".init(),
55955606 });
55965607 try block_scope.discardVariable(c, mangled_name);
5597 if (m.peek().? != .Comma) break;
5608 if (m.peek().? != .comma) break;
55985609 _ = m.next();
55995610 }
56005611
5601 try m.skip(c, .RParen);
5612 try m.skip(c, .r_paren);
56025613
56035614 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {
56045615 .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}),
......@@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
56075618
56085619 const expr = try parseCExpr(c, m, scope);
56095620 const last = m.next().?;
5610 if (last != .Eof and last != .Nl)
5621 if (last != .eof and last != .nl)
56115622 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
56125623
56135624 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
......@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56445655 defer block_scope.deinit();
56455656
56465657 const node = try parseCCondExpr(c, m, &block_scope.base);
5647 if (m.next().? != .Comma) {
5658 if (m.next().? != .comma) {
56485659 m.i -= 1;
56495660 return node;
56505661 }
......@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56565667 try block_scope.statements.append(ignore);
56575668
56585669 last = try parseCCondExpr(c, m, &block_scope.base);
5659 if (m.next().? != .Comma) {
5670 if (m.next().? != .comma) {
56605671 m.i -= 1;
56615672 break;
56625673 }
......@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
56705681 return try block_scope.complete(c);
56715682}
56725683
5673fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
5674 var lit_bytes = m.slice();
5684fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node {
5685 const lit_bytes = m.slice();
5686 var bytes = try std.ArrayListUnmanaged(u8).initCapacity(ctx.arena, lit_bytes.len + 3);
56755687
5676 switch (m.list[m.i].id) {
5677 .IntegerLiteral => |suffix| {
5678 var base: []const u8 = "decimal";
5679 if (lit_bytes.len >= 2 and lit_bytes[0] == '0') {
5680 switch (lit_bytes[1]) {
5681 '0'...'7' => {
5682 // Octal
5683 lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes[1..]});
5684 base = "octal";
5685 },
5686 'X' => {
5687 // Hexadecimal with capital X, valid in C but not in Zig
5688 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
5689 base = "hexadecimal";
5690 },
5691 'x' => {
5692 base = "hexadecimal";
5693 },
5694 else => {},
5695 }
5696 }
5697
5698 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5699 .none => "c_int",
5700 .u => "c_uint",
5701 .l => "c_long",
5702 .lu => "c_ulong",
5703 .ll => "c_longlong",
5704 .llu => "c_ulonglong",
5705 .f => unreachable,
5706 });
5707 lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) {
5708 .none => @as(u8, 0),
5709 .u, .l => 1,
5710 .lu, .ll => 2,
5711 .llu => 3,
5712 .f => unreachable,
5713 }];
5714
5715 const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128);
5716
5717 // make the output less noisy by skipping promoteIntLiteral where
5718 // it's guaranteed to not be required because of C standard type constraints
5719 const guaranteed_to_fit = switch (suffix) {
5720 .none => math.cast(i16, value) != null,
5721 .u => math.cast(u16, value) != null,
5722 .l => math.cast(i32, value) != null,
5723 .lu => math.cast(u32, value) != null,
5724 .ll => math.cast(i64, value) != null,
5725 .llu => math.cast(u64, value) != null,
5726 .f => unreachable,
5727 };
5728
5729 const literal_node = try transCreateNodeNumber(c, lit_bytes, .int);
5688 const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes);
5689 switch (prefix) {
5690 .binary => bytes.appendSliceAssumeCapacity("0b"),
5691 .octal => bytes.appendSliceAssumeCapacity("0o"),
5692 .hex => bytes.appendSliceAssumeCapacity("0x"),
5693 .decimal => {},
5694 }
57305695
5731 if (guaranteed_to_fit) {
5732 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });
5733 } else {
5734 return Tag.helpers_promoteIntLiteral.create(c.arena, .{
5735 .type = type_node,
5736 .value = literal_node,
5737 .base = try Tag.enum_literal.create(c.arena, base),
5738 });
5696 const after_prefix = lit_bytes[prefix.stringLen()..];
5697 const after_int = for (after_prefix, 0..) |c, i| switch (c) {
5698 '.' => {
5699 if (i == 0) {
5700 bytes.appendAssumeCapacity('0');
57395701 }
5702 break after_prefix[i..];
57405703 },
5741 .FloatLiteral => |suffix| {
5742 if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1];
5743
5744 if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) {
5745 if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {
5746 if (dot_index == 2) {
5747 lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]});
5748 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) {
5749 // If the literal lacks a digit after the `.`, we need to
5750 // add one since `0x1.p10` would be invalid syntax in Zig.
5751 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{
5752 lit_bytes[2 .. dot_index + 1],
5753 lit_bytes[dot_index + 1 ..],
5754 });
5755 }
5756 }
5704 'e', 'E' => {
5705 if (prefix != .hex) break after_prefix[i..];
5706 bytes.appendAssumeCapacity(c);
5707 },
5708 'p', 'P' => break after_prefix[i..],
5709 '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => {
5710 if (!prefix.digitAllowed(c)) break after_prefix[i..];
5711 bytes.appendAssumeCapacity(c);
5712 },
5713 '\'' => {
5714 bytes.appendAssumeCapacity('_');
5715 },
5716 else => break after_prefix[i..],
5717 } else "";
57575718
5758 if (lit_bytes[1] == 'X') {
5759 // Hexadecimal with capital X, valid in C but not in Zig
5760 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});
5761 }
5762 } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {
5763 if (dot_index == 0) {
5764 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
5765 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) {
5766 // If the literal lacks a digit after the `.`, we need to
5767 // add one since `1.` or `1.e10` would be invalid syntax in Zig.
5768 lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{
5769 lit_bytes[0 .. dot_index + 1],
5770 lit_bytes[dot_index + 1 ..],
5771 });
5772 }
5719 const after_frac = frac: {
5720 if (after_int.len == 0 or after_int[0] != '.') break :frac after_int;
5721 bytes.appendAssumeCapacity('.');
5722 for (after_int[1..], 1..) |c, i| {
5723 if (c == '\'') {
5724 bytes.appendAssumeCapacity('_');
5725 continue;
57735726 }
5727 if (!prefix.digitAllowed(c)) break :frac after_int[i..];
5728 bytes.appendAssumeCapacity(c);
5729 }
5730 break :frac "";
5731 };
5732
5733 const suffix_str = exponent: {
5734 if (after_frac.len == 0) break :exponent after_frac;
5735 switch (after_frac[0]) {
5736 'e', 'E' => {},
5737 'p', 'P' => if (prefix != .hex) break :exponent after_frac,
5738 else => break :exponent after_frac,
5739 }
5740 bytes.appendAssumeCapacity(after_frac[0]);
5741 for (after_frac[1..], 1..) |c, i| switch (c) {
5742 '+', '-', '0'...'9' => {
5743 bytes.appendAssumeCapacity(c);
5744 },
5745 '\'' => {
5746 bytes.appendAssumeCapacity('_');
5747 },
5748 else => break :exponent after_frac[i..],
5749 };
5750 break :exponent "";
5751 };
5752
5753 const is_float = after_int.len != suffix_str.len;
5754 const suffix = aro.Tree.Token.NumberSuffix.fromString(suffix_str, if (is_float) .float else .int) orelse {
5755 try m.fail(ctx, "invalid number suffix: '{s}'", .{suffix_str});
5756 return error.ParseError;
5757 };
5758 if (suffix.isImaginary()) {
5759 try m.fail(ctx, "TODO: imaginary literals", .{});
5760 return error.ParseError;
5761 }
5762 if (suffix.isBitInt()) {
5763 try m.fail(ctx, "TODO: _BitInt literals", .{});
5764 return error.ParseError;
5765 }
5766
5767 if (is_float) {
5768 const type_node = try Tag.type.create(ctx.arena, switch (suffix) {
5769 .F16 => "f16",
5770 .F => "f32",
5771 .None => "f64",
5772 .L => "c_longdouble",
5773 .W => "f80",
5774 .Q, .F128 => "f128",
5775 else => unreachable,
5776 });
5777 const rhs = try Tag.float_literal.create(ctx.arena, bytes.items);
5778 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = rhs });
5779 } else {
5780 const type_node = try Tag.type.create(ctx.arena, switch (suffix) {
5781 .None => "c_int",
5782 .U => "c_uint",
5783 .L => "c_long",
5784 .UL => "c_ulong",
5785 .LL => "c_longlong",
5786 .ULL => "c_ulonglong",
5787 else => unreachable,
5788 });
5789 const value = std.fmt.parseInt(i128, bytes.items, 0) catch math.maxInt(i128);
5790
5791 // make the output less noisy by skipping promoteIntLiteral where
5792 // it's guaranteed to not be required because of C standard type constraints
5793 const guaranteed_to_fit = switch (suffix) {
5794 .None => math.cast(i16, value) != null,
5795 .U => math.cast(u16, value) != null,
5796 .L => math.cast(i32, value) != null,
5797 .UL => math.cast(u32, value) != null,
5798 .LL => math.cast(i64, value) != null,
5799 .ULL => math.cast(u64, value) != null,
5800 else => unreachable,
5801 };
57745802
5775 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5776 .f => "f32",
5777 .none => "f64",
5778 .l => "c_longdouble",
5779 else => unreachable,
5803 const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items);
5804 if (guaranteed_to_fit) {
5805 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node });
5806 } else {
5807 return Tag.helpers_promoteIntLiteral.create(ctx.arena, .{
5808 .type = type_node,
5809 .value = literal_node,
5810 .base = try Tag.enum_literal.create(ctx.arena, @tagName(prefix)),
57805811 });
5781 const rhs = try transCreateNodeNumber(c, lit_bytes, .float);
5782 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5783 },
5784 else => unreachable,
5812 }
57855813 }
57865814}
57875815
......@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58005828 } else return source;
58015829 var bytes = try ctx.arena.alloc(u8, source.len * 2);
58025830 var state: enum {
5803 Start,
5804 Escape,
5805 Hex,
5806 Octal,
5807 } = .Start;
5831 start,
5832 escape,
5833 hex,
5834 octal,
5835 } = .start;
58085836 var i: usize = 0;
58095837 var count: u8 = 0;
58105838 var num: u8 = 0;
58115839 for (source) |c| {
58125840 switch (state) {
5813 .Escape => {
5841 .escape => {
58145842 switch (c) {
58155843 'n', 'r', 't', '\\', '\'', '\"' => {
58165844 bytes[i] = c;
......@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58185846 '0'...'7' => {
58195847 count += 1;
58205848 num += c - '0';
5821 state = .Octal;
5849 state = .octal;
58225850 bytes[i] = 'x';
58235851 },
58245852 'x' => {
5825 state = .Hex;
5853 state = .hex;
58265854 bytes[i] = 'x';
58275855 },
58285856 'a' => {
......@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58675895 },
58685896 }
58695897 i += 1;
5870 if (state == .Escape)
5871 state = .Start;
5898 if (state == .escape)
5899 state = .start;
58725900 },
5873 .Start => {
5901 .start => {
58745902 if (c == '\t') {
58755903 bytes[i] = '\\';
58765904 i += 1;
......@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58795907 continue;
58805908 }
58815909 if (c == '\\') {
5882 state = .Escape;
5910 state = .escape;
58835911 }
58845912 bytes[i] = c;
58855913 i += 1;
58865914 },
5887 .Hex => {
5915 .hex => {
58885916 switch (c) {
58895917 '0'...'9' => {
58905918 num = std.math.mul(u8, num, 16) catch {
......@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
59115939 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
59125940 num = 0;
59135941 if (c == '\\')
5914 state = .Escape
5942 state = .escape
59155943 else
5916 state = .Start;
5944 state = .start;
59175945 bytes[i] = c;
59185946 i += 1;
59195947 },
59205948 }
59215949 },
5922 .Octal => {
5950 .octal => {
59235951 const accept_digit = switch (c) {
59245952 // The maximum length of a octal literal is 3 digits
59255953 '0'...'7' => count < 3,
......@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
59385966 num = 0;
59395967 count = 0;
59405968 if (c == '\\')
5941 state = .Escape
5969 state = .escape
59425970 else
5943 state = .Start;
5971 state = .start;
59445972 bytes[i] = c;
59455973 i += 1;
59465974 }
59475975 },
59485976 }
59495977 }
5950 if (state == .Hex or state == .Octal)
5978 if (state == .hex or state == .octal)
59515979 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
59525980 return bytes[0..i];
59535981}
......@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59726000 const tok = m.next().?;
59736001 const slice = m.slice();
59746002 switch (tok) {
5975 .CharLiteral => {
6003 .char_literal,
6004 .char_literal_utf_8,
6005 .char_literal_utf_16,
6006 .char_literal_utf_32,
6007 .char_literal_wide,
6008 => {
59766009 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
59776010 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
59786011 } else {
......@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59806013 return Tag.integer_literal.create(c.arena, str);
59816014 }
59826015 },
5983 .StringLiteral => {
6016 .string_literal,
6017 .string_literal_utf_16,
6018 .string_literal_utf_8,
6019 .string_literal_utf_32,
6020 .string_literal_wide,
6021 => {
59846022 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
59856023 },
5986 .IntegerLiteral, .FloatLiteral => {
6024 .pp_num => {
59876025 return parseCNumLit(c, m);
59886026 },
5989 .Identifier => {
6027 .identifier, .extended_identifier => {
59906028 if (c.global_scope.blank_macros.contains(slice)) {
59916029 return parseCPrimaryExprInner(c, m, scope);
59926030 }
......@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
59966034 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
59976035 return identifier;
59986036 },
5999 .LParen => {
6037 .l_paren => {
60006038 const inner_node = try parseCExpr(c, m, scope);
60016039
6002 try m.skip(c, .RParen);
6040 try m.skip(c, .r_paren);
60036041 return inner_node;
60046042 },
60056043 else => {
......@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60226060 // after a primary expression.
60236061 while (true) {
60246062 switch (m.peek().?) {
6025 .StringLiteral => {},
6026 .Identifier => {
6063 .string_literal,
6064 .string_literal_utf_16,
6065 .string_literal_utf_8,
6066 .string_literal_utf_32,
6067 .string_literal_wide,
6068 => {},
6069 .identifier, .extended_identifier => {
60276070 const tok = m.list[m.i + 1];
60286071 const slice = m.source[tok.start..tok.end];
60296072 if (c.global_scope.blank_macros.contains(slice)) {
......@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {
60576100
60586101fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60596102 const node = try parseCOrExpr(c, m, scope);
6060 if (m.peek().? != .QuestionMark) {
6103 if (m.peek().? != .question_mark) {
60616104 return node;
60626105 }
60636106 _ = m.next();
60646107
60656108 const then_body = try parseCOrExpr(c, m, scope);
6066 try m.skip(c, .Colon);
6109 try m.skip(c, .colon);
60676110 const else_body = try parseCCondExpr(c, m, scope);
60686111 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
60696112}
60706113
60716114fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60726115 var node = try parseCAndExpr(c, m, scope);
6073 while (m.next().? == .PipePipe) {
6116 while (m.next().? == .pipe_pipe) {
60746117 const lhs = try macroIntToBool(c, node);
60756118 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
60766119 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60816124
60826125fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60836126 var node = try parseCBitOrExpr(c, m, scope);
6084 while (m.next().? == .AmpersandAmpersand) {
6127 while (m.next().? == .ampersand_ampersand) {
60856128 const lhs = try macroIntToBool(c, node);
60866129 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
60876130 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60926135
60936136fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60946137 var node = try parseCBitXorExpr(c, m, scope);
6095 while (m.next().? == .Pipe) {
6138 while (m.next().? == .pipe) {
60966139 const lhs = try macroIntFromBool(c, node);
60976140 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));
60986141 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61036146
61046147fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61056148 var node = try parseCBitAndExpr(c, m, scope);
6106 while (m.next().? == .Caret) {
6149 while (m.next().? == .caret) {
61076150 const lhs = try macroIntFromBool(c, node);
61086151 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));
61096152 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61146157
61156158fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61166159 var node = try parseCEqExpr(c, m, scope);
6117 while (m.next().? == .Ampersand) {
6160 while (m.next().? == .ampersand) {
61186161 const lhs = try macroIntFromBool(c, node);
61196162 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));
61206163 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
......@@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61276170 var node = try parseCRelExpr(c, m, scope);
61286171 while (true) {
61296172 switch (m.peek().?) {
6130 .BangEqual => {
6173 .bang_equal => {
61316174 _ = m.next();
61326175 const lhs = try macroIntFromBool(c, node);
61336176 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
61346177 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61356178 },
6136 .EqualEqual => {
6179 .equal_equal => {
61376180 _ = m.next();
61386181 const lhs = try macroIntFromBool(c, node);
61396182 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
......@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61486191 var node = try parseCShiftExpr(c, m, scope);
61496192 while (true) {
61506193 switch (m.peek().?) {
6151 .AngleBracketRight => {
6194 .angle_bracket_right => {
61526195 _ = m.next();
61536196 const lhs = try macroIntFromBool(c, node);
61546197 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61556198 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61566199 },
6157 .AngleBracketRightEqual => {
6200 .angle_bracket_right_equal => {
61586201 _ = m.next();
61596202 const lhs = try macroIntFromBool(c, node);
61606203 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61616204 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61626205 },
6163 .AngleBracketLeft => {
6206 .angle_bracket_left => {
61646207 _ = m.next();
61656208 const lhs = try macroIntFromBool(c, node);
61666209 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
61676210 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61686211 },
6169 .AngleBracketLeftEqual => {
6212 .angle_bracket_left_equal => {
61706213 _ = m.next();
61716214 const lhs = try macroIntFromBool(c, node);
61726215 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
......@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61816224 var node = try parseCAddSubExpr(c, m, scope);
61826225 while (true) {
61836226 switch (m.peek().?) {
6184 .AngleBracketAngleBracketLeft => {
6227 .angle_bracket_angle_bracket_left => {
61856228 _ = m.next();
61866229 const lhs = try macroIntFromBool(c, node);
61876230 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
61886231 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
61896232 },
6190 .AngleBracketAngleBracketRight => {
6233 .angle_bracket_angle_bracket_right => {
61916234 _ = m.next();
61926235 const lhs = try macroIntFromBool(c, node);
61936236 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
......@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62026245 var node = try parseCMulExpr(c, m, scope);
62036246 while (true) {
62046247 switch (m.peek().?) {
6205 .Plus => {
6248 .plus => {
62066249 _ = m.next();
62076250 const lhs = try macroIntFromBool(c, node);
62086251 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
62096252 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
62106253 },
6211 .Minus => {
6254 .minus => {
62126255 _ = m.next();
62136256 const lhs = try macroIntFromBool(c, node);
62146257 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
......@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62236266 var node = try parseCCastExpr(c, m, scope);
62246267 while (true) {
62256268 switch (m.next().?) {
6226 .Asterisk => {
6269 .asterisk => {
62276270 const lhs = try macroIntFromBool(c, node);
62286271 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62296272 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
62306273 },
6231 .Slash => {
6274 .slash => {
62326275 const lhs = try macroIntFromBool(c, node);
62336276 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62346277 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });
62356278 },
6236 .Percent => {
6279 .percent => {
62376280 const lhs = try macroIntFromBool(c, node);
62386281 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
62396282 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs });
......@@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62486291
62496292fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62506293 switch (m.next().?) {
6251 .LParen => {
6294 .l_paren => {
62526295 if (try parseCTypeName(c, m, scope, true)) |type_name| {
62536296 while (true) {
62546297 const next_token = m.next().?;
62556298 switch (next_token) {
6256 .RParen => break,
6299 .r_paren => break,
62576300 else => |next_tag| {
62586301 // Skip trailing blank defined before the RParen.
6259 if (next_tag == .Identifier and c.global_scope.blank_macros.contains(m.slice())) {
6302 if ((next_tag == .identifier or next_tag == .extended_identifier) and
6303 c.global_scope.blank_macros.contains(m.slice()))
62606304 continue;
6261 }
6305
62626306 try m.fail(
62636307 c,
62646308 "unable to translate C expr: expected ')' instead got '{s}'",
......@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62686312 },
62696313 }
62706314 }
6271 if (m.peek().? == .LBrace) {
6315 if (m.peek().? == .l_brace) {
62726316 // initializer list
62736317 return parseCPostfixExpr(c, m, scope, type_name);
62746318 }
......@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
62946338fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
62956339 const tok = m.next().?;
62966340 switch (tok) {
6297 .Identifier => {
6341 .identifier, .extended_identifier => {
62986342 if (c.global_scope.blank_macros.contains(m.slice())) {
62996343 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);
63006344 }
......@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
63046348 return try Tag.identifier.create(c.arena, mangled_name);
63056349 }
63066350 },
6307 .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6308 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),
6309 .Keyword_char,
6310 .Keyword_int,
6311 .Keyword_short,
6312 .Keyword_long,
6313 .Keyword_float,
6314 .Keyword_double,
6315 .Keyword_signed,
6316 .Keyword_unsigned,
6317 .Keyword_complex,
6351 .keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6352 .keyword_bool => return try Tag.type.create(c.arena, "bool"),
6353 .keyword_char,
6354 .keyword_int,
6355 .keyword_short,
6356 .keyword_long,
6357 .keyword_float,
6358 .keyword_double,
6359 .keyword_signed,
6360 .keyword_unsigned,
6361 .keyword_complex,
63186362 => {
63196363 m.i -= 1;
63206364 return try parseCNumericType(c, m);
63216365 },
6322 .Keyword_enum, .Keyword_struct, .Keyword_union => {
6366 .keyword_enum, .keyword_struct, .keyword_union => {
63236367 // struct Foo will be declared as struct_Foo by transRecordDecl
63246368 const slice = m.slice();
6325 try m.skip(c, .Identifier);
6369 try m.skip(c, .identifier);
63266370
63276371 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
63286372 return try Tag.identifier.create(c.arena, name);
......@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
63646408 var i: u8 = 0;
63656409 while (i < math.maxInt(u8)) : (i += 1) {
63666410 switch (m.next().?) {
6367 .Keyword_double => kw.double += 1,
6368 .Keyword_long => kw.long += 1,
6369 .Keyword_int => kw.int += 1,
6370 .Keyword_float => kw.float += 1,
6371 .Keyword_short => kw.short += 1,
6372 .Keyword_char => kw.char += 1,
6373 .Keyword_unsigned => kw.unsigned += 1,
6374 .Keyword_signed => kw.signed += 1,
6375 .Keyword_complex => kw.complex += 1,
6411 .keyword_double => kw.double += 1,
6412 .keyword_long => kw.long += 1,
6413 .keyword_int => kw.int += 1,
6414 .keyword_float => kw.float += 1,
6415 .keyword_short => kw.short += 1,
6416 .keyword_char => kw.char += 1,
6417 .keyword_unsigned => kw.unsigned += 1,
6418 .keyword_signed => kw.signed += 1,
6419 .keyword_complex => kw.complex += 1,
63766420 else => {
63776421 m.i -= 1;
63786422 break;
......@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
64426486
64436487fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {
64446488 switch (m.next().?) {
6445 .Asterisk => {
6489 .asterisk => {
64466490 // last token of `node`
64476491 const prev_id = m.list[m.i - 1].id;
64486492
6449 if (prev_id == .Keyword_void) {
6493 if (prev_id == .keyword_void) {
64506494 const ptr = try Tag.single_pointer.create(c.arena, .{
64516495 .is_const = false,
64526496 .is_volatile = false,
......@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
64726516 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
64736517 while (true) {
64746518 switch (m.next().?) {
6475 .Period => {
6476 try m.skip(c, .Identifier);
6519 .period => {
6520 try m.skip(c, .identifier);
64776521
64786522 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
64796523 },
6480 .Arrow => {
6481 try m.skip(c, .Identifier);
6524 .arrow => {
6525 try m.skip(c, .identifier);
64826526
64836527 const deref = try Tag.deref.create(c.arena, node);
64846528 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
64856529 },
6486 .LBracket => {
6530 .l_bracket => {
64876531 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));
64886532 const index = try Tag.as.create(c.arena, .{
64896533 .lhs = try Tag.type.create(c.arena, "usize"),
64906534 .rhs = try Tag.int_cast.create(c.arena, index_val),
64916535 });
64926536 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
6493 try m.skip(c, .RBracket);
6537 try m.skip(c, .r_bracket);
64946538 },
6495 .LParen => {
6496 if (m.peek().? == .RParen) {
6539 .l_paren => {
6540 if (m.peek().? == .r_paren) {
64976541 m.i += 1;
64986542 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
64996543 } else {
......@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65046548 try args.append(arg);
65056549 const next_id = m.next().?;
65066550 switch (next_id) {
6507 .Comma => {},
6508 .RParen => break,
6551 .comma => {},
6552 .r_paren => break,
65096553 else => {
65106554 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});
65116555 return error.ParseError;
......@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65156559 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
65166560 }
65176561 },
6518 .LBrace => {
6562 .l_brace => {
65196563 // Check for designated field initializers
6520 if (m.peek().? == .Period) {
6564 if (m.peek().? == .period) {
65216565 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);
65226566 defer init_vals.deinit();
65236567
65246568 while (true) {
6525 try m.skip(c, .Period);
6526 try m.skip(c, .Identifier);
6569 try m.skip(c, .period);
6570 try m.skip(c, .identifier);
65276571 const name = m.slice();
6528 try m.skip(c, .Equal);
6572 try m.skip(c, .equal);
65296573
65306574 const val = try parseCCondExpr(c, m, scope);
65316575 try init_vals.append(.{ .name = name, .value = val });
65326576 const next_id = m.next().?;
65336577 switch (next_id) {
6534 .Comma => {},
6535 .RBrace => break,
6578 .comma => {},
6579 .r_brace => break,
65366580 else => {
65376581 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
65386582 return error.ParseError;
......@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65526596 try init_vals.append(val);
65536597 const next_id = m.next().?;
65546598 switch (next_id) {
6555 .Comma => {},
6556 .RBrace => break,
6599 .comma => {},
6600 .r_brace => break,
65576601 else => {
65586602 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
65596603 return error.ParseError;
......@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65636607 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
65646608 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
65656609 },
6566 .PlusPlus, .MinusMinus => {
6610 .plus_plus, .minus_minus => {
65676611 try m.fail(c, "TODO postfix inc/dec expr", .{});
65686612 return error.ParseError;
65696613 },
......@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65776621
65786622fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65796623 switch (m.next().?) {
6580 .Bang => {
6624 .bang => {
65816625 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
65826626 return Tag.not.create(c.arena, operand);
65836627 },
6584 .Minus => {
6628 .minus => {
65856629 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
65866630 return Tag.negate.create(c.arena, operand);
65876631 },
6588 .Plus => return try parseCCastExpr(c, m, scope),
6589 .Tilde => {
6632 .plus => return try parseCCastExpr(c, m, scope),
6633 .tilde => {
65906634 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
65916635 return Tag.bit_not.create(c.arena, operand);
65926636 },
6593 .Asterisk => {
6637 .asterisk => {
65946638 const operand = try parseCCastExpr(c, m, scope);
65956639 return Tag.deref.create(c.arena, operand);
65966640 },
6597 .Ampersand => {
6641 .ampersand => {
65986642 const operand = try parseCCastExpr(c, m, scope);
65996643 return Tag.address_of.create(c.arena, operand);
66006644 },
6601 .Keyword_sizeof => {
6602 const operand = if (m.peek().? == .LParen) blk: {
6645 .keyword_sizeof => {
6646 const operand = if (m.peek().? == .l_paren) blk: {
66036647 _ = m.next();
66046648 const inner = (try parseCTypeName(c, m, scope, false)).?;
6605 try m.skip(c, .RParen);
6649 try m.skip(c, .r_paren);
66066650 break :blk inner;
66076651 } else try parseCUnaryExpr(c, m, scope);
66086652
66096653 return Tag.helpers_sizeof.create(c.arena, operand);
66106654 },
6611 .Keyword_alignof => {
6655 .keyword_alignof => {
66126656 // TODO this won't work if using <stdalign.h>'s
66136657 // #define alignof _Alignof
6614 try m.skip(c, .LParen);
6658 try m.skip(c, .l_paren);
66156659 const operand = (try parseCTypeName(c, m, scope, false)).?;
6616 try m.skip(c, .RParen);
6660 try m.skip(c, .r_paren);
66176661
66186662 return Tag.alignof.create(c.arena, operand);
66196663 },
6620 .PlusPlus, .MinusMinus => {
6664 .plus_plus, .minus_minus => {
66216665 try m.fail(c, "TODO unary inc/dec expr", .{});
66226666 return error.ParseError;
66236667 },
test/translate_c.zig+7-7
......@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
424424 \\ });
425425 \\}
426426 ,
427 \\pub const B = A(@as(f32, 0.0));
427 \\pub const B = A(@as(f32, 0));
428428 });
429429
430430 cases.add("complex switch",
......@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
633633 cases.add("#define hex literal with capital X",
634634 \\#define VAL 0XF00D
635635 , &[_][]const u8{
636 \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hexadecimal);
636 \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex);
637637 });
638638
639639 cases.add("anonymous struct & unions",
......@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12431243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
12441244 , &([_][]const u8{
12451245 "pub const foo = @as(f32, 3.14);",
1246 "pub const bar = @as(c_longdouble, 16.0e-2);",
1246 "pub const bar = @as(c_longdouble, 16.e-2);",
12471247 "pub const FOO = @as(f64, 0.12345);",
12481248 "pub const BAR = @as(f64, 0.12345);",
12491249 "pub const baz = @as(f64, 1e1);",
12501250 "pub const BAZ = @as(f32, 42e-3);",
1251 "pub const foobar = -@as(c_longdouble, 73.0);",
1251 "pub const foobar = -@as(c_longdouble, 73);",
12521252 "pub export const my_float: f32 = 1.0;",
12531253 "pub export const my_double: f64 = 1.0;",
12541254 "pub export const my_longdouble: c_longdouble = 1.0;",
......@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12721272 "pub const BAR = -@as(f32, 0x8F.BP5);",
12731273 "pub const FOOBAR = @as(f64, 0x0P+0);",
12741274 "pub const BAZ = -@as(f64, 0x0.0a5dp+12);",
1275 "pub const FOOBAZ = @as(c_longdouble, 0xfE.0P-1);",
1275 "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);",
12761276 });
12771277
12781278 cases.add("comments",
......@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
37303730 , &[_][]const u8{
37313731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
37323732 ,
3733 \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hexadecimal));
3733 \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex));
37343734 });
37353735
37363736 if (builtin.abi == .msvc) {
......@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
38123812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);
38133813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);
38143814 \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal);
3815 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hexadecimal);
3815 \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex);
38163816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
38173817 });
38183818