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...@@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES
218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"218 "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"219 "${CMAKE_SOURCE_DIR}/lib/std/c.zig"
220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"220 "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
221 "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig"
222 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"221 "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig"
223 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"222 "${CMAKE_SOURCE_DIR}/lib/std/coff.zig"
224 "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig"223 "${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;...@@ -5,14 +5,6 @@ const page_size = std.mem.page_size;
5const iovec = std.os.iovec;5const iovec = std.os.iovec;
6const iovec_const = std.os.iovec_const;6const 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
16/// The return type is `type` to force comptime function call execution.8/// The return type is `type` to force comptime function call execution.
17/// TODO: https://github.com/ziglang/zig/issues/4259/// TODO: https://github.com/ziglang/zig/issues/425
18/// If not linking libc, returns struct{pub const ok = false;}10/// 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" {...@@ -252,7 +252,7 @@ test "sizeof" {
252 try testing.expect(sizeof(anyopaque) == 1);252 try testing.expect(sizeof(anyopaque) == 1);
253}253}
254254
255pub const CIntLiteralBase = enum { decimal, octal, hexadecimal };255pub const CIntLiteralBase = enum { decimal, octal, hex };
256256
257/// Deprecated: use `CIntLiteralBase`257/// Deprecated: use `CIntLiteralBase`
258pub const CIntLiteralRadix = CIntLiteralBase;258pub const CIntLiteralRadix = CIntLiteralBase;
...@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(...@@ -289,13 +289,13 @@ pub fn promoteIntLiteral(
289}289}
290290
291test "promoteIntLiteral" {291test "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);
293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));293 try testing.expectEqual(c_uint, @TypeOf(signed_hex));
294294
295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;295 if (math.maxInt(c_longlong) == math.maxInt(c_int)) return;
296296
297 const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal);297 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
300 if (math.maxInt(c_long) > math.maxInt(c_int)) {300 if (math.maxInt(c_long) > math.maxInt(c_int)) {
301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));301 try testing.expectEqual(c_long, @TypeOf(signed_decimal));
src/Compilation.zig+1-1
...@@ -4194,7 +4194,7 @@ pub const CImportResult = struct {...@@ -4194,7 +4194,7 @@ pub const CImportResult = struct {
4194/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked4194/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
4195/// a bit when we want to start using it from self-hosted.4195/// a bit when we want to start using it from self-hosted.
4196pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {4196pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
4197 if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping4197 if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build");
4198 const tracy_trace = trace(@src());4198 const tracy_trace = trace(@src());
4199 defer tracy_trace.end();4199 defer tracy_trace.end();
42004200
src/main.zig+1-1
...@@ -4286,7 +4286,7 @@ fn updateModule(comp: *Compilation) !void {...@@ -4286,7 +4286,7 @@ fn updateModule(comp: *Compilation) !void {
4286}4286}
42874287
4288fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {4288fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {
4289 if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping4289 if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build");
4290 assert(comp.c_source_files.len == 1);4290 assert(comp.c_source_files.len == 1);
4291 const c_source_file = comp.c_source_files[0];4291 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 {...@@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type {
22 return .{};22 return .{};
23 }23 }
24 pub fn tagFromName(name: []const u8) ?Tag {24 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);
26 }28 }
27 pub const NameBuf = struct {29 pub const NameBuf = struct {
28 pub fn span(_: *const NameBuf) []const u8 {30 pub fn span(_: *const NameBuf) []const u8 {
src/translate_c.zig+305-261
...@@ -1,13 +1,13 @@...@@ -1,13 +1,13 @@
1const std = @import("std");1const std = @import("std");
2const testing = std.testing;2const testing = std.testing;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const clang = @import("clang.zig");
5const ctok = std.c.tokenizer;
6const CToken = std.c.Token;
7const mem = std.mem;4const mem = std.mem;
8const math = std.math;5const math = std.math;
9const meta = std.meta;6const meta = std.meta;
10const CallingConvention = std.builtin.CallingConvention;7const CallingConvention = std.builtin.CallingConvention;
8const clang = @import("clang.zig");
9const aro = @import("aro");
10const CToken = aro.Tokenizer.Token;
11const ast = @import("translate_c/ast.zig");11const ast = @import("translate_c/ast.zig");
12const Node = ast.Node;12const Node = ast.Node;
13const Tag = Node.Tag;13const Tag = Node.Tag;
...@@ -190,19 +190,21 @@ pub fn translate(...@@ -190,19 +190,21 @@ pub fn translate(
190190
191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)191/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
192/// Macros of this form will not be translated.192/// Macros of this form will not be translated.
193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {193fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool {
194 const source = getMacroText(unit, c, macro);194 const source = try getMacroText(unit, c, macro);
195 var tokenizer = std.c.Tokenizer{195 var tokenizer: aro.Tokenizer = .{
196 .buffer = source,196 .buf = source,
197 .source = .unused,
198 .langopts = .{},
197 };199 };
198 const name_tok = tokenizer.next();200 const name_tok = tokenizer.nextNoWS();
199 const name = source[name_tok.start..name_tok.end];201 const name = source[name_tok.start..name_tok.end];
200202
201 const first_tok = tokenizer.next();203 const first_tok = tokenizer.nextNoWS();
202 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by204 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
203 // the tokenizer.205 // the tokenizer.
204 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)206 // 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;
206 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);208 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
207}209}
208210
...@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {...@@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
223 const raw_name = macro.getName_getNameStart();225 const raw_name = macro.getName_getNameStart();
224 const name = try c.str(raw_name);226 const name = try c.str(raw_name);
225227
226 if (!isSelfDefinedMacro(ast_unit, c, macro)) {228 if (!try isSelfDefinedMacro(ast_unit, c, macro)) {
227 try c.global_names.put(c.gpa, name, {});229 try c.global_names.put(c.gpa, name, {});
228 }230 }
229 },231 },
...@@ -5159,16 +5161,16 @@ pub const PatternList = struct {...@@ -5159,16 +5161,16 @@ pub const PatternList = struct {
5159 /// Assumes that `ms` represents a tokenized function-like macro.5161 /// Assumes that `ms` represents a tokenized function-like macro.
5160 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {5162 fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {
5161 assert(ms.tokens.len > 2);5163 assert(ms.tokens.len > 2);
5162 assert(ms.tokens[0].id == .Identifier);5164 assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier);
5163 assert(ms.tokens[1].id == .LParen);5165 assert(ms.tokens[1].id == .l_paren);
51645166
5165 var i: usize = 2;5167 var i: usize = 2;
5166 while (true) : (i += 1) {5168 while (true) : (i += 1) {
5167 const token = ms.tokens[i];5169 const token = ms.tokens[i];
5168 switch (token.id) {5170 switch (token.id) {
5169 .RParen => break,5171 .r_paren => break,
5170 .Comma => continue,5172 .comma => continue,
5171 .Identifier => {5173 .identifier, .extended_identifier => {
5172 const identifier = ms.slice(token);5174 const identifier = ms.slice(token);
5173 try hash.put(allocator, identifier, i);5175 try hash.put(allocator, identifier, i);
5174 },5176 },
...@@ -5220,18 +5222,18 @@ pub const PatternList = struct {...@@ -5220,18 +5222,18 @@ pub const PatternList = struct {
5220 if (args_hash.count() != self.args_hash.count()) return false;5222 if (args_hash.count() != self.args_hash.count()) return false;
52215223
5222 var i: usize = 2;5224 var i: usize = 2;
5223 while (self.tokens[i].id != .RParen) : (i += 1) {}5225 while (self.tokens[i].id != .r_paren) : (i += 1) {}
52245226
5225 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };5227 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };
5226 while (i < self.tokens.len) : (i += 1) {5228 while (i < self.tokens.len) : (i += 1) {
5227 const pattern_token = self.tokens[i];5229 const pattern_token = self.tokens[i];
5228 const macro_token = ms.tokens[i];5230 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
5231 const pattern_bytes = pattern_slicer.slice(pattern_token);5233 const pattern_bytes = pattern_slicer.slice(pattern_token);
5232 const macro_bytes = ms.slice(macro_token);5234 const macro_bytes = ms.slice(macro_token);
5233 switch (pattern_token.id) {5235 switch (pattern_token.id) {
5234 .Identifier => {5236 .identifier, .extended_identifier => {
5235 const pattern_arg_index = self.args_hash.get(pattern_bytes);5237 const pattern_arg_index = self.args_hash.get(pattern_bytes);
5236 const macro_arg_index = args_hash.get(macro_bytes);5238 const macro_arg_index = args_hash.get(macro_bytes);
52375239
...@@ -5243,7 +5245,7 @@ pub const PatternList = struct {...@@ -5243,7 +5245,7 @@ pub const PatternList = struct {
5243 return false;5245 return false;
5244 }5246 }
5245 },5247 },
5246 .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => {5248 .string_literal, .char_literal, .pp_num => {
5247 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;5249 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
5248 },5250 },
5249 else => {5251 else => {
...@@ -5359,13 +5361,13 @@ const MacroCtx = struct {...@@ -5359,13 +5361,13 @@ const MacroCtx = struct {
5359 return self.list[self.i].id;5361 return self.list[self.i].id;
5360 }5362 }
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 {
5363 const next_id = self.next().?;5365 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)) {
5365 try self.fail(5367 try self.fail(
5366 c,5368 c,
5367 "unable to translate C expr: expected '{s}' instead got '{s}'",5369 "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() },
5369 );5371 );
5370 return error.ParseError;5372 return error.ParseError;
5371 }5373 }
...@@ -5396,12 +5398,12 @@ const MacroCtx = struct {...@@ -5396,12 +5398,12 @@ const MacroCtx = struct {
5396 while (i < self.list.len) : (i += 1) {5398 while (i < self.list.len) : (i += 1) {
5397 const token = self.list[i];5399 const token = self.list[i];
5398 switch (token.id) {5400 switch (token.id) {
5399 .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown5401 .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) {5402 .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) {
5401 last_is_type_kw = true;5403 last_is_type_kw = true;
5402 continue;5404 continue;
5403 },5405 },
5404 .Identifier => {5406 .identifier, .extended_identifier => {
5405 const identifier = slicer.slice(token);5407 const identifier = slicer.slice(token);
5406 const is_param = for (params) |param| {5408 const is_param = for (params) |param| {
5407 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;5409 if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true;
...@@ -5422,31 +5424,38 @@ const MacroCtx = struct {...@@ -5422,31 +5424,38 @@ const MacroCtx = struct {
5422};5424};
54235425
5424fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {5426fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {
5425 var tokenizer = std.c.Tokenizer{5427 var tokenizer: aro.Tokenizer = .{
5426 .buffer = source,5428 .buf = source,
5429 .source = .unused,
5430 .langopts = .{},
5427 };5431 };
5428 while (true) {5432 while (true) {
5429 const tok = tokenizer.next();5433 const tok = tokenizer.next();
5430 switch (tok.id) {5434 switch (tok.id) {
5431 .Nl, .Eof => {5435 .whitespace => continue,
5436 .nl, .eof => {
5432 try tok_list.append(tok);5437 try tok_list.append(tok);
5433 break;5438 break;
5434 },5439 },
5435 .LineComment, .MultiLineComment => continue,
5436 else => {},5440 else => {},
5437 }5441 }
5438 try tok_list.append(tok);5442 try tok_list.append(tok);
5439 }5443 }
5440}5444}
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 {
5443 const begin_loc = macro.getSourceRange_getBegin();5447 const begin_loc = macro.getSourceRange_getBegin();
5444 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);5448 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54455449
5446 const begin_c = c.source_manager.getCharacterData(begin_loc);5450 const begin_c = c.source_manager.getCharacterData(begin_loc);
5447 const end_c = c.source_manager.getCharacterData(end_loc);5451 const end_c = c.source_manager.getCharacterData(end_loc);
5448 const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c);5452 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);
5450}5459}
54515460
5452fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {5461fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
...@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5471 continue;5480 continue;
5472 }5481 }
54735482
5474 const source = getMacroText(unit, c, macro);5483 const source = try getMacroText(unit, c, macro);
54755484
5476 try tokenizeMacro(source, &tok_list);5485 try tokenizeMacro(source, &tok_list);
54775486
...@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54855494
5486 var macro_fn = false;5495 var macro_fn = false;
5487 switch (macro_ctx.peek().?) {5496 switch (macro_ctx.peek().?) {
5488 .Identifier => {5497 .identifier, .extended_identifier => {
5489 // if it equals itself, ignore. for example, from stdio.h:5498 // if it equals itself, ignore. for example, from stdio.h:
5490 // #define stdin stdin5499 // #define stdin stdin
5491 const tok = macro_ctx.list[1];5500 const tok = macro_ctx.list[1];
...@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5494 continue;5503 continue;
5495 }5504 }
5496 },5505 },
5497 .Nl, .Eof => {5506 .nl, .eof => {
5498 // this means it is a macro without a value5507 // this means it is a macro without a value
5499 // We define it as an empty string so that it can still be used with ++5508 // We define it as an empty string so that it can still be used with ++
5500 const str_node = try Tag.string_literal.create(c.arena, "\"\"");5509 const str_node = try Tag.string_literal.create(c.arena, "\"\"");
...@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5503 try c.global_scope.blank_macros.put(name, {});5512 try c.global_scope.blank_macros.put(name, {});
5504 continue;5513 continue;
5505 },5514 },
5506 .LParen => {5515 .l_paren => {
5507 // if the name is immediately followed by a '(' then it is a function5516 // if the name is immediately followed by a '(' then it is a function
5508 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;5517 macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start;
5509 },5518 },
...@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5534 // Check if the macro only uses other blank macros.5543 // Check if the macro only uses other blank macros.
5535 while (true) {5544 while (true) {
5536 switch (m.peek().?) {5545 switch (m.peek().?) {
5537 .Identifier => {5546 .identifier, .extended_identifier => {
5538 const tok = m.list[m.i + 1];5547 const tok = m.list[m.i + 1];
5539 const slice = m.source[tok.start..tok.end];5548 const slice = m.source[tok.start..tok.end];
5540 if (c.global_scope.blank_macros.contains(slice)) {5549 if (c.global_scope.blank_macros.contains(slice)) {
...@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5542 continue;5551 continue;
5543 }5552 }
5544 },5553 },
5545 .Eof, .Nl => {5554 .eof, .nl => {
5546 try c.global_scope.blank_macros.put(m.name, {});5555 try c.global_scope.blank_macros.put(m.name, {});
5547 const init_node = try Tag.string_literal.create(c.arena, "\"\"");5556 const init_node = try Tag.string_literal.create(c.arena, "\"\"");
5548 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5557 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 {...@@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
55565565
5557 const init_node = try parseCExpr(c, m, scope);5566 const init_node = try parseCExpr(c, m, scope);
5558 const last = m.next().?;5567 const last = m.next().?;
5559 if (last != .Eof and last != .Nl)5568 if (last != .eof and last != .nl)
5560 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});5569 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
55615570
5562 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5571 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 {...@@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5578 defer block_scope.deinit();5587 defer block_scope.deinit();
5579 const scope = &block_scope.base;5588 const scope = &block_scope.base;
55805589
5581 try m.skip(c, .LParen);5590 try m.skip(c, .l_paren);
55825591
5583 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);5592 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
5584 defer fn_params.deinit();5593 defer fn_params.deinit();
55855594
5586 while (true) {5595 while (true) {
5587 if (m.peek().? != .Identifier) break;5596 switch (m.peek().?) {
5588 _ = m.next();5597 .identifier, .extended_identifier => _ = m.next(),
5598 else => break,
5599 }
55895600
5590 const mangled_name = try block_scope.makeMangledName(c, m.slice());5601 const mangled_name = try block_scope.makeMangledName(c, m.slice());
5591 try fn_params.append(.{5602 try fn_params.append(.{
...@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5594 .type = Tag.@"anytype".init(),5605 .type = Tag.@"anytype".init(),
5595 });5606 });
5596 try block_scope.discardVariable(c, mangled_name);5607 try block_scope.discardVariable(c, mangled_name);
5597 if (m.peek().? != .Comma) break;5608 if (m.peek().? != .comma) break;
5598 _ = m.next();5609 _ = m.next();
5599 }5610 }
56005611
5601 try m.skip(c, .RParen);5612 try m.skip(c, .r_paren);
56025613
5603 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {5614 if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) {
5604 .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}),5615 .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 {...@@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
56075618
5608 const expr = try parseCExpr(c, m, scope);5619 const expr = try parseCExpr(c, m, scope);
5609 const last = m.next().?;5620 const last = m.next().?;
5610 if (last != .Eof and last != .Nl)5621 if (last != .eof and last != .nl)
5611 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});5622 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
56125623
5613 const typeof_arg = if (expr.castTag(.block)) |some| blk: {5624 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
...@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5644 defer block_scope.deinit();5655 defer block_scope.deinit();
56455656
5646 const node = try parseCCondExpr(c, m, &block_scope.base);5657 const node = try parseCCondExpr(c, m, &block_scope.base);
5647 if (m.next().? != .Comma) {5658 if (m.next().? != .comma) {
5648 m.i -= 1;5659 m.i -= 1;
5649 return node;5660 return node;
5650 }5661 }
...@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5656 try block_scope.statements.append(ignore);5667 try block_scope.statements.append(ignore);
56575668
5658 last = try parseCCondExpr(c, m, &block_scope.base);5669 last = try parseCCondExpr(c, m, &block_scope.base);
5659 if (m.next().? != .Comma) {5670 if (m.next().? != .comma) {
5660 m.i -= 1;5671 m.i -= 1;
5661 break;5672 break;
5662 }5673 }
...@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5670 return try block_scope.complete(c);5681 return try block_scope.complete(c);
5671}5682}
56725683
5673fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {5684fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node {
5674 var lit_bytes = m.slice();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) {5688 const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes);
5677 .IntegerLiteral => |suffix| {5689 switch (prefix) {
5678 var base: []const u8 = "decimal";5690 .binary => bytes.appendSliceAssumeCapacity("0b"),
5679 if (lit_bytes.len >= 2 and lit_bytes[0] == '0') {5691 .octal => bytes.appendSliceAssumeCapacity("0o"),
5680 switch (lit_bytes[1]) {5692 .hex => bytes.appendSliceAssumeCapacity("0x"),
5681 '0'...'7' => {5693 .decimal => {},
5682 // Octal5694 }
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);
57305695
5731 if (guaranteed_to_fit) {5696 const after_prefix = lit_bytes[prefix.stringLen()..];
5732 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node });5697 const after_int = for (after_prefix, 0..) |c, i| switch (c) {
5733 } else {5698 '.' => {
5734 return Tag.helpers_promoteIntLiteral.create(c.arena, .{5699 if (i == 0) {
5735 .type = type_node,5700 bytes.appendAssumeCapacity('0');
5736 .value = literal_node,
5737 .base = try Tag.enum_literal.create(c.arena, base),
5738 });
5739 }5701 }
5702 break after_prefix[i..];
5740 },5703 },
5741 .FloatLiteral => |suffix| {5704 'e', 'E' => {
5742 if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1];5705 if (prefix != .hex) break after_prefix[i..];
57435706 bytes.appendAssumeCapacity(c);
5744 if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) {5707 },
5745 if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {5708 'p', 'P' => break after_prefix[i..],
5746 if (dot_index == 2) {5709 '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => {
5747 lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]});5710 if (!prefix.digitAllowed(c)) break after_prefix[i..];
5748 } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) {5711 bytes.appendAssumeCapacity(c);
5749 // If the literal lacks a digit after the `.`, we need to5712 },
5750 // add one since `0x1.p10` would be invalid syntax in Zig.5713 '\'' => {
5751 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{5714 bytes.appendAssumeCapacity('_');
5752 lit_bytes[2 .. dot_index + 1],5715 },
5753 lit_bytes[dot_index + 1 ..],5716 else => break after_prefix[i..],
5754 });5717 } else "";
5755 }
5756 }
57575718
5758 if (lit_bytes[1] == 'X') {5719 const after_frac = frac: {
5759 // Hexadecimal with capital X, valid in C but not in Zig5720 if (after_int.len == 0 or after_int[0] != '.') break :frac after_int;
5760 lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]});5721 bytes.appendAssumeCapacity('.');
5761 }5722 for (after_int[1..], 1..) |c, i| {
5762 } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| {5723 if (c == '\'') {
5763 if (dot_index == 0) {5724 bytes.appendAssumeCapacity('_');
5764 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});5725 continue;
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 }
5773 }5726 }
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) {5803 const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items);
5776 .f => "f32",5804 if (guaranteed_to_fit) {
5777 .none => "f64",5805 return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node });
5778 .l => "c_longdouble",5806 } else {
5779 else => unreachable,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)),
5780 });5811 });
5781 const rhs = try transCreateNodeNumber(c, lit_bytes, .float);5812 }
5782 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5783 },
5784 else => unreachable,
5785 }5813 }
5786}5814}
57875815
...@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5800 } else return source;5828 } else return source;
5801 var bytes = try ctx.arena.alloc(u8, source.len * 2);5829 var bytes = try ctx.arena.alloc(u8, source.len * 2);
5802 var state: enum {5830 var state: enum {
5803 Start,5831 start,
5804 Escape,5832 escape,
5805 Hex,5833 hex,
5806 Octal,5834 octal,
5807 } = .Start;5835 } = .start;
5808 var i: usize = 0;5836 var i: usize = 0;
5809 var count: u8 = 0;5837 var count: u8 = 0;
5810 var num: u8 = 0;5838 var num: u8 = 0;
5811 for (source) |c| {5839 for (source) |c| {
5812 switch (state) {5840 switch (state) {
5813 .Escape => {5841 .escape => {
5814 switch (c) {5842 switch (c) {
5815 'n', 'r', 't', '\\', '\'', '\"' => {5843 'n', 'r', 't', '\\', '\'', '\"' => {
5816 bytes[i] = c;5844 bytes[i] = c;
...@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5818 '0'...'7' => {5846 '0'...'7' => {
5819 count += 1;5847 count += 1;
5820 num += c - '0';5848 num += c - '0';
5821 state = .Octal;5849 state = .octal;
5822 bytes[i] = 'x';5850 bytes[i] = 'x';
5823 },5851 },
5824 'x' => {5852 'x' => {
5825 state = .Hex;5853 state = .hex;
5826 bytes[i] = 'x';5854 bytes[i] = 'x';
5827 },5855 },
5828 'a' => {5856 'a' => {
...@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5867 },5895 },
5868 }5896 }
5869 i += 1;5897 i += 1;
5870 if (state == .Escape)5898 if (state == .escape)
5871 state = .Start;5899 state = .start;
5872 },5900 },
5873 .Start => {5901 .start => {
5874 if (c == '\t') {5902 if (c == '\t') {
5875 bytes[i] = '\\';5903 bytes[i] = '\\';
5876 i += 1;5904 i += 1;
...@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5879 continue;5907 continue;
5880 }5908 }
5881 if (c == '\\') {5909 if (c == '\\') {
5882 state = .Escape;5910 state = .escape;
5883 }5911 }
5884 bytes[i] = c;5912 bytes[i] = c;
5885 i += 1;5913 i += 1;
5886 },5914 },
5887 .Hex => {5915 .hex => {
5888 switch (c) {5916 switch (c) {
5889 '0'...'9' => {5917 '0'...'9' => {
5890 num = std.math.mul(u8, num, 16) catch {5918 num = std.math.mul(u8, num, 16) catch {
...@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5911 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });5939 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5912 num = 0;5940 num = 0;
5913 if (c == '\\')5941 if (c == '\\')
5914 state = .Escape5942 state = .escape
5915 else5943 else
5916 state = .Start;5944 state = .start;
5917 bytes[i] = c;5945 bytes[i] = c;
5918 i += 1;5946 i += 1;
5919 },5947 },
5920 }5948 }
5921 },5949 },
5922 .Octal => {5950 .octal => {
5923 const accept_digit = switch (c) {5951 const accept_digit = switch (c) {
5924 // The maximum length of a octal literal is 3 digits5952 // The maximum length of a octal literal is 3 digits
5925 '0'...'7' => count < 3,5953 '0'...'7' => count < 3,
...@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
5938 num = 0;5966 num = 0;
5939 count = 0;5967 count = 0;
5940 if (c == '\\')5968 if (c == '\\')
5941 state = .Escape5969 state = .escape
5942 else5970 else
5943 state = .Start;5971 state = .start;
5944 bytes[i] = c;5972 bytes[i] = c;
5945 i += 1;5973 i += 1;
5946 }5974 }
5947 },5975 },
5948 }5976 }
5949 }5977 }
5950 if (state == .Hex or state == .Octal)5978 if (state == .hex or state == .octal)
5951 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });5979 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5952 return bytes[0..i];5980 return bytes[0..i];
5953}5981}
...@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5972 const tok = m.next().?;6000 const tok = m.next().?;
5973 const slice = m.slice();6001 const slice = m.slice();
5974 switch (tok) {6002 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 => {
5976 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {6009 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
5977 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));6010 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
5978 } else {6011 } else {
...@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5980 return Tag.integer_literal.create(c.arena, str);6013 return Tag.integer_literal.create(c.arena, str);
5981 }6014 }
5982 },6015 },
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 => {
5984 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));6022 return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m));
5985 },6023 },
5986 .IntegerLiteral, .FloatLiteral => {6024 .pp_num => {
5987 return parseCNumLit(c, m);6025 return parseCNumLit(c, m);
5988 },6026 },
5989 .Identifier => {6027 .identifier, .extended_identifier => {
5990 if (c.global_scope.blank_macros.contains(slice)) {6028 if (c.global_scope.blank_macros.contains(slice)) {
5991 return parseCPrimaryExprInner(c, m, scope);6029 return parseCPrimaryExprInner(c, m, scope);
5992 }6030 }
...@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5996 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);6034 scope.skipVariableDiscard(identifier.castTag(.identifier).?.data);
5997 return identifier;6035 return identifier;
5998 },6036 },
5999 .LParen => {6037 .l_paren => {
6000 const inner_node = try parseCExpr(c, m, scope);6038 const inner_node = try parseCExpr(c, m, scope);
60016039
6002 try m.skip(c, .RParen);6040 try m.skip(c, .r_paren);
6003 return inner_node;6041 return inner_node;
6004 },6042 },
6005 else => {6043 else => {
...@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6022 // after a primary expression.6060 // after a primary expression.
6023 while (true) {6061 while (true) {
6024 switch (m.peek().?) {6062 switch (m.peek().?) {
6025 .StringLiteral => {},6063 .string_literal,
6026 .Identifier => {6064 .string_literal_utf_16,
6065 .string_literal_utf_8,
6066 .string_literal_utf_32,
6067 .string_literal_wide,
6068 => {},
6069 .identifier, .extended_identifier => {
6027 const tok = m.list[m.i + 1];6070 const tok = m.list[m.i + 1];
6028 const slice = m.source[tok.start..tok.end];6071 const slice = m.source[tok.start..tok.end];
6029 if (c.global_scope.blank_macros.contains(slice)) {6072 if (c.global_scope.blank_macros.contains(slice)) {
...@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {...@@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node {
60576100
6058fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6101fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6059 const node = try parseCOrExpr(c, m, scope);6102 const node = try parseCOrExpr(c, m, scope);
6060 if (m.peek().? != .QuestionMark) {6103 if (m.peek().? != .question_mark) {
6061 return node;6104 return node;
6062 }6105 }
6063 _ = m.next();6106 _ = m.next();
60646107
6065 const then_body = try parseCOrExpr(c, m, scope);6108 const then_body = try parseCOrExpr(c, m, scope);
6066 try m.skip(c, .Colon);6109 try m.skip(c, .colon);
6067 const else_body = try parseCCondExpr(c, m, scope);6110 const else_body = try parseCCondExpr(c, m, scope);
6068 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });6111 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
6069}6112}
60706113
6071fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6114fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6072 var node = try parseCAndExpr(c, m, scope);6115 var node = try parseCAndExpr(c, m, scope);
6073 while (m.next().? == .PipePipe) {6116 while (m.next().? == .pipe_pipe) {
6074 const lhs = try macroIntToBool(c, node);6117 const lhs = try macroIntToBool(c, node);
6075 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));6118 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
6076 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });6119 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 {...@@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60816124
6082fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6125fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6083 var node = try parseCBitOrExpr(c, m, scope);6126 var node = try parseCBitOrExpr(c, m, scope);
6084 while (m.next().? == .AmpersandAmpersand) {6127 while (m.next().? == .ampersand_ampersand) {
6085 const lhs = try macroIntToBool(c, node);6128 const lhs = try macroIntToBool(c, node);
6086 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));6129 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
6087 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });6130 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 {...@@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
60926135
6093fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6136fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6094 var node = try parseCBitXorExpr(c, m, scope);6137 var node = try parseCBitXorExpr(c, m, scope);
6095 while (m.next().? == .Pipe) {6138 while (m.next().? == .pipe) {
6096 const lhs = try macroIntFromBool(c, node);6139 const lhs = try macroIntFromBool(c, node);
6097 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));6140 const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope));
6098 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6141 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 {...@@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61036146
6104fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6147fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6105 var node = try parseCBitAndExpr(c, m, scope);6148 var node = try parseCBitAndExpr(c, m, scope);
6106 while (m.next().? == .Caret) {6149 while (m.next().? == .caret) {
6107 const lhs = try macroIntFromBool(c, node);6150 const lhs = try macroIntFromBool(c, node);
6108 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));6151 const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope));
6109 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6152 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 {...@@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61146157
6115fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6158fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6116 var node = try parseCEqExpr(c, m, scope);6159 var node = try parseCEqExpr(c, m, scope);
6117 while (m.next().? == .Ampersand) {6160 while (m.next().? == .ampersand) {
6118 const lhs = try macroIntFromBool(c, node);6161 const lhs = try macroIntFromBool(c, node);
6119 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));6162 const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope));
6120 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6163 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 {...@@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6127 var node = try parseCRelExpr(c, m, scope);6170 var node = try parseCRelExpr(c, m, scope);
6128 while (true) {6171 while (true) {
6129 switch (m.peek().?) {6172 switch (m.peek().?) {
6130 .BangEqual => {6173 .bang_equal => {
6131 _ = m.next();6174 _ = m.next();
6132 const lhs = try macroIntFromBool(c, node);6175 const lhs = try macroIntFromBool(c, node);
6133 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));6176 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
6134 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6177 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6135 },6178 },
6136 .EqualEqual => {6179 .equal_equal => {
6137 _ = m.next();6180 _ = m.next();
6138 const lhs = try macroIntFromBool(c, node);6181 const lhs = try macroIntFromBool(c, node);
6139 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));6182 const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope));
...@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6148 var node = try parseCShiftExpr(c, m, scope);6191 var node = try parseCShiftExpr(c, m, scope);
6149 while (true) {6192 while (true) {
6150 switch (m.peek().?) {6193 switch (m.peek().?) {
6151 .AngleBracketRight => {6194 .angle_bracket_right => {
6152 _ = m.next();6195 _ = m.next();
6153 const lhs = try macroIntFromBool(c, node);6196 const lhs = try macroIntFromBool(c, node);
6154 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6197 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6155 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6198 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6156 },6199 },
6157 .AngleBracketRightEqual => {6200 .angle_bracket_right_equal => {
6158 _ = m.next();6201 _ = m.next();
6159 const lhs = try macroIntFromBool(c, node);6202 const lhs = try macroIntFromBool(c, node);
6160 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6203 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6161 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6204 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6162 },6205 },
6163 .AngleBracketLeft => {6206 .angle_bracket_left => {
6164 _ = m.next();6207 _ = m.next();
6165 const lhs = try macroIntFromBool(c, node);6208 const lhs = try macroIntFromBool(c, node);
6166 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6209 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
6167 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6210 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6168 },6211 },
6169 .AngleBracketLeftEqual => {6212 .angle_bracket_left_equal => {
6170 _ = m.next();6213 _ = m.next();
6171 const lhs = try macroIntFromBool(c, node);6214 const lhs = try macroIntFromBool(c, node);
6172 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));6215 const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope));
...@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6181 var node = try parseCAddSubExpr(c, m, scope);6224 var node = try parseCAddSubExpr(c, m, scope);
6182 while (true) {6225 while (true) {
6183 switch (m.peek().?) {6226 switch (m.peek().?) {
6184 .AngleBracketAngleBracketLeft => {6227 .angle_bracket_angle_bracket_left => {
6185 _ = m.next();6228 _ = m.next();
6186 const lhs = try macroIntFromBool(c, node);6229 const lhs = try macroIntFromBool(c, node);
6187 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));6230 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
6188 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6231 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6189 },6232 },
6190 .AngleBracketAngleBracketRight => {6233 .angle_bracket_angle_bracket_right => {
6191 _ = m.next();6234 _ = m.next();
6192 const lhs = try macroIntFromBool(c, node);6235 const lhs = try macroIntFromBool(c, node);
6193 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));6236 const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope));
...@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6202 var node = try parseCMulExpr(c, m, scope);6245 var node = try parseCMulExpr(c, m, scope);
6203 while (true) {6246 while (true) {
6204 switch (m.peek().?) {6247 switch (m.peek().?) {
6205 .Plus => {6248 .plus => {
6206 _ = m.next();6249 _ = m.next();
6207 const lhs = try macroIntFromBool(c, node);6250 const lhs = try macroIntFromBool(c, node);
6208 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));6251 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
6209 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6252 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6210 },6253 },
6211 .Minus => {6254 .minus => {
6212 _ = m.next();6255 _ = m.next();
6213 const lhs = try macroIntFromBool(c, node);6256 const lhs = try macroIntFromBool(c, node);
6214 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));6257 const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope));
...@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6223 var node = try parseCCastExpr(c, m, scope);6266 var node = try parseCCastExpr(c, m, scope);
6224 while (true) {6267 while (true) {
6225 switch (m.next().?) {6268 switch (m.next().?) {
6226 .Asterisk => {6269 .asterisk => {
6227 const lhs = try macroIntFromBool(c, node);6270 const lhs = try macroIntFromBool(c, node);
6228 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6271 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6229 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });6272 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6230 },6273 },
6231 .Slash => {6274 .slash => {
6232 const lhs = try macroIntFromBool(c, node);6275 const lhs = try macroIntFromBool(c, node);
6233 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6276 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6234 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });6277 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs });
6235 },6278 },
6236 .Percent => {6279 .percent => {
6237 const lhs = try macroIntFromBool(c, node);6280 const lhs = try macroIntFromBool(c, node);
6238 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6281 const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6239 node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs });6282 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 {...@@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62486291
6249fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6292fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6250 switch (m.next().?) {6293 switch (m.next().?) {
6251 .LParen => {6294 .l_paren => {
6252 if (try parseCTypeName(c, m, scope, true)) |type_name| {6295 if (try parseCTypeName(c, m, scope, true)) |type_name| {
6253 while (true) {6296 while (true) {
6254 const next_token = m.next().?;6297 const next_token = m.next().?;
6255 switch (next_token) {6298 switch (next_token) {
6256 .RParen => break,6299 .r_paren => break,
6257 else => |next_tag| {6300 else => |next_tag| {
6258 // Skip trailing blank defined before the RParen.6301 // 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()))
6260 continue;6304 continue;
6261 }6305
6262 try m.fail(6306 try m.fail(
6263 c,6307 c,
6264 "unable to translate C expr: expected ')' instead got '{s}'",6308 "unable to translate C expr: expected ')' instead got '{s}'",
...@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6268 },6312 },
6269 }6313 }
6270 }6314 }
6271 if (m.peek().? == .LBrace) {6315 if (m.peek().? == .l_brace) {
6272 // initializer list6316 // initializer list
6273 return parseCPostfixExpr(c, m, scope, type_name);6317 return parseCPostfixExpr(c, m, scope, type_name);
6274 }6318 }
...@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa...@@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa
6294fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {6338fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node {
6295 const tok = m.next().?;6339 const tok = m.next().?;
6296 switch (tok) {6340 switch (tok) {
6297 .Identifier => {6341 .identifier, .extended_identifier => {
6298 if (c.global_scope.blank_macros.contains(m.slice())) {6342 if (c.global_scope.blank_macros.contains(m.slice())) {
6299 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);6343 return try parseCSpecifierQualifierList(c, m, scope, allow_fail);
6300 }6344 }
...@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6304 return try Tag.identifier.create(c.arena, mangled_name);6348 return try Tag.identifier.create(c.arena, mangled_name);
6305 }6349 }
6306 },6350 },
6307 .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"),6351 .keyword_void => return try Tag.type.create(c.arena, "anyopaque"),
6308 .Keyword_bool => return try Tag.type.create(c.arena, "bool"),6352 .keyword_bool => return try Tag.type.create(c.arena, "bool"),
6309 .Keyword_char,6353 .keyword_char,
6310 .Keyword_int,6354 .keyword_int,
6311 .Keyword_short,6355 .keyword_short,
6312 .Keyword_long,6356 .keyword_long,
6313 .Keyword_float,6357 .keyword_float,
6314 .Keyword_double,6358 .keyword_double,
6315 .Keyword_signed,6359 .keyword_signed,
6316 .Keyword_unsigned,6360 .keyword_unsigned,
6317 .Keyword_complex,6361 .keyword_complex,
6318 => {6362 => {
6319 m.i -= 1;6363 m.i -= 1;
6320 return try parseCNumericType(c, m);6364 return try parseCNumericType(c, m);
6321 },6365 },
6322 .Keyword_enum, .Keyword_struct, .Keyword_union => {6366 .keyword_enum, .keyword_struct, .keyword_union => {
6323 // struct Foo will be declared as struct_Foo by transRecordDecl6367 // struct Foo will be declared as struct_Foo by transRecordDecl
6324 const slice = m.slice();6368 const slice = m.slice();
6325 try m.skip(c, .Identifier);6369 try m.skip(c, .identifier);
63266370
6327 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });6371 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
6328 return try Tag.identifier.create(c.arena, name);6372 return try Tag.identifier.create(c.arena, name);
...@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {...@@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
6364 var i: u8 = 0;6408 var i: u8 = 0;
6365 while (i < math.maxInt(u8)) : (i += 1) {6409 while (i < math.maxInt(u8)) : (i += 1) {
6366 switch (m.next().?) {6410 switch (m.next().?) {
6367 .Keyword_double => kw.double += 1,6411 .keyword_double => kw.double += 1,
6368 .Keyword_long => kw.long += 1,6412 .keyword_long => kw.long += 1,
6369 .Keyword_int => kw.int += 1,6413 .keyword_int => kw.int += 1,
6370 .Keyword_float => kw.float += 1,6414 .keyword_float => kw.float += 1,
6371 .Keyword_short => kw.short += 1,6415 .keyword_short => kw.short += 1,
6372 .Keyword_char => kw.char += 1,6416 .keyword_char => kw.char += 1,
6373 .Keyword_unsigned => kw.unsigned += 1,6417 .keyword_unsigned => kw.unsigned += 1,
6374 .Keyword_signed => kw.signed += 1,6418 .keyword_signed => kw.signed += 1,
6375 .Keyword_complex => kw.complex += 1,6419 .keyword_complex => kw.complex += 1,
6376 else => {6420 else => {
6377 m.i -= 1;6421 m.i -= 1;
6378 break;6422 break;
...@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {...@@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node {
64426486
6443fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {6487fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node {
6444 switch (m.next().?) {6488 switch (m.next().?) {
6445 .Asterisk => {6489 .asterisk => {
6446 // last token of `node`6490 // last token of `node`
6447 const prev_id = m.list[m.i - 1].id;6491 const prev_id = m.list[m.i - 1].id;
64486492
6449 if (prev_id == .Keyword_void) {6493 if (prev_id == .keyword_void) {
6450 const ptr = try Tag.single_pointer.create(c.arena, .{6494 const ptr = try Tag.single_pointer.create(c.arena, .{
6451 .is_const = false,6495 .is_const = false,
6452 .is_volatile = false,6496 .is_volatile = false,
...@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6472 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);6516 var node = type_name orelse try parseCPrimaryExpr(c, m, scope);
6473 while (true) {6517 while (true) {
6474 switch (m.next().?) {6518 switch (m.next().?) {
6475 .Period => {6519 .period => {
6476 try m.skip(c, .Identifier);6520 try m.skip(c, .identifier);
64776521
6478 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });6522 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
6479 },6523 },
6480 .Arrow => {6524 .arrow => {
6481 try m.skip(c, .Identifier);6525 try m.skip(c, .identifier);
64826526
6483 const deref = try Tag.deref.create(c.arena, node);6527 const deref = try Tag.deref.create(c.arena, node);
6484 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });6528 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
6485 },6529 },
6486 .LBracket => {6530 .l_bracket => {
6487 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));6531 const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope));
6488 const index = try Tag.as.create(c.arena, .{6532 const index = try Tag.as.create(c.arena, .{
6489 .lhs = try Tag.type.create(c.arena, "usize"),6533 .lhs = try Tag.type.create(c.arena, "usize"),
6490 .rhs = try Tag.int_cast.create(c.arena, index_val),6534 .rhs = try Tag.int_cast.create(c.arena, index_val),
6491 });6535 });
6492 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });6536 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);
6494 },6538 },
6495 .LParen => {6539 .l_paren => {
6496 if (m.peek().? == .RParen) {6540 if (m.peek().? == .r_paren) {
6497 m.i += 1;6541 m.i += 1;
6498 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });6542 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} });
6499 } else {6543 } else {
...@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6504 try args.append(arg);6548 try args.append(arg);
6505 const next_id = m.next().?;6549 const next_id = m.next().?;
6506 switch (next_id) {6550 switch (next_id) {
6507 .Comma => {},6551 .comma => {},
6508 .RParen => break,6552 .r_paren => break,
6509 else => {6553 else => {
6510 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});6554 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});
6511 return error.ParseError;6555 return error.ParseError;
...@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6515 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });6559 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
6516 }6560 }
6517 },6561 },
6518 .LBrace => {6562 .l_brace => {
6519 // Check for designated field initializers6563 // Check for designated field initializers
6520 if (m.peek().? == .Period) {6564 if (m.peek().? == .period) {
6521 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);6565 var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa);
6522 defer init_vals.deinit();6566 defer init_vals.deinit();
65236567
6524 while (true) {6568 while (true) {
6525 try m.skip(c, .Period);6569 try m.skip(c, .period);
6526 try m.skip(c, .Identifier);6570 try m.skip(c, .identifier);
6527 const name = m.slice();6571 const name = m.slice();
6528 try m.skip(c, .Equal);6572 try m.skip(c, .equal);
65296573
6530 const val = try parseCCondExpr(c, m, scope);6574 const val = try parseCCondExpr(c, m, scope);
6531 try init_vals.append(.{ .name = name, .value = val });6575 try init_vals.append(.{ .name = name, .value = val });
6532 const next_id = m.next().?;6576 const next_id = m.next().?;
6533 switch (next_id) {6577 switch (next_id) {
6534 .Comma => {},6578 .comma => {},
6535 .RBrace => break,6579 .r_brace => break,
6536 else => {6580 else => {
6537 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});6581 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6538 return error.ParseError;6582 return error.ParseError;
...@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6552 try init_vals.append(val);6596 try init_vals.append(val);
6553 const next_id = m.next().?;6597 const next_id = m.next().?;
6554 switch (next_id) {6598 switch (next_id) {
6555 .Comma => {},6599 .comma => {},
6556 .RBrace => break,6600 .r_brace => break,
6557 else => {6601 else => {
6558 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});6602 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6559 return error.ParseError;6603 return error.ParseError;
...@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6563 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));6607 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
6564 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });6608 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
6565 },6609 },
6566 .PlusPlus, .MinusMinus => {6610 .plus_plus, .minus_minus => {
6567 try m.fail(c, "TODO postfix inc/dec expr", .{});6611 try m.fail(c, "TODO postfix inc/dec expr", .{});
6568 return error.ParseError;6612 return error.ParseError;
6569 },6613 },
...@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
65776621
6578fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {6622fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6579 switch (m.next().?) {6623 switch (m.next().?) {
6580 .Bang => {6624 .bang => {
6581 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));6625 const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope));
6582 return Tag.not.create(c.arena, operand);6626 return Tag.not.create(c.arena, operand);
6583 },6627 },
6584 .Minus => {6628 .minus => {
6585 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6629 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6586 return Tag.negate.create(c.arena, operand);6630 return Tag.negate.create(c.arena, operand);
6587 },6631 },
6588 .Plus => return try parseCCastExpr(c, m, scope),6632 .plus => return try parseCCastExpr(c, m, scope),
6589 .Tilde => {6633 .tilde => {
6590 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));6634 const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope));
6591 return Tag.bit_not.create(c.arena, operand);6635 return Tag.bit_not.create(c.arena, operand);
6592 },6636 },
6593 .Asterisk => {6637 .asterisk => {
6594 const operand = try parseCCastExpr(c, m, scope);6638 const operand = try parseCCastExpr(c, m, scope);
6595 return Tag.deref.create(c.arena, operand);6639 return Tag.deref.create(c.arena, operand);
6596 },6640 },
6597 .Ampersand => {6641 .ampersand => {
6598 const operand = try parseCCastExpr(c, m, scope);6642 const operand = try parseCCastExpr(c, m, scope);
6599 return Tag.address_of.create(c.arena, operand);6643 return Tag.address_of.create(c.arena, operand);
6600 },6644 },
6601 .Keyword_sizeof => {6645 .keyword_sizeof => {
6602 const operand = if (m.peek().? == .LParen) blk: {6646 const operand = if (m.peek().? == .l_paren) blk: {
6603 _ = m.next();6647 _ = m.next();
6604 const inner = (try parseCTypeName(c, m, scope, false)).?;6648 const inner = (try parseCTypeName(c, m, scope, false)).?;
6605 try m.skip(c, .RParen);6649 try m.skip(c, .r_paren);
6606 break :blk inner;6650 break :blk inner;
6607 } else try parseCUnaryExpr(c, m, scope);6651 } else try parseCUnaryExpr(c, m, scope);
66086652
6609 return Tag.helpers_sizeof.create(c.arena, operand);6653 return Tag.helpers_sizeof.create(c.arena, operand);
6610 },6654 },
6611 .Keyword_alignof => {6655 .keyword_alignof => {
6612 // TODO this won't work if using <stdalign.h>'s6656 // TODO this won't work if using <stdalign.h>'s
6613 // #define alignof _Alignof6657 // #define alignof _Alignof
6614 try m.skip(c, .LParen);6658 try m.skip(c, .l_paren);
6615 const operand = (try parseCTypeName(c, m, scope, false)).?;6659 const operand = (try parseCTypeName(c, m, scope, false)).?;
6616 try m.skip(c, .RParen);6660 try m.skip(c, .r_paren);
66176661
6618 return Tag.alignof.create(c.arena, operand);6662 return Tag.alignof.create(c.arena, operand);
6619 },6663 },
6620 .PlusPlus, .MinusMinus => {6664 .plus_plus, .minus_minus => {
6621 try m.fail(c, "TODO unary inc/dec expr", .{});6665 try m.fail(c, "TODO unary inc/dec expr", .{});
6622 return error.ParseError;6666 return error.ParseError;
6623 },6667 },
test/translate_c.zig+7-7
...@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
424 \\ });424 \\ });
425 \\}425 \\}
426 ,426 ,
427 \\pub const B = A(@as(f32, 0.0));427 \\pub const B = A(@as(f32, 0));
428 });428 });
429429
430 cases.add("complex switch",430 cases.add("complex switch",
...@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
633 cases.add("#define hex literal with capital X",633 cases.add("#define hex literal with capital X",
634 \\#define VAL 0XF00D634 \\#define VAL 0XF00D
635 , &[_][]const u8{635 , &[_][]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);
637 });637 });
638638
639 cases.add("anonymous struct & unions",639 cases.add("anonymous struct & unions",
...@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;1243 \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l;
1244 , &([_][]const u8{1244 , &([_][]const u8{
1245 "pub const foo = @as(f32, 3.14);",1245 "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);",
1247 "pub const FOO = @as(f64, 0.12345);",1247 "pub const FOO = @as(f64, 0.12345);",
1248 "pub const BAR = @as(f64, 0.12345);",1248 "pub const BAR = @as(f64, 0.12345);",
1249 "pub const baz = @as(f64, 1e1);",1249 "pub const baz = @as(f64, 1e1);",
1250 "pub const BAZ = @as(f32, 42e-3);",1250 "pub const BAZ = @as(f32, 42e-3);",
1251 "pub const foobar = -@as(c_longdouble, 73.0);",1251 "pub const foobar = -@as(c_longdouble, 73);",
1252 "pub export const my_float: f32 = 1.0;",1252 "pub export const my_float: f32 = 1.0;",
1253 "pub export const my_double: f64 = 1.0;",1253 "pub export const my_double: f64 = 1.0;",
1254 "pub export const my_longdouble: c_longdouble = 1.0;",1254 "pub export const my_longdouble: c_longdouble = 1.0;",
...@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1272 "pub const BAR = -@as(f32, 0x8F.BP5);",1272 "pub const BAR = -@as(f32, 0x8F.BP5);",
1273 "pub const FOOBAR = @as(f64, 0x0P+0);",1273 "pub const FOOBAR = @as(f64, 0x0P+0);",
1274 "pub const BAZ = -@as(f64, 0x0.0a5dp+12);",1274 "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);",
1276 });1276 });
12771277
1278 cases.add("comments",1278 cases.add("comments",
...@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3730 , &[_][]const u8{3730 , &[_][]const u8{
3731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));3731 \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0));
3732 ,3732 ,
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));
3734 });3734 });
37353735
3736 if (builtin.abi == .msvc) {3736 if (builtin.abi == .msvc) {
...@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);3812 \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal);
3813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);3813 \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal);
3814 \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal);3814 \\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);
3816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);3816 \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal);
3817 });3817 });
38183818