authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-16 10:55:32-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-12-16 10:55:32-05:00
log0f09ff49235e77af06056d3b5cdca0098aa050c3
tree011e513a74d7250994a34424e3bb7105674692f8
parent650acc5e3d50f8fae82bfb8bddf297d1927f40d4
parent04dc0bd0e4f7bc7c23e9d0e30b5d2b6153e2c0d5
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3916 from Vexu/translate-c-2

Translate-c-2 macros

5 files changed, 2176 insertions(+), 709 deletions(-)

src-self-hosted/c_tokenizer.zig created+656
...@@ -0,0 +1,656 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4pub const TokenList = std.SegmentedList(CToken, 32);
5
6pub const CToken = struct {
7 id: Id,
8 bytes: []const u8,
9 num_lit_suffix: NumLitSuffix = .None,
10
11 pub const Id = enum {
12 CharLit,
13 StrLit,
14 NumLitInt,
15 NumLitFloat,
16 Identifier,
17 Minus,
18 Slash,
19 LParen,
20 RParen,
21 Eof,
22 Dot,
23 Asterisk,
24 Bang,
25 Tilde,
26 Shl,
27 Lt,
28 Comma,
29 Fn,
30 };
31
32 pub const NumLitSuffix = enum {
33 None,
34 F,
35 L,
36 U,
37 LU,
38 LL,
39 LLU,
40 };
41};
42
43pub fn tokenizeCMacro(tl: *TokenList, chars: [*:0]const u8) !void {
44 var index: usize = 0;
45 var first = true;
46 while (true) {
47 const tok = try next(chars, &index);
48 if (tok.id == .StrLit or tok.id == .CharLit)
49 try tl.push(try zigifyEscapeSequences(tl.allocator, tok))
50 else
51 try tl.push(tok);
52 if (tok.id == .Eof)
53 return;
54 if (first) {
55 // distinguish NAME (EXPR) from NAME(ARGS)
56 first = false;
57 if (chars[index] == '(') {
58 try tl.push(.{
59 .id = .Fn,
60 .bytes = "",
61 });
62 }
63 }
64 }
65}
66
67fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken {
68 for (tok.bytes) |c| {
69 if (c == '\\') {
70 break;
71 }
72 } else return tok;
73 var bytes = try allocator.alloc(u8, tok.bytes.len * 2);
74 var escape = false;
75 var i: usize = 0;
76 for (tok.bytes) |c| {
77 if (escape) {
78 switch (c) {
79 'n', 'r', 't', '\\', '\'', '\"', 'x' => {
80 bytes[i] = c;
81 },
82 'a' => {
83 bytes[i] = 'x';
84 i += 1;
85 bytes[i] = '0';
86 i += 1;
87 bytes[i] = '7';
88 },
89 'b' => {
90 bytes[i] = 'x';
91 i += 1;
92 bytes[i] = '0';
93 i += 1;
94 bytes[i] = '8';
95 },
96 'f' => {
97 bytes[i] = 'x';
98 i += 1;
99 bytes[i] = '0';
100 i += 1;
101 bytes[i] = 'C';
102 },
103 'v' => {
104 bytes[i] = 'x';
105 i += 1;
106 bytes[i] = '0';
107 i += 1;
108 bytes[i] = 'B';
109 },
110 '?' => {
111 i -= 1;
112 bytes[i] = '?';
113 },
114 'u', 'U' => {
115 // TODO unicode escape sequences
116 return error.TokenizingFailed;
117 },
118 '0'...'7' => {
119 // TODO octal escape sequences
120 return error.TokenizingFailed;
121 },
122 else => {
123 // unknown escape sequence
124 return error.TokenizingFailed;
125 },
126 }
127 i += 1;
128 escape = false;
129 } else {
130 if (c == '\\') {
131 escape = true;
132 }
133 bytes[i] = c;
134 i += 1;
135 }
136 }
137 return CToken{
138 .id = tok.id,
139 .bytes = bytes[0..i],
140 };
141}
142
143fn next(chars: [*:0]const u8, i: *usize) !CToken {
144 var state: enum {
145 Start,
146 GotLt,
147 CharLit,
148 OpenComment,
149 Comment,
150 CommentStar,
151 Backslash,
152 String,
153 Identifier,
154 Decimal,
155 Octal,
156 GotZero,
157 Hex,
158 Bin,
159 Float,
160 ExpSign,
161 FloatExp,
162 FloatExpFirst,
163 NumLitIntSuffixU,
164 NumLitIntSuffixL,
165 NumLitIntSuffixLL,
166 NumLitIntSuffixUL,
167 } = .Start;
168
169 var result = CToken{
170 .bytes = "",
171 .id = .Eof,
172 };
173 var begin_index: usize = 0;
174 var digits: u8 = 0;
175 var pre_escape = state;
176
177 while (true) {
178 const c = chars[i.*];
179 if (c == 0) {
180 switch (state) {
181 .Start => {
182 return result;
183 },
184 .Identifier,
185 .Decimal,
186 .Hex,
187 .Bin,
188 .Octal,
189 .GotZero,
190 .Float,
191 .FloatExp,
192 => {
193 result.bytes = chars[begin_index..i.*];
194 return result;
195 },
196 .NumLitIntSuffixU,
197 .NumLitIntSuffixL,
198 .NumLitIntSuffixUL,
199 .NumLitIntSuffixLL,
200 .GotLt,
201 => {
202 return result;
203 },
204 .CharLit,
205 .OpenComment,
206 .Comment,
207 .CommentStar,
208 .Backslash,
209 .String,
210 .ExpSign,
211 .FloatExpFirst,
212 => return error.TokenizingFailed,
213 }
214 }
215 i.* += 1;
216 switch (state) {
217 .Start => {
218 switch (c) {
219 ' ', '\t', '\x0B', '\x0C' => {},
220 '\'' => {
221 state = .CharLit;
222 result.id = .CharLit;
223 begin_index = i.* - 1;
224 },
225 '\"' => {
226 state = .String;
227 result.id = .StrLit;
228 begin_index = i.* - 1;
229 },
230 '/' => {
231 state = .OpenComment;
232 },
233 '\\' => {
234 state = .Backslash;
235 },
236 '\n', '\r' => {
237 return result;
238 },
239 'a'...'z', 'A'...'Z', '_' => {
240 state = .Identifier;
241 result.id = .Identifier;
242 begin_index = i.* - 1;
243 },
244 '1'...'9' => {
245 state = .Decimal;
246 result.id = .NumLitInt;
247 begin_index = i.* - 1;
248 },
249 '0' => {
250 state = .GotZero;
251 result.id = .NumLitInt;
252 begin_index = i.* - 1;
253 },
254 '.' => {
255 result.id = .Dot;
256 return result;
257 },
258 '<' => {
259 result.id = .Lt;
260 state = .GotLt;
261 },
262 '(' => {
263 result.id = .LParen;
264 return result;
265 },
266 ')' => {
267 result.id = .RParen;
268 return result;
269 },
270 '*' => {
271 result.id = .Asterisk;
272 return result;
273 },
274 '-' => {
275 result.id = .Minus;
276 return result;
277 },
278 '!' => {
279 result.id = .Bang;
280 return result;
281 },
282 '~' => {
283 result.id = .Tilde;
284 return result;
285 },
286 ',' => {
287 result.id = .Comma;
288 return result;
289 },
290 else => return error.TokenizingFailed,
291 }
292 },
293 .GotLt => {
294 switch (c) {
295 '<' => {
296 result.id = .Shl;
297 return result;
298 },
299 else => {
300 return result;
301 },
302 }
303 },
304 .Float => {
305 switch (c) {
306 '.', '0'...'9' => {},
307 'e', 'E' => {
308 state = .ExpSign;
309 },
310 'f',
311 'F',
312 => {
313 i.* -= 1;
314 result.num_lit_suffix = .F;
315 result.bytes = chars[begin_index..i.*];
316 return result;
317 },
318 'l', 'L' => {
319 i.* -= 1;
320 result.num_lit_suffix = .L;
321 result.bytes = chars[begin_index..i.*];
322 return result;
323 },
324 else => {
325 i.* -= 1;
326 result.bytes = chars[begin_index..i.*];
327 return result;
328 },
329 }
330 },
331 .ExpSign => {
332 switch (c) {
333 '+', '-' => {
334 state = .FloatExpFirst;
335 },
336 '0'...'9' => {
337 state = .FloatExp;
338 },
339 else => return error.TokenizingFailed,
340 }
341 },
342 .FloatExpFirst => {
343 switch (c) {
344 '0'...'9' => {
345 state = .FloatExp;
346 },
347 else => return error.TokenizingFailed,
348 }
349 },
350 .FloatExp => {
351 switch (c) {
352 '0'...'9' => {},
353 'f', 'F' => {
354 result.num_lit_suffix = .F;
355 result.bytes = chars[begin_index .. i.* - 1];
356 return result;
357 },
358 'l', 'L' => {
359 result.num_lit_suffix = .L;
360 result.bytes = chars[begin_index .. i.* - 1];
361 return result;
362 },
363 else => {
364 i.* -= 1;
365 result.bytes = chars[begin_index..i.*];
366 return result;
367 },
368 }
369 },
370 .Decimal => {
371 switch (c) {
372 '0'...'9' => {},
373 '\'' => {},
374 'u', 'U' => {
375 state = .NumLitIntSuffixU;
376 result.num_lit_suffix = .U;
377 result.bytes = chars[begin_index .. i.* - 1];
378 },
379 'l', 'L' => {
380 state = .NumLitIntSuffixL;
381 result.num_lit_suffix = .L;
382 result.bytes = chars[begin_index .. i.* - 1];
383 },
384 '.' => {
385 result.id = .NumLitFloat;
386 state = .Float;
387 },
388 else => {
389 i.* -= 1;
390 result.bytes = chars[begin_index..i.*];
391 return result;
392 },
393 }
394 },
395 .GotZero => {
396 switch (c) {
397 'x', 'X' => {
398 state = .Hex;
399 },
400 'b', 'B' => {
401 state = .Bin;
402 },
403 '.' => {
404 state = .Float;
405 result.id = .NumLitFloat;
406 },
407 'u', 'U' => {
408 state = .NumLitIntSuffixU;
409 result.num_lit_suffix = .U;
410 result.bytes = chars[begin_index .. i.* - 1];
411 },
412 'l', 'L' => {
413 state = .NumLitIntSuffixL;
414 result.num_lit_suffix = .L;
415 result.bytes = chars[begin_index .. i.* - 1];
416 },
417 else => {
418 i.* -= 1;
419 state = .Octal;
420 },
421 }
422 },
423 .Octal => {
424 switch (c) {
425 '0'...'7' => {},
426 '8', '9' => return error.TokenizingFailed,
427 else => {
428 i.* -= 1;
429 result.bytes = chars[begin_index..i.*];
430 return result;
431 },
432 }
433 },
434 .Hex => {
435 switch (c) {
436 '0'...'9', 'a'...'f', 'A'...'F' => {},
437 'u', 'U' => {
438 // marks the number literal as unsigned
439 state = .NumLitIntSuffixU;
440 result.num_lit_suffix = .U;
441 result.bytes = chars[begin_index .. i.* - 1];
442 },
443 'l', 'L' => {
444 // marks the number literal as long
445 state = .NumLitIntSuffixL;
446 result.num_lit_suffix = .L;
447 result.bytes = chars[begin_index .. i.* - 1];
448 },
449 else => {
450 i.* -= 1;
451 result.bytes = chars[begin_index..i.*];
452 return result;
453 },
454 }
455 },
456 .Bin => {
457 switch (c) {
458 '0'...'1' => {},
459 '2'...'9' => return error.TokenizingFailed,
460 'u', 'U' => {
461 // marks the number literal as unsigned
462 state = .NumLitIntSuffixU;
463 result.num_lit_suffix = .U;
464 result.bytes = chars[begin_index .. i.* - 1];
465 },
466 'l', 'L' => {
467 // marks the number literal as long
468 state = .NumLitIntSuffixL;
469 result.num_lit_suffix = .L;
470 result.bytes = chars[begin_index .. i.* - 1];
471 },
472 else => {
473 i.* -= 1;
474 result.bytes = chars[begin_index..i.*];
475 return result;
476 },
477 }
478 },
479 .NumLitIntSuffixU => {
480 switch (c) {
481 'l', 'L' => {
482 result.num_lit_suffix = .LU;
483 state = .NumLitIntSuffixUL;
484 },
485 else => {
486 i.* -= 1;
487 return result;
488 },
489 }
490 },
491 .NumLitIntSuffixL => {
492 switch (c) {
493 'l', 'L' => {
494 result.num_lit_suffix = .LL;
495 state = .NumLitIntSuffixLL;
496 },
497 'u', 'U' => {
498 result.num_lit_suffix = .LU;
499 return result;
500 },
501 else => {
502 i.* -= 1;
503 return result;
504 },
505 }
506 },
507 .NumLitIntSuffixLL => {
508 switch (c) {
509 'u', 'U' => {
510 result.num_lit_suffix = .LLU;
511 return result;
512 },
513 else => {
514 i.* -= 1;
515 return result;
516 },
517 }
518 },
519 .NumLitIntSuffixUL => {
520 switch (c) {
521 'l', 'L' => {
522 result.num_lit_suffix = .LLU;
523 return result;
524 },
525 else => {
526 i.* -= 1;
527 return result;
528 },
529 }
530 },
531 .Identifier => {
532 switch (c) {
533 '_', 'a'...'z', 'A'...'Z', '0'...'9' => {},
534 else => {
535 i.* -= 1;
536 result.bytes = chars[begin_index..i.*];
537 return result;
538 },
539 }
540 },
541 .String => { // TODO char escapes
542 switch (c) {
543 '\"' => {
544 result.bytes = chars[begin_index..i.*];
545 return result;
546 },
547 else => {},
548 }
549 },
550 .CharLit => {
551 switch (c) {
552 '\'' => {
553 result.bytes = chars[begin_index..i.*];
554 return result;
555 },
556 else => {},
557 }
558 },
559 .OpenComment => {
560 switch (c) {
561 '/' => {
562 return result;
563 },
564 '*' => {
565 state = .Comment;
566 },
567 else => {
568 result.id = .Slash;
569 return result;
570 },
571 }
572 },
573 .Comment => {
574 switch (c) {
575 '*' => {
576 state = .CommentStar;
577 },
578 else => {},
579 }
580 },
581 .CommentStar => {
582 switch (c) {
583 '/' => {
584 state = .Start;
585 },
586 else => {
587 state = .Comment;
588 },
589 }
590 },
591 .Backslash => {
592 switch (c) {
593 ' ', '\t', '\x0B', '\x0C' => {},
594 '\n', '\r' => {
595 state = .Start;
596 },
597 else => return error.TokenizingFailed,
598 }
599 },
600 }
601 }
602 unreachable;
603}
604
605test "tokenize macro" {
606 var tl = TokenList.init(std.heap.page_allocator);
607 defer tl.deinit();
608
609 const src = "TEST(0\n";
610 try tokenizeCMacro(&tl, src);
611 var it = tl.iterator(0);
612 expect(it.next().?.id == .Identifier);
613 expect(it.next().?.id == .Fn);
614 expect(it.next().?.id == .LParen);
615 expect(std.mem.eql(u8, it.next().?.bytes, "0"));
616 expect(it.next().?.id == .Eof);
617 expect(it.next() == null);
618 tl.shrink(0);
619
620 const src2 = "__FLT_MIN_10_EXP__ -37\n";
621 try tokenizeCMacro(&tl, src2);
622 it = tl.iterator(0);
623 expect(std.mem.eql(u8, it.next().?.bytes, "__FLT_MIN_10_EXP__"));
624 expect(it.next().?.id == .Minus);
625 expect(std.mem.eql(u8, it.next().?.bytes, "37"));
626 expect(it.next().?.id == .Eof);
627 expect(it.next() == null);
628 tl.shrink(0);
629
630 const src3 = "__llvm__ 1\n#define";
631 try tokenizeCMacro(&tl, src3);
632 it = tl.iterator(0);
633 expect(std.mem.eql(u8, it.next().?.bytes, "__llvm__"));
634 expect(std.mem.eql(u8, it.next().?.bytes, "1"));
635 expect(it.next().?.id == .Eof);
636 expect(it.next() == null);
637 tl.shrink(0);
638
639 const src4 = "TEST 2";
640 try tokenizeCMacro(&tl, src4);
641 it = tl.iterator(0);
642 expect(it.next().?.id == .Identifier);
643 expect(std.mem.eql(u8, it.next().?.bytes, "2"));
644 expect(it.next().?.id == .Eof);
645 expect(it.next() == null);
646 tl.shrink(0);
647
648 const src5 = "FOO 0l";
649 try tokenizeCMacro(&tl, src5);
650 it = tl.iterator(0);
651 expect(it.next().?.id == .Identifier);
652 expect(std.mem.eql(u8, it.next().?.bytes, "0"));
653 expect(it.next().?.id == .Eof);
654 expect(it.next() == null);
655 tl.shrink(0);
656}
src-self-hosted/clang.zig+31-9
...@@ -75,6 +75,7 @@ pub const struct_ZigClangWhileStmt = @OpaqueType();...@@ -75,6 +75,7 @@ pub const struct_ZigClangWhileStmt = @OpaqueType();
75pub const struct_ZigClangFunctionType = @OpaqueType();75pub const struct_ZigClangFunctionType = @OpaqueType();
76pub const struct_ZigClangPredefinedExpr = @OpaqueType();76pub const struct_ZigClangPredefinedExpr = @OpaqueType();
77pub const struct_ZigClangInitListExpr = @OpaqueType();77pub const struct_ZigClangInitListExpr = @OpaqueType();
78pub const ZigClangPreprocessingRecord = @OpaqueType();
7879
79pub const ZigClangBO = extern enum {80pub const ZigClangBO = extern enum {
80 PtrMemD,81 PtrMemD,
...@@ -717,11 +718,23 @@ pub const ZigClangEnumDecl_enumerator_iterator = extern struct {...@@ -717,11 +718,23 @@ pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
717 opaque: *c_void,718 opaque: *c_void,
718};719};
719720
721pub const ZigClangPreprocessingRecord_iterator = extern struct {
722 I: c_int,
723 Self: *ZigClangPreprocessingRecord,
724};
725
726pub const ZigClangPreprocessedEntity_EntityKind = extern enum {
727 InvalidKind,
728 MacroExpansionKind,
729 MacroDefinitionKind,
730 InclusionDirectiveKind,
731};
732
720pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;733pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
721pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;734pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
722pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;735pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
723pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;736pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
724pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*c]const u8;737pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*:0]const u8;
725pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;738pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
726pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;739pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
727pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;740pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
...@@ -751,14 +764,14 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE...@@ -751,14 +764,14 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE
751pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;764pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;
752pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;765pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;
753pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool;766pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool;
754pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8;767pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*:0]const u8;
755pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;768pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
756pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;769pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
757pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType;770pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType;
758pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType;771pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType;
759pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass;772pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass;
760pub extern fn ZigClangQualType_getTypePtr(self: struct_ZigClangQualType) *const struct_ZigClangType;773pub extern fn ZigClangQualType_getTypePtr(self: struct_ZigClangQualType) *const struct_ZigClangType;
761pub extern fn ZigClangQualType_addConst(self: [*c]struct_ZigClangQualType) void;774pub extern fn ZigClangQualType_addConst(self: *struct_ZigClangQualType) void;
762pub extern fn ZigClangQualType_eq(self: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool;775pub extern fn ZigClangQualType_eq(self: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool;
763pub extern fn ZigClangQualType_isConstQualified(self: struct_ZigClangQualType) bool;776pub extern fn ZigClangQualType_isConstQualified(self: struct_ZigClangQualType) bool;
764pub extern fn ZigClangQualType_isVolatileQualified(self: struct_ZigClangQualType) bool;777pub extern fn ZigClangQualType_isVolatileQualified(self: struct_ZigClangQualType) bool;
...@@ -786,7 +799,7 @@ pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;...@@ -786,7 +799,7 @@ pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;
786pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;799pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;
787pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;800pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;
788pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;801pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;
789pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*c]const u64;802pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64;
790pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;803pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;
791804
792pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;805pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;
...@@ -918,25 +931,25 @@ pub const struct_ZigClangAPValueLValueBase = extern struct {...@@ -918,25 +931,25 @@ pub const struct_ZigClangAPValueLValueBase = extern struct {
918 Version: c_uint,931 Version: c_uint,
919};932};
920933
921pub extern fn ZigClangErrorMsg_delete(ptr: [*c]Stage2ErrorMsg, len: usize) void;934pub extern fn ZigClangErrorMsg_delete(ptr: [*]Stage2ErrorMsg, len: usize) void;
922935
923pub extern fn ZigClangLoadFromCommandLine(936pub extern fn ZigClangLoadFromCommandLine(
924 args_begin: [*]?[*]const u8,937 args_begin: [*]?[*]const u8,
925 args_end: [*]?[*]const u8,938 args_end: [*]?[*]const u8,
926 errors_ptr: *[*]Stage2ErrorMsg,939 errors_ptr: *[*]Stage2ErrorMsg,
927 errors_len: *usize,940 errors_len: *usize,
928 resources_path: [*c]const u8,941 resources_path: [*:0]const u8,
929) ?*ZigClangASTUnit;942) ?*ZigClangASTUnit;
930943
931pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;944pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;
932pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8;945pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8;
933946
934pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt;947pub const ZigClangCompoundStmt_const_body_iterator = [*]const *struct_ZigClangStmt;
935948
936pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;949pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
937pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;950pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
938951
939pub const ZigClangDeclStmt_const_decl_iterator = [*c]const *struct_ZigClangDecl;952pub const ZigClangDeclStmt_const_decl_iterator = [*]const *struct_ZigClangDecl;
940953
941pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;954pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
942pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;955pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
...@@ -1004,7 +1017,7 @@ pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigC...@@ -1004,7 +1017,7 @@ pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigC
1004pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType;1017pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType;
10051018
1006pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind;1019pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind;
1007pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8;1020pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*]const u8;
10081021
1009pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;1022pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;
10101023
...@@ -1014,3 +1027,12 @@ pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) str...@@ -1014,3 +1027,12 @@ pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) str
10141027
1015pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr;1028pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr;
1016pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt;1029pub extern fn ZigClangEnumConstantDecl_getInitVal(*const ZigClangEnumConstantDecl) *const ZigClangAPSInt;
1030
1031pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_begin(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator;
1032pub extern fn ZigClangASTUnit_getLocalPreprocessingEntities_end(*ZigClangASTUnit) ZigClangPreprocessingRecord_iterator;
1033pub extern fn ZigClangPreprocessingRecord_iterator_deref(ZigClangPreprocessingRecord_iterator) *ZigClangPreprocessedEntity;
1034pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEntity) ZigClangPreprocessedEntity_EntityKind;
1035
1036pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8;
1037pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
1038pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
src-self-hosted/stage1.zig+1-1
...@@ -93,7 +93,7 @@ export fn stage2_translate_c(...@@ -93,7 +93,7 @@ export fn stage2_translate_c(
93 out_errors_len: *usize,93 out_errors_len: *usize,
94 args_begin: [*]?[*]const u8,94 args_begin: [*]?[*]const u8,
95 args_end: [*]?[*]const u8,95 args_end: [*]?[*]const u8,
96 resources_path: [*]const u8,96 resources_path: [*:0]const u8,
97) Error {97) Error {
98 var errors: []translate_c.ClangErrMsg = undefined;98 var errors: []translate_c.ClangErrMsg = undefined;
99 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {99 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
src-self-hosted/translate_c.zig+929-291
...@@ -6,6 +6,8 @@ const assert = std.debug.assert;...@@ -6,6 +6,8 @@ const assert = std.debug.assert;
6const ast = std.zig.ast;6const ast = std.zig.ast;
7const Token = std.zig.Token;7const Token = std.zig.Token;
8usingnamespace @import("clang.zig");8usingnamespace @import("clang.zig");
9const ctok = @import("c_tokenizer.zig");
10const CToken = ctok.CToken;
911
10const CallingConvention = std.builtin.TypeInfo.CallingConvention;12const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1113
...@@ -31,7 +33,7 @@ fn addrEql(a: usize, b: usize) bool {...@@ -31,7 +33,7 @@ fn addrEql(a: usize, b: usize) bool {
31 return a == b;33 return a == b;
32}34}
3335
34const SymbolTable = std.StringHashMap(void);36const SymbolTable = std.StringHashMap(*ast.Node);
35const AliasList = std.SegmentedList(struct {37const AliasList = std.SegmentedList(struct {
36 alias: []const u8,38 alias: []const u8,
37 name: []const u8,39 name: []const u8,
...@@ -43,59 +45,151 @@ const Scope = struct {...@@ -43,59 +45,151 @@ const Scope = struct {
4345
44 const Id = enum {46 const Id = enum {
45 Switch,47 Switch,
46 Var,
47 Block,48 Block,
48 Root,49 Root,
49 While,50 While,
51 FnDef,
52 Ref,
50 };53 };
54
51 const Switch = struct {55 const Switch = struct {
52 base: Scope,56 base: Scope,
53 };57 };
5458
55 const Var = struct {59 /// used when getting a member `a.b`
60 const Ref = struct {
56 base: Scope,61 base: Scope,
57 c_name: []const u8,
58 zig_name: []const u8,
59 };62 };
6063
61 const Block = struct {64 const Block = struct {
62 base: Scope,65 base: Scope,
63 block_node: *ast.Node.Block,66 block_node: *ast.Node.Block,
67 variables: AliasList,
6468
65 /// Don't forget to set rbrace token later69 /// Don't forget to set rbrace token later
66 fn create(c: *Context, parent: *Scope, lbrace_tok: ast.TokenIndex) !*Block {70 fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block {
67 const block = try c.a().create(Block);71 const block = try c.a().create(Block);
68 block.* = Block{72 block.* = .{
69 .base = Scope{73 .base = .{
70 .id = Id.Block,74 .id = .Block,
71 .parent = parent,75 .parent = parent,
72 },76 },
73 .block_node = try c.a().create(ast.Node.Block),77 .block_node = block_node,
74 };78 .variables = AliasList.init(c.a()),
75 block.block_node.* = ast.Node.Block{
76 .base = ast.Node{ .id = ast.Node.Id.Block },
77 .label = null,
78 .lbrace = lbrace_tok,
79 .statements = ast.Node.Block.StatementList.init(c.a()),
80 .rbrace = undefined,
81 };79 };
82 return block;80 return block;
83 }81 }
82
83 fn getAlias(scope: *Block, name: []const u8) ?[]const u8 {
84 var it = scope.variables.iterator(0);
85 while (it.next()) |p| {
86 if (std.mem.eql(u8, p.name, name))
87 return p.alias;
88 }
89 return scope.base.parent.?.getAlias(name);
90 }
91
92 fn contains(scope: *Block, name: []const u8) bool {
93 var it = scope.variables.iterator(0);
94 while (it.next()) |p| {
95 if (std.mem.eql(u8, p.name, name))
96 return true;
97 }
98 return scope.base.parent.?.contains(name);
99 }
84 };100 };
85101
86 const Root = struct {102 const Root = struct {
87 base: Scope,103 base: Scope,
104 sym_table: SymbolTable,
105 macro_table: SymbolTable,
106
107 fn init(c: *Context) Root {
108 return .{
109 .base = .{
110 .id = .Root,
111 .parent = null,
112 },
113 .sym_table = SymbolTable.init(c.a()),
114 .macro_table = SymbolTable.init(c.a()),
115 };
116 }
117
118 fn contains(scope: *Root, name: []const u8) bool {
119 return scope.sym_table.contains(name) or scope.macro_table.contains(name);
120 }
88 };121 };
89122
90 const While = struct {123 const While = struct {
91 base: Scope,124 base: Scope,
92 };125 };
93};
94126
95const TransResult = struct {127 const FnDef = struct {
96 node: *ast.Node,128 base: Scope,
97 node_scope: *Scope,129 params: AliasList,
98 child_scope: *Scope,130
131 fn init(c: *Context) FnDef {
132 return .{
133 .base = .{
134 .id = .FnDef,
135 .parent = &c.global_scope.base,
136 },
137 .params = AliasList.init(c.a()),
138 };
139 }
140
141 fn getAlias(scope: *FnDef, name: []const u8) ?[]const u8 {
142 var it = scope.params.iterator(0);
143 while (it.next()) |p| {
144 if (std.mem.eql(u8, p.name, name))
145 return p.alias;
146 }
147 return scope.base.parent.?.getAlias(name);
148 }
149
150 fn contains(scope: *FnDef, name: []const u8) bool {
151 var it = scope.params.iterator(0);
152 while (it.next()) |p| {
153 if (std.mem.eql(u8, p.name, name))
154 return true;
155 }
156 return scope.base.parent.?.contains(name);
157 }
158 };
159
160 fn findBlockScope(inner: *Scope) *Scope.Block {
161 var scope = inner;
162 while (true) : (scope = scope.parent orelse unreachable) {
163 if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope);
164 }
165 }
166
167 fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 {
168 if (scope.contains(name)) {
169 return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() });
170 }
171 return null;
172 }
173
174 fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 {
175 return switch (scope.id) {
176 .Root => null,
177 .Ref => null,
178 .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
179 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
180 else => @panic("TODO Scope.getAlias"),
181 };
182 }
183
184 fn contains(scope: *Scope, name: []const u8) bool {
185 return switch (scope.id) {
186 .Ref => false,
187 .Root => @fieldParentPtr(Root, "base", scope).contains(name),
188 .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
189 .Block => @fieldParentPtr(Block, "base", scope).contains(name),
190 else => @panic("TODO Scope.contains"),
191 };
192 }
99};193};
100194
101const Context = struct {195const Context = struct {
...@@ -105,7 +199,6 @@ const Context = struct {...@@ -105,7 +199,6 @@ const Context = struct {
105 source_manager: *ZigClangSourceManager,199 source_manager: *ZigClangSourceManager,
106 decl_table: DeclTable,200 decl_table: DeclTable,
107 alias_list: AliasList,201 alias_list: AliasList,
108 sym_table: SymbolTable,
109 global_scope: *Scope.Root,202 global_scope: *Scope.Root,
110 ptr_params: std.BufSet,203 ptr_params: std.BufSet,
111 clang_context: *ZigClangASTContext,204 clang_context: *ZigClangASTContext,
...@@ -142,7 +235,7 @@ pub fn translate(...@@ -142,7 +235,7 @@ pub fn translate(
142 args_begin: [*]?[*]const u8,235 args_begin: [*]?[*]const u8,
143 args_end: [*]?[*]const u8,236 args_end: [*]?[*]const u8,
144 errors: *[]ClangErrMsg,237 errors: *[]ClangErrMsg,
145 resources_path: [*]const u8,238 resources_path: [*:0]const u8,
146) !*ast.Tree {239) !*ast.Tree {
147 const ast_unit = ZigClangLoadFromCommandLine(240 const ast_unit = ZigClangLoadFromCommandLine(
148 args_begin,241 args_begin,
...@@ -192,24 +285,22 @@ pub fn translate(...@@ -192,24 +285,22 @@ pub fn translate(
192 .err = undefined,285 .err = undefined,
193 .decl_table = DeclTable.init(arena),286 .decl_table = DeclTable.init(arena),
194 .alias_list = AliasList.init(arena),287 .alias_list = AliasList.init(arena),
195 .sym_table = SymbolTable.init(arena),
196 .global_scope = try arena.create(Scope.Root),288 .global_scope = try arena.create(Scope.Root),
197 .ptr_params = std.BufSet.init(arena),289 .ptr_params = std.BufSet.init(arena),
198 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,290 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
199 };291 };
200 context.global_scope.* = Scope.Root{292 context.global_scope.* = Scope.Root.init(&context);
201 .base = Scope{
202 .id = Scope.Id.Root,
203 .parent = null,
204 },
205 };
206293
207 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {294 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
208 return context.err;295 return context.err;
209 }296 }
297
298 try transPreprocessorEntities(&context, ast_unit);
299
300 try addMacros(&context);
210 var it = context.alias_list.iterator(0);301 var it = context.alias_list.iterator(0);
211 while (it.next()) |alias| {302 while (it.next()) |alias| {
212 if (!context.sym_table.contains(alias.alias)) {303 if (!context.global_scope.sym_table.contains(alias.alias)) {
213 try createAlias(&context, alias);304 try createAlias(&context, alias);
214 }305 }
215 }306 }
...@@ -268,7 +359,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -268,7 +359,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
268 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);359 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
269 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);360 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
270 const fn_type = ZigClangQualType_getTypePtr(fn_qt);361 const fn_type = ZigClangQualType_getTypePtr(fn_qt);
271 var scope = &c.global_scope.base;362 var fndef_scope = Scope.FnDef.init(c);
363 var scope = &fndef_scope.base;
272 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);364 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
273 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);365 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
274 const decl_ctx = FnDeclContext{366 const decl_ctx = FnDeclContext{
...@@ -314,14 +406,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -314,14 +406,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
314406
315 // actual function definition with body407 // actual function definition with body
316 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);408 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);
317 const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) {409 const body_node = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) {
318 error.OutOfMemory => |e| return e,410 error.OutOfMemory => |e| return e,
319 error.UnsupportedTranslation,411 error.UnsupportedTranslation,
320 error.UnsupportedType,412 error.UnsupportedType,
321 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),413 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
322 };414 };
323 assert(result.node.id == ast.Node.Id.Block);415 assert(body_node.id == .Block);
324 proto_node.body_node = result.node;416 proto_node.body_node = body_node;
325417
326 return addTopLevelDecl(c, fn_name, &proto_node.base);418 return addTopLevelDecl(c, fn_name, &proto_node.base);
327}419}
...@@ -336,7 +428,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -336,7 +428,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
336 else428 else
337 try appendToken(c, .Keyword_threadlocal, "threadlocal");429 try appendToken(c, .Keyword_threadlocal, "threadlocal");
338430
339 var scope = &c.global_scope.base;431 const scope = &c.global_scope.base;
340 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));432 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
341 _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);433 _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);
342 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);434 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
...@@ -372,17 +464,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -372,17 +464,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
372464
373 if (ZigClangVarDecl_hasInit(var_decl)) {465 if (ZigClangVarDecl_hasInit(var_decl)) {
374 eq_tok = try appendToken(c, .Equal, "=");466 eq_tok = try appendToken(c, .Equal, "=");
375 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| blk: {467 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
376 var res = transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {468 transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
377 error.UnsupportedTranslation,469 error.UnsupportedTranslation,
378 error.UnsupportedType,470 error.UnsupportedType,
379 => {471 => {
380 return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{});472 return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{});
381 },473 },
382 error.OutOfMemory => |e| return e,474 error.OutOfMemory => |e| return e,
383 };475 }
384 break :blk res.node;476 else
385 } else
386 try transCreateNodeUndefinedLiteral(c);477 try transCreateNodeUndefinedLiteral(c);
387 } else if (storage_class != .Extern) {478 } else if (storage_class != .Extern) {
388 return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{});479 return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{});
...@@ -548,7 +639,7 @@ fn transStmt(...@@ -548,7 +639,7 @@ fn transStmt(
548 stmt: *const ZigClangStmt,639 stmt: *const ZigClangStmt,
549 result_used: ResultUsed,640 result_used: ResultUsed,
550 lrvalue: LRValue,641 lrvalue: LRValue,
551) TransError!TransResult {642) TransError!*ast.Node {
552 const sc = ZigClangStmt_getStmtClass(stmt);643 const sc = ZigClangStmt_getStmtClass(stmt);
553 switch (sc) {644 switch (sc) {
554 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),645 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),
...@@ -580,7 +671,7 @@ fn transBinaryOperator(...@@ -580,7 +671,7 @@ fn transBinaryOperator(
580 scope: *Scope,671 scope: *Scope,
581 stmt: *const ZigClangBinaryOperator,672 stmt: *const ZigClangBinaryOperator,
582 result_used: ResultUsed,673 result_used: ResultUsed,
583) TransError!TransResult {674) TransError!*ast.Node {
584 const op = ZigClangBinaryOperator_getOpcode(stmt);675 const op = ZigClangBinaryOperator_getOpcode(stmt);
585 const qt = ZigClangBinaryOperator_getType(stmt);676 const qt = ZigClangBinaryOperator_getType(stmt);
586 switch (op) {677 switch (op) {
...@@ -591,67 +682,43 @@ fn transBinaryOperator(...@@ -591,67 +682,43 @@ fn transBinaryOperator(
591 "TODO: handle more C binary operators: {}",682 "TODO: handle more C binary operators: {}",
592 .{op},683 .{op},
593 ),684 ),
594 .Assign => return TransResult{685 .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,
595 .node = &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,
596 .child_scope = scope,
597 .node_scope = scope,
598 },
599 .Add => {686 .Add => {
600 const node = if (cIsUnsignedInteger(qt))687 const node = if (cIsUnsignedInteger(qt))
601 try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)688 try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)
602 else689 else
603 try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);690 try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);
604 return maybeSuppressResult(rp, scope, result_used, TransResult{691 return maybeSuppressResult(rp, scope, result_used, node);
605 .node = node,
606 .child_scope = scope,
607 .node_scope = scope,
608 });
609 },692 },
610 .Sub => {693 .Sub => {
611 const node = if (cIsUnsignedInteger(qt))694 const node = if (cIsUnsignedInteger(qt))
612 try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)695 try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)
613 else696 else
614 try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);697 try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);
615 return maybeSuppressResult(rp, scope, result_used, TransResult{698 return maybeSuppressResult(rp, scope, result_used, node);
616 .node = node,
617 .child_scope = scope,
618 .node_scope = scope,
619 });
620 },699 },
621 .Mul => {700 .Mul => {
622 const node = if (cIsUnsignedInteger(qt))701 const node = if (cIsUnsignedInteger(qt))
623 try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)702 try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)
624 else703 else
625 try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);704 try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);
626 return maybeSuppressResult(rp, scope, result_used, TransResult{705 return maybeSuppressResult(rp, scope, result_used, node);
627 .node = node,
628 .child_scope = scope,
629 .node_scope = scope,
630 });
631 },706 },
632 .Div => {707 .Div => {
633 if (!cIsUnsignedInteger(qt)) {708 if (!cIsUnsignedInteger(qt)) {
634 // signed integer division uses @divTrunc709 // signed integer division uses @divTrunc
635 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");710 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
636 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);711 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
637 try div_trunc_node.params.push(lhs.node);712 try div_trunc_node.params.push(lhs);
638 _ = try appendToken(rp.c, .Comma, ",");713 _ = try appendToken(rp.c, .Comma, ",");
639 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);714 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
640 try div_trunc_node.params.push(rhs.node);715 try div_trunc_node.params.push(rhs);
641 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");716 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
642 return maybeSuppressResult(rp, scope, result_used, TransResult{717 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
643 .node = &div_trunc_node.base,
644 .child_scope = scope,
645 .node_scope = scope,
646 });
647 } else {718 } else {
648 // unsigned/float division uses the operator719 // unsigned/float division uses the operator
649 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true);720 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true);
650 return maybeSuppressResult(rp, scope, result_used, TransResult{721 return maybeSuppressResult(rp, scope, result_used, node);
651 .node = node,
652 .child_scope = scope,
653 .node_scope = scope,
654 });
655 }722 }
656 },723 },
657 .Rem => {724 .Rem => {
...@@ -659,24 +726,16 @@ fn transBinaryOperator(...@@ -659,24 +726,16 @@ fn transBinaryOperator(
659 // signed integer division uses @rem726 // signed integer division uses @rem
660 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");727 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
661 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);728 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
662 try rem_node.params.push(lhs.node);729 try rem_node.params.push(lhs);
663 _ = try appendToken(rp.c, .Comma, ",");730 _ = try appendToken(rp.c, .Comma, ",");
664 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);731 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
665 try rem_node.params.push(rhs.node);732 try rem_node.params.push(rhs);
666 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");733 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
667 return maybeSuppressResult(rp, scope, result_used, TransResult{734 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
668 .node = &rem_node.base,
669 .child_scope = scope,
670 .node_scope = scope,
671 });
672 } else {735 } else {
673 // unsigned/float division uses the operator736 // unsigned/float division uses the operator
674 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);737 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);
675 return maybeSuppressResult(rp, scope, result_used, TransResult{738 return maybeSuppressResult(rp, scope, result_used, node);
676 .node = node,
677 .child_scope = scope,
678 .node_scope = scope,
679 });
680 }739 }
681 },740 },
682 .Shl,741 .Shl,
...@@ -720,33 +779,22 @@ fn transCompoundStmtInline(...@@ -720,33 +779,22 @@ fn transCompoundStmtInline(
720 parent_scope: *Scope,779 parent_scope: *Scope,
721 stmt: *const ZigClangCompoundStmt,780 stmt: *const ZigClangCompoundStmt,
722 block_node: *ast.Node.Block,781 block_node: *ast.Node.Block,
723) TransError!TransResult {782) TransError!void {
724 var it = ZigClangCompoundStmt_body_begin(stmt);783 var it = ZigClangCompoundStmt_body_begin(stmt);
725 const end_it = ZigClangCompoundStmt_body_end(stmt);784 const end_it = ZigClangCompoundStmt_body_end(stmt);
726 var scope = parent_scope;
727 while (it != end_it) : (it += 1) {785 while (it != end_it) : (it += 1) {
728 const result = try transStmt(rp, parent_scope, it.*, .unused, .r_value);786 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
729 scope = result.child_scope;787 if (result != &block_node.base)
730 if (result.node != &block_node.base)788 try block_node.statements.push(result);
731 try block_node.statements.push(result.node);
732 }789 }
733 return TransResult{
734 .node = &block_node.base,
735 .child_scope = scope,
736 .node_scope = scope,
737 };
738}790}
739791
740fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) !TransResult {792fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
741 const lbrace_tok = try appendToken(rp.c, .LBrace, "{");793 const block_node = try transCreateNodeBlock(rp.c, null);
742 const block_scope = try Scope.Block.create(rp.c, scope, lbrace_tok);794 const block_scope = try Scope.Block.init(rp.c, scope, block_node);
743 const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);795 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node);
744 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");796 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
745 return TransResult{797 return &block_node.base;
746 .node = &block_scope.block_node.base,
747 .node_scope = inline_result.node_scope,
748 .child_scope = inline_result.child_scope,
749 };
750}798}
751799
752fn transCStyleCastExprClass(800fn transCStyleCastExprClass(
...@@ -755,7 +803,7 @@ fn transCStyleCastExprClass(...@@ -755,7 +803,7 @@ fn transCStyleCastExprClass(
755 stmt: *const ZigClangCStyleCastExpr,803 stmt: *const ZigClangCStyleCastExpr,
756 result_used: ResultUsed,804 result_used: ResultUsed,
757 lrvalue: LRValue,805 lrvalue: LRValue,
758) !TransResult {806) TransError!*ast.Node {
759 const sub_expr = ZigClangCStyleCastExpr_getSubExpr(stmt);807 const sub_expr = ZigClangCStyleCastExpr_getSubExpr(stmt);
760 const cast_node = (try transCCast(808 const cast_node = (try transCCast(
761 rp,809 rp,
...@@ -763,27 +811,21 @@ fn transCStyleCastExprClass(...@@ -763,27 +811,21 @@ fn transCStyleCastExprClass(
763 ZigClangCStyleCastExpr_getBeginLoc(stmt),811 ZigClangCStyleCastExpr_getBeginLoc(stmt),
764 ZigClangCStyleCastExpr_getType(stmt),812 ZigClangCStyleCastExpr_getType(stmt),
765 ZigClangExpr_getType(sub_expr),813 ZigClangExpr_getType(sub_expr),
766 (try transExpr(rp, scope, sub_expr, .used, lrvalue)).node,814 try transExpr(rp, scope, sub_expr, .used, lrvalue),
767 ));815 ));
768 const cast_res = TransResult{816 return maybeSuppressResult(rp, scope, result_used, cast_node);
769 .node = cast_node,
770 .child_scope = scope,
771 .node_scope = scope,
772 };
773 return maybeSuppressResult(rp, scope, result_used, cast_res);
774}817}
775818
776fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) !TransResult {819fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {
777 const c = rp.c;820 const c = rp.c;
778 const block_scope = findBlockScope(parent_scope);821 const block_scope = scope.findBlockScope();
779 var scope = parent_scope;
780822
781 var it = ZigClangDeclStmt_decl_begin(stmt);823 var it = ZigClangDeclStmt_decl_begin(stmt);
782 const end_it = ZigClangDeclStmt_decl_end(stmt);824 const end_it = ZigClangDeclStmt_decl_end(stmt);
783 while (it != end_it) : (it += 1) {825 while (it != end_it) : (it += 1) {
784 switch (ZigClangDecl_getKind(it.*)) {826 switch (ZigClangDecl_getKind(it[0])) {
785 .Var => {827 .Var => {
786 const var_decl = @ptrCast(*const ZigClangVarDecl, it.*);828 const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]);
787829
788 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)830 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
789 null831 null
...@@ -794,18 +836,14 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe...@@ -794,18 +836,14 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
794 try appendToken(c, .Keyword_const, "const")836 try appendToken(c, .Keyword_const, "const")
795 else837 else
796 try appendToken(c, .Keyword_var, "var");838 try appendToken(c, .Keyword_var, "var");
797 const c_name = try c.str(ZigClangDecl_getName_bytes_begin(839 const name = try c.str(ZigClangDecl_getName_bytes_begin(
798 @ptrCast(*const ZigClangDecl, var_decl),840 @ptrCast(*const ZigClangDecl, var_decl),
799 ));841 ));
800 const name_token = try appendIdentifier(c, c_name);842 const checked_name = if (try scope.createAlias(c, name)) |a| blk: {
801843 try block_scope.variables.push(.{ .name = name, .alias = a });
802 const var_scope = try c.a().create(Scope.Var);844 break :blk a;
803 var_scope.* = Scope.Var{845 } else name;
804 .base = Scope{ .id = .Var, .parent = scope },846 const name_token = try appendIdentifier(c, checked_name);
805 .c_name = c_name,
806 .zig_name = c_name, // TODO: getWantedName
807 };
808 scope = &var_scope.base;
809847
810 const colon_token = try appendToken(c, .Colon, ":");848 const colon_token = try appendToken(c, .Colon, ":");
811 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));849 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));
...@@ -813,7 +851,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe...@@ -813,7 +851,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
813851
814 const eq_token = try appendToken(c, .Equal, "=");852 const eq_token = try appendToken(c, .Equal, "=");
815 const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|853 const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
816 (try transExpr(rp, scope, expr, .used, .r_value)).node854 try transExpr(rp, scope, expr, .used, .r_value)
817 else855 else
818 try transCreateNodeUndefinedLiteral(c);856 try transCreateNodeUndefinedLiteral(c);
819 const semicolon_token = try appendToken(c, .Semicolon, ";");857 const semicolon_token = try appendToken(c, .Semicolon, ";");
...@@ -837,7 +875,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe...@@ -837,7 +875,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
837 };875 };
838 try block_scope.block_node.statements.push(&node.base);876 try block_scope.block_node.statements.push(&node.base);
839 },877 },
840
841 else => |kind| return revertAndWarn(878 else => |kind| return revertAndWarn(
842 rp,879 rp,
843 error.UnsupportedTranslation,880 error.UnsupportedTranslation,
...@@ -847,12 +884,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe...@@ -847,12 +884,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
847 ),884 ),
848 }885 }
849 }886 }
850887 return &block_scope.block_node.base;
851 return TransResult{
852 .node = &block_scope.block_node.base,
853 .node_scope = scope,
854 .child_scope = scope,
855 };
856}888}
857889
858fn transDeclRefExpr(890fn transDeclRefExpr(
...@@ -860,17 +892,12 @@ fn transDeclRefExpr(...@@ -860,17 +892,12 @@ fn transDeclRefExpr(
860 scope: *Scope,892 scope: *Scope,
861 expr: *const ZigClangDeclRefExpr,893 expr: *const ZigClangDeclRefExpr,
862 lrvalue: LRValue,894 lrvalue: LRValue,
863) !TransResult {895) TransError!*ast.Node {
864 const value_decl = ZigClangDeclRefExpr_getDecl(expr);896 const value_decl = ZigClangDeclRefExpr_getDecl(expr);
865 const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));897 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
866 const zig_name = transLookupZigIdentifier(scope, c_name);898 const checked_name = if (scope.getAlias(name)) |a| a else name;
867 if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name);899 if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name);
868 const node = try transCreateNodeIdentifier(rp.c, zig_name);900 return transCreateNodeIdentifier(rp.c, checked_name);
869 return TransResult{
870 .node = node,
871 .node_scope = scope,
872 .child_scope = scope,
873 };
874}901}
875902
876fn transImplicitCastExpr(903fn transImplicitCastExpr(
...@@ -878,7 +905,7 @@ fn transImplicitCastExpr(...@@ -878,7 +905,7 @@ fn transImplicitCastExpr(
878 scope: *Scope,905 scope: *Scope,
879 expr: *const ZigClangImplicitCastExpr,906 expr: *const ZigClangImplicitCastExpr,
880 result_used: ResultUsed,907 result_used: ResultUsed,
881) !TransResult {908) TransError!*ast.Node {
882 const c = rp.c;909 const c = rp.c;
883 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);910 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);
884 const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value);911 const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value);
...@@ -886,20 +913,12 @@ fn transImplicitCastExpr(...@@ -886,20 +913,12 @@ fn transImplicitCastExpr(
886 .BitCast => {913 .BitCast => {
887 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));914 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));
888 const src_type = getExprQualType(c, sub_expr);915 const src_type = getExprQualType(c, sub_expr);
889 return TransResult{916 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
890 .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node),
891 .node_scope = scope,
892 .child_scope = scope,
893 };
894 },917 },
895 .IntegralCast => {918 .IntegralCast => {
896 const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr));919 const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr));
897 const src_type = ZigClangExpr_getType(sub_expr);920 const src_type = ZigClangExpr_getType(sub_expr);
898 return TransResult{921 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
899 .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node),
900 .node_scope = scope,
901 .child_scope = scope,
902 };
903 },922 },
904 .FunctionToPointerDecay, .ArrayToPointerDecay => {923 .FunctionToPointerDecay, .ArrayToPointerDecay => {
905 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);924 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
...@@ -908,11 +927,7 @@ fn transImplicitCastExpr(...@@ -908,11 +927,7 @@ fn transImplicitCastExpr(
908 return transExpr(rp, scope, sub_expr, .used, .r_value);927 return transExpr(rp, scope, sub_expr, .used, .r_value);
909 },928 },
910 .NullToPointer => {929 .NullToPointer => {
911 return TransResult{930 return transCreateNodeNullLiteral(rp.c);
912 .node = try transCreateNodeNullLiteral(rp.c),
913 .node_scope = scope,
914 .child_scope = scope,
915 };
916 },931 },
917 else => |kind| return revertAndWarn(932 else => |kind| return revertAndWarn(
918 rp,933 rp,
...@@ -929,37 +944,27 @@ fn transIntegerLiteral(...@@ -929,37 +944,27 @@ fn transIntegerLiteral(
929 scope: *Scope,944 scope: *Scope,
930 expr: *const ZigClangIntegerLiteral,945 expr: *const ZigClangIntegerLiteral,
931 result_used: ResultUsed,946 result_used: ResultUsed,
932) !TransResult {947) TransError!*ast.Node {
933 var eval_result: ZigClangExprEvalResult = undefined;948 var eval_result: ZigClangExprEvalResult = undefined;
934 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {949 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
935 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);950 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
936 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});951 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
937 }952 }
938 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));953 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
939 const res = TransResult{954 return maybeSuppressResult(rp, scope, result_used, node);
940 .node = node,
941 .child_scope = scope,
942 .node_scope = scope,
943 };
944 return maybeSuppressResult(rp, scope, result_used, res);
945}955}
946956
947fn transReturnStmt(957fn transReturnStmt(
948 rp: RestorePoint,958 rp: RestorePoint,
949 scope: *Scope,959 scope: *Scope,
950 expr: *const ZigClangReturnStmt,960 expr: *const ZigClangReturnStmt,
951) !TransResult {961) TransError!*ast.Node {
952 const node = try transCreateNodeReturnExpr(rp.c);962 const node = try transCreateNodeReturnExpr(rp.c);
953 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {963 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
954 const ret_node = node.cast(ast.Node.ControlFlowExpression).?;964 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
955 ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
956 }965 }
957 _ = try appendToken(rp.c, .Semicolon, ";");966 _ = try appendToken(rp.c, .Semicolon, ";");
958 return TransResult{967 return &node.base;
959 .node = node,
960 .child_scope = scope,
961 .node_scope = scope,
962 };
963}968}
964969
965fn transStringLiteral(970fn transStringLiteral(
...@@ -967,7 +972,7 @@ fn transStringLiteral(...@@ -967,7 +972,7 @@ fn transStringLiteral(
967 scope: *Scope,972 scope: *Scope,
968 stmt: *const ZigClangStringLiteral,973 stmt: *const ZigClangStringLiteral,
969 result_used: ResultUsed,974 result_used: ResultUsed,
970) !TransResult {975) TransError!*ast.Node {
971 const kind = ZigClangStringLiteral_getKind(stmt);976 const kind = ZigClangStringLiteral_getKind(stmt);
972 switch (kind) {977 switch (kind) {
973 .Ascii, .UTF8 => {978 .Ascii, .UTF8 => {
...@@ -989,12 +994,7 @@ fn transStringLiteral(...@@ -989,12 +994,7 @@ fn transStringLiteral(
989 node.* = ast.Node.StringLiteral{994 node.* = ast.Node.StringLiteral{
990 .token = token,995 .token = token,
991 };996 };
992 const res = TransResult{997 return maybeSuppressResult(rp, scope, result_used, &node.base);
993 .node = &node.base,
994 .child_scope = scope,
995 .node_scope = scope,
996 };
997 return maybeSuppressResult(rp, scope, result_used, res);
998 },998 },
999 .UTF16, .UTF32, .Wide => return revertAndWarn(999 .UTF16, .UTF32, .Wide => return revertAndWarn(
1000 rp,1000 rp,
...@@ -1088,7 +1088,7 @@ fn transExpr(...@@ -1088,7 +1088,7 @@ fn transExpr(
1088 expr: *const ZigClangExpr,1088 expr: *const ZigClangExpr,
1089 used: ResultUsed,1089 used: ResultUsed,
1090 lrvalue: LRValue,1090 lrvalue: LRValue,
1091) TransError!TransResult {1091) TransError!*ast.Node {
1092 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);1092 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);
1093}1093}
10941094
...@@ -1097,7 +1097,7 @@ fn transInitListExpr(...@@ -1097,7 +1097,7 @@ fn transInitListExpr(
1097 scope: *Scope,1097 scope: *Scope,
1098 expr: *const ZigClangInitListExpr,1098 expr: *const ZigClangInitListExpr,
1099 used: ResultUsed,1099 used: ResultUsed,
1100) TransError!TransResult {1100) TransError!*ast.Node {
1101 const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr));1101 const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr));
1102 const qual_type = ZigClangQualType_getTypePtr(qt);1102 const qual_type = ZigClangQualType_getTypePtr(qt);
1103 const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr));1103 const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr));
...@@ -1128,16 +1128,12 @@ fn transInitListExpr(...@@ -1128,16 +1128,12 @@ fn transInitListExpr(
1128 var i: c_uint = 0;1128 var i: c_uint = 0;
1129 while (i < init_count) : (i += 1) {1129 while (i < init_count) : (i += 1) {
1130 const elem_expr = ZigClangInitListExpr_getInit(expr, i);1130 const elem_expr = ZigClangInitListExpr_getInit(expr, i);
1131 try init_node.op.ArrayInitializer.push((try transExpr(rp, scope, elem_expr, .used, .r_value)).node);1131 try init_node.op.ArrayInitializer.push(try transExpr(rp, scope, elem_expr, .used, .r_value));
1132 _ = try appendToken(rp.c, .Comma, ",");1132 _ = try appendToken(rp.c, .Comma, ",");
1133 }1133 }
1134 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");1134 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
1135 if (leftover_count == 0) {1135 if (leftover_count == 0) {
1136 return TransResult{1136 return &init_node.base;
1137 .node = &init_node.base,
1138 .child_scope = scope,
1139 .node_scope = scope,
1140 };
1141 }1137 }
1142 cat_tok = try appendToken(rp.c, .PlusPlus, "++");1138 cat_tok = try appendToken(rp.c, .PlusPlus, "++");
1143 }1139 }
...@@ -1145,7 +1141,7 @@ fn transInitListExpr(...@@ -1145,7 +1141,7 @@ fn transInitListExpr(
1145 const dot_tok = try appendToken(rp.c, .Period, ".");1141 const dot_tok = try appendToken(rp.c, .Period, ".");
1146 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);1142 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
1147 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);1143 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);
1148 try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node);1144 try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value));
1149 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");1145 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
11501146
1151 const rhs_node = if (leftover_count == 1)1147 const rhs_node = if (leftover_count == 1)
...@@ -1163,11 +1159,7 @@ fn transInitListExpr(...@@ -1163,11 +1159,7 @@ fn transInitListExpr(
1163 };1159 };
11641160
1165 if (init_count == 0) {1161 if (init_count == 0) {
1166 return TransResult{1162 return rhs_node;
1167 .node = rhs_node,
1168 .child_scope = scope,
1169 .node_scope = scope,
1170 };
1171 }1163 }
11721164
1173 const cat_node = try rp.c.a().create(ast.Node.InfixOp);1165 const cat_node = try rp.c.a().create(ast.Node.InfixOp);
...@@ -1177,11 +1169,7 @@ fn transInitListExpr(...@@ -1177,11 +1169,7 @@ fn transInitListExpr(
1177 .op = .ArrayCat,1169 .op = .ArrayCat,
1178 .rhs = rhs_node,1170 .rhs = rhs_node,
1179 };1171 };
1180 return TransResult{1172 return &cat_node.base;
1181 .node = &cat_node.base,
1182 .child_scope = scope,
1183 .node_scope = scope,
1184 };
1185}1173}
11861174
1187fn transImplicitValueInitExpr(1175fn transImplicitValueInitExpr(
...@@ -1189,7 +1177,7 @@ fn transImplicitValueInitExpr(...@@ -1189,7 +1177,7 @@ fn transImplicitValueInitExpr(
1189 scope: *Scope,1177 scope: *Scope,
1190 expr: *const ZigClangExpr,1178 expr: *const ZigClangExpr,
1191 used: ResultUsed,1179 used: ResultUsed,
1192) TransError!TransResult {1180) TransError!*ast.Node {
1193 const source_loc = ZigClangExpr_getBeginLoc(expr);1181 const source_loc = ZigClangExpr_getBeginLoc(expr);
1194 const qt = getExprQualType(rp.c, expr);1182 const qt = getExprQualType(rp.c, expr);
1195 const ty = ZigClangQualType_getTypePtr(qt);1183 const ty = ZigClangQualType_getTypePtr(qt);
...@@ -1197,9 +1185,7 @@ fn transImplicitValueInitExpr(...@@ -1197,9 +1185,7 @@ fn transImplicitValueInitExpr(
1197 .Builtin => blk: {1185 .Builtin => blk: {
1198 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);1186 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1199 switch (ZigClangBuiltinType_getKind(builtin_ty)) {1187 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1200 .Bool => {1188 .Bool => return transCreateNodeBoolLiteral(rp.c, false),
1201 break :blk try transCreateNodeBoolLiteral(rp.c, false);
1202 },
1203 .Char_U,1189 .Char_U,
1204 .UChar,1190 .UChar,
1205 .Char_S,1191 .Char_S,
...@@ -1220,37 +1206,13 @@ fn transImplicitValueInitExpr(...@@ -1220,37 +1206,13 @@ fn transImplicitValueInitExpr(
1220 .Float128,1206 .Float128,
1221 .Float16,1207 .Float16,
1222 .LongDouble,1208 .LongDouble,
1223 => {1209 => return transCreateNodeInt(rp.c, 0),
1224 break :blk try transCreateNodeInt(rp.c, 0);
1225 },
1226 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),1210 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
1227 }1211 }
1228 },1212 },
1229 .Pointer => try transCreateNodeNullLiteral(rp.c),1213 .Pointer => return transCreateNodeNullLiteral(rp.c),
1230 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}),1214 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}),
1231 };1215 };
1232 return TransResult{
1233 .node = node,
1234 .child_scope = scope,
1235 .node_scope = scope,
1236 };
1237}
1238
1239fn findBlockScope(inner: *Scope) *Scope.Block {
1240 var scope = inner;
1241 while (true) : (scope = scope.parent orelse unreachable) {
1242 if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope);
1243 }
1244}
1245
1246fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 {
1247 var scope = inner;
1248 while (true) : (scope = scope.parent orelse return c_name) {
1249 if (scope.id == .Var) {
1250 const var_scope = @ptrCast(*const Scope.Var, scope);
1251 if (std.mem.eql(u8, var_scope.c_name, c_name)) return var_scope.zig_name;
1252 }
1253 }
1254}1216}
12551217
1256fn transCPtrCast(1218fn transCPtrCast(
...@@ -1294,8 +1256,8 @@ fn maybeSuppressResult(...@@ -1294,8 +1256,8 @@ fn maybeSuppressResult(
1294 rp: RestorePoint,1256 rp: RestorePoint,
1295 scope: *Scope,1257 scope: *Scope,
1296 used: ResultUsed,1258 used: ResultUsed,
1297 result: TransResult,1259 result: *ast.Node,
1298) !TransResult {1260) TransError!*ast.Node {
1299 if (used == .used) return result;1261 if (used == .used) return result;
1300 // NOTE: This is backwards, but the semicolon must immediately follow the node.1262 // NOTE: This is backwards, but the semicolon must immediately follow the node.
1301 _ = try appendToken(rp.c, .Semicolon, ";");1263 _ = try appendToken(rp.c, .Semicolon, ";");
...@@ -1306,18 +1268,14 @@ fn maybeSuppressResult(...@@ -1306,18 +1268,14 @@ fn maybeSuppressResult(
1306 .op_token = op_token,1268 .op_token = op_token,
1307 .lhs = lhs,1269 .lhs = lhs,
1308 .op = .Assign,1270 .op = .Assign,
1309 .rhs = result.node,1271 .rhs = result,
1310 };
1311 return TransResult{
1312 .node = &op_node.base,
1313 .child_scope = scope,
1314 .node_scope = scope,
1315 };1272 };
1273 return &op_node.base;
1316}1274}
13171275
1318fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {1276fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
1319 try c.tree.root_node.decls.push(decl_node);1277 try c.tree.root_node.decls.push(decl_node);
1320 _ = try c.sym_table.put(name, {});1278 _ = try c.global_scope.sym_table.put(name, decl_node);
1321}1279}
13221280
1323fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {1281fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
...@@ -1716,11 +1674,11 @@ fn transCreateNodeAssign(...@@ -1716,11 +1674,11 @@ fn transCreateNodeAssign(
1716 _ = try appendToken(rp.c, .Semicolon, ";");1674 _ = try appendToken(rp.c, .Semicolon, ";");
17171675
1718 const node = try rp.c.a().create(ast.Node.InfixOp);1676 const node = try rp.c.a().create(ast.Node.InfixOp);
1719 node.* = ast.Node.InfixOp{1677 node.* = .{
1720 .op_token = eq_token,1678 .op_token = eq_token,
1721 .lhs = lhs_node.node,1679 .lhs = lhs_node,
1722 .op = .Assign,1680 .op = .Assign,
1723 .rhs = rhs_node.node,1681 .rhs = rhs_node,
1724 };1682 };
1725 return node;1683 return node;
1726 }1684 }
...@@ -1757,7 +1715,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {...@@ -1757,7 +1715,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
1757 _ = try appendToken(c, .LParen, "(");1715 _ = try appendToken(c, .LParen, "(");
1758 const node = try c.a().create(ast.Node.SuffixOp);1716 const node = try c.a().create(ast.Node.SuffixOp);
1759 node.* = ast.Node.SuffixOp{1717 node.* = ast.Node.SuffixOp{
1760 .lhs = fn_expr,1718 .lhs = .{ .node = fn_expr },
1761 .op = ast.Node.SuffixOp.Op{1719 .op = ast.Node.SuffixOp.Op{
1762 .Call = ast.Node.SuffixOp.Op.Call{1720 .Call = ast.Node.SuffixOp.Op.Call{
1763 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),1721 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
...@@ -1800,9 +1758,9 @@ fn transCreateNodeInfixOp(...@@ -1800,9 +1758,9 @@ fn transCreateNodeInfixOp(
1800 const node = try rp.c.a().create(ast.Node.InfixOp);1758 const node = try rp.c.a().create(ast.Node.InfixOp);
1801 node.* = ast.Node.InfixOp{1759 node.* = ast.Node.InfixOp{
1802 .op_token = op_token,1760 .op_token = op_token,
1803 .lhs = lhs.node,1761 .lhs = lhs,
1804 .op = op,1762 .op = op,
1805 .rhs = rhs.node,1763 .rhs = rhs,
1806 };1764 };
1807 if (!grouped) return &node.base;1765 if (!grouped) return &node.base;
1808 const rparen = try appendToken(rp.c, .RParen, ")");1766 const rparen = try appendToken(rp.c, .RParen, ")");
...@@ -1871,7 +1829,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {...@@ -1871,7 +1829,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
1871 return &node.base;1829 return &node.base;
1872}1830}
18731831
1874fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {1832fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
1875 const ltoken = try appendToken(c, .Keyword_return, "return");1833 const ltoken = try appendToken(c, .Keyword_return, "return");
1876 const node = try c.a().create(ast.Node.ControlFlowExpression);1834 const node = try c.a().create(ast.Node.ControlFlowExpression);
1877 node.* = ast.Node.ControlFlowExpression{1835 node.* = ast.Node.ControlFlowExpression{
...@@ -1879,7 +1837,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {...@@ -1879,7 +1837,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
1879 .kind = .Return,1837 .kind = .Return,
1880 .rhs = null,1838 .rhs = null,
1881 };1839 };
1882 return &node.base;1840 return node;
1883}1841}
18841842
1885fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {1843fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
...@@ -1934,19 +1892,158 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {...@@ -1934,19 +1892,158 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
1934 return &node.base;1892 return &node.base;
1935}1893}
19361894
1895fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node {
1896 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});
1897 const node = try c.a().create(ast.Node.FloatLiteral);
1898 node.* = .{
1899 .token = token,
1900 };
1901 return &node.base;
1902}
1903
1937fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {1904fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1938 const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType");1905 const call_node = try transCreateNodeBuiltinFnCall(c, "@OpaqueType");
1906 call_node.rparen_token = try appendToken(c, .RParen, ")");
1907 return &call_node.base;
1908}
1909
1910fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node {
1911 const scope = &c.global_scope.base;
1912
1913 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
1914 const inline_tok = try appendToken(c, .Keyword_inline, "inline");
1915 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
1916 const name_tok = try appendIdentifier(c, name);
1939 _ = try appendToken(c, .LParen, "(");1917 _ = try appendToken(c, .LParen, "(");
1940 const rparen_tok = try appendToken(c, .RParen, ")");
19411918
1942 const call_node = try c.a().create(ast.Node.BuiltinCall);1919 const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?;
1943 call_node.* = ast.Node.BuiltinCall{1920
1944 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },1921 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
1945 .builtin_token = builtin_tok,1922 var it = proto_alias.params.iterator(0);
1946 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),1923 while (it.next()) |pn| {
1947 .rparen_token = rparen_tok,1924 if (it.index != 0) {
1925 _ = try appendToken(c, .Comma, ",");
1926 }
1927 const param = pn.*.cast(ast.Node.ParamDecl).?;
1928
1929 const param_name_tok = param.name_token orelse
1930 try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()});
1931
1932 _ = try appendToken(c, .Colon, ":");
1933
1934 const param_node = try c.a().create(ast.Node.ParamDecl);
1935 param_node.* = .{
1936 .doc_comments = null,
1937 .comptime_token = null,
1938 .noalias_token = param.noalias_token,
1939 .name_token = param_name_tok,
1940 .type_node = param.type_node,
1941 .var_args_token = null,
1942 };
1943 try fn_params.push(&param_node.base);
1944 }
1945
1946 _ = try appendToken(c, .RParen, ")");
1947
1948 const fn_proto = try c.a().create(ast.Node.FnProto);
1949 fn_proto.* = .{
1950 .doc_comments = null,
1951 .visib_token = pub_tok,
1952 .fn_token = fn_tok,
1953 .name_token = name_tok,
1954 .params = fn_params,
1955 .return_type = proto_alias.return_type,
1956 .var_args_token = null,
1957 .extern_export_inline_token = inline_tok,
1958 .cc_token = null,
1959 .body_node = null,
1960 .lib_name = null,
1961 .align_expr = null,
1962 .section_expr = null,
1948 };1963 };
1949 return &call_node.base;1964
1965 const block = try transCreateNodeBlock(c, null);
1966
1967 const return_expr = try transCreateNodeReturnExpr(c);
1968 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?);
1969 const call_expr = try transCreateNodeFnCall(c, unwrap_expr);
1970 it = fn_params.iterator(0);
1971 while (it.next()) |pn| {
1972 if (it.index != 0) {
1973 _ = try appendToken(c, .Comma, ",");
1974 }
1975 const param = pn.*.cast(ast.Node.ParamDecl).?;
1976 try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)));
1977 }
1978 call_expr.rtoken = try appendToken(c, .RParen, ")");
1979 return_expr.rhs = &call_expr.base;
1980 _ = try appendToken(c, .Semicolon, ";");
1981
1982 block.rbrace = try appendToken(c, .RBrace, "}");
1983 try block.statements.push(&return_expr.base);
1984 fn_proto.body_node = &block.base;
1985 return &fn_proto.base;
1986}
1987
1988fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
1989 _ = try appendToken(c, .Period, ".");
1990 const qm = try appendToken(c, .QuestionMark, "?");
1991 const node = try c.a().create(ast.Node.SuffixOp);
1992 node.* = .{
1993 .op = .UnwrapOptional,
1994 .lhs = .{ .node = wrapped },
1995 .rtoken = qm,
1996 };
1997 return &node.base;
1998}
1999
2000fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
2001 const node = try c.a().create(ast.Node.EnumLiteral);
2002 node.* = .{
2003 .dot = try appendToken(c, .Period, "."),
2004 .name = try appendIdentifier(c, name),
2005 };
2006 return &node.base;
2007}
2008
2009fn transCreateNodeIf(c: *Context) !*ast.Node.If {
2010 const if_tok = try appendToken(c, .Keyword_if, "if");
2011 _ = try appendToken(c, .LParen, "(");
2012 const node = try c.a().create(ast.Node.If);
2013 node.* = .{
2014 .if_token = if_tok,
2015 .condition = undefined,
2016 .payload = null,
2017 .body = undefined,
2018 .@"else" = null,
2019 };
2020 return node;
2021}
2022
2023fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
2024 const node = try c.a().create(ast.Node.Else);
2025 node.* = .{
2026 .else_token = try appendToken(c, .Keyword_else, "else"),
2027 .payload = null,
2028 .body = undefined,
2029 };
2030 return node;
2031}
2032
2033fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {
2034 const label_node = if (label) |l| blk: {
2035 const ll = try appendIdentifier(c, l);
2036 _ = try appendToken(c, .Colon, ":");
2037 break :blk ll;
2038 } else null;
2039 const block_node = try c.a().create(ast.Node.Block);
2040 block_node.* = .{
2041 .label = label_node,
2042 .lbrace = try appendToken(c, .LBrace, "{"),
2043 .statements = ast.Node.Block.StatementList.init(c.a()),
2044 .rbrace = undefined,
2045 };
2046 return block_node;
1950}2047}
19512048
1952const RestorePoint = struct {2049const RestorePoint = struct {
...@@ -1972,28 +2069,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -1972,28 +2069,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
1972 switch (ZigClangType_getTypeClass(ty)) {2069 switch (ZigClangType_getTypeClass(ty)) {
1973 .Builtin => {2070 .Builtin => {
1974 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);2071 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1975 switch (ZigClangBuiltinType_getKind(builtin_ty)) {2072 return transCreateNodeIdentifier(rp.c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1976 .Void => return transCreateNodeIdentifier(rp.c, "c_void"),2073 .Void => "c_void",
1977 .Bool => return transCreateNodeIdentifier(rp.c, "bool"),2074 .Bool => "bool",
1978 .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"),2075 .Char_U, .UChar, .Char_S, .Char8 => "u8",
1979 .SChar => return transCreateNodeIdentifier(rp.c, "i8"),2076 .SChar => "i8",
1980 .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"),2077 .UShort => "c_ushort",
1981 .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"),2078 .UInt => "c_uint",
1982 .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"),2079 .ULong => "c_ulong",
1983 .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"),2080 .ULongLong => "c_ulonglong",
1984 .Short => return transCreateNodeIdentifier(rp.c, "c_short"),2081 .Short => "c_short",
1985 .Int => return transCreateNodeIdentifier(rp.c, "c_int"),2082 .Int => "c_int",
1986 .Long => return transCreateNodeIdentifier(rp.c, "c_long"),2083 .Long => "c_long",
1987 .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"),2084 .LongLong => "c_longlong",
1988 .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"),2085 .UInt128 => "u128",
1989 .Int128 => return transCreateNodeIdentifier(rp.c, "i128"),2086 .Int128 => "i128",
1990 .Float => return transCreateNodeIdentifier(rp.c, "f32"),2087 .Float => "f32",
1991 .Double => return transCreateNodeIdentifier(rp.c, "f64"),2088 .Double => "f64",
1992 .Float128 => return transCreateNodeIdentifier(rp.c, "f128"),2089 .Float128 => "f128",
1993 .Float16 => return transCreateNodeIdentifier(rp.c, "f16"),2090 .Float16 => "f16",
1994 .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"),2091 .LongDouble => "c_longdouble",
1995 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),2092 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
1996 }2093 });
1997 },2094 },
1998 .FunctionProto => {2095 .FunctionProto => {
1999 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);2096 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
...@@ -2076,6 +2173,13 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -2076,6 +2173,13 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
2076 .Record => {2173 .Record => {
2077 const record_ty = @ptrCast(*const ZigClangRecordType, ty);2174 const record_ty = @ptrCast(*const ZigClangRecordType, ty);
20782175
2176 // TODO this sould get the name from decl_table
2177 // struct Foo {
2178 // struct Bar{
2179 // int b;
2180 // };
2181 // struct Bar c;
2182 // };
2079 const record_decl = ZigClangRecordType_getDecl(record_ty);2183 const record_decl = ZigClangRecordType_getDecl(record_ty);
2080 if (try getContainerName(rp, record_decl)) |name|2184 if (try getContainerName(rp, record_decl)) |name|
2081 return transCreateNodeIdentifier(rp.c, name)2185 return transCreateNodeIdentifier(rp.c, name)
...@@ -2203,6 +2307,9 @@ fn finishTransFnProto(...@@ -2203,6 +2307,9 @@ fn finishTransFnProto(
2203 // TODO check for always_inline attribute2307 // TODO check for always_inline attribute
2204 // TODO check for align attribute2308 // TODO check for align attribute
22052309
2310 var fndef_scope = Scope.FnDef.init(rp.c);
2311 const scope = &fndef_scope.base;
2312
2206 // pub extern fn name(...) T2313 // pub extern fn name(...) T
2207 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;2314 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
2208 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;2315 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
...@@ -2228,13 +2335,17 @@ fn finishTransFnProto(...@@ -2228,13 +2335,17 @@ fn finishTransFnProto(
2228 const param_name_tok: ?ast.TokenIndex = blk: {2335 const param_name_tok: ?ast.TokenIndex = blk: {
2229 if (fn_decl != null) {2336 if (fn_decl != null) {
2230 const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i));2337 const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i));
2231 const param_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));2338 var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
2232 if (param_name.len > 0) {2339 if (param_name.len < 1)
2233 // TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank?2340 param_name = "arg"[0..];
2234 const result = try appendIdentifier(rp.c, param_name);2341 const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: {
2235 _ = try appendToken(rp.c, .Colon, ":");2342 try fndef_scope.params.push(.{ .name = param_name, .alias = a });
2236 break :blk result;2343 break :blk a;
2237 }2344 } else param_name;
2345
2346 const result = try appendIdentifier(rp.c, checked_param_name);
2347 _ = try appendToken(rp.c, .Colon, ":");
2348 break :blk result;
2238 }2349 }
2239 break :blk null;2350 break :blk null;
2240 };2351 };
...@@ -2444,3 +2555,530 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {...@@ -2444,3 +2555,530 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
2444pub fn freeErrors(errors: []ClangErrMsg) void {2555pub fn freeErrors(errors: []ClangErrMsg) void {
2445 ZigClangErrorMsg_delete(errors.ptr, errors.len);2556 ZigClangErrorMsg_delete(errors.ptr, errors.len);
2446}2557}
2558
2559fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
2560 // TODO if we see #undef, delete it from the table
2561 var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit);
2562 const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit);
2563 var tok_list = ctok.TokenList.init(c.a());
2564 const scope = &c.global_scope.base;
2565
2566 while (it.I != it_end.I) : (it.I += 1) {
2567 const entity = ZigClangPreprocessingRecord_iterator_deref(it);
2568 tok_list.shrink(0);
2569 switch (ZigClangPreprocessedEntity_getKind(entity)) {
2570 .MacroDefinitionKind => {
2571 const macro = @ptrCast(*ZigClangMacroDefinitionRecord, entity);
2572 const raw_name = ZigClangMacroDefinitionRecord_getName_getNameStart(macro);
2573 const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro);
2574
2575 const name = try c.str(raw_name);
2576 if (scope.contains(name)) {
2577 continue;
2578 }
2579 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
2580 ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) {
2581 error.OutOfMemory => |e| return e,
2582 else => {
2583 try failDecl(c, begin_loc, name, "unable to tokenize macro definition", .{});
2584 continue;
2585 },
2586 };
2587
2588 var tok_it = tok_list.iterator(0);
2589 const first_tok = tok_it.next().?;
2590 assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name));
2591 const next = tok_it.peek().?;
2592 switch (next.id) {
2593 .Identifier => {
2594 // if it equals itself, ignore. for example, from stdio.h:
2595 // #define stdin stdin
2596 if (std.mem.eql(u8, name, next.bytes)) {
2597 continue;
2598 }
2599 },
2600 .Eof => {
2601 // this means it is a macro without a value
2602 // we don't care about such things
2603 continue;
2604 },
2605 else => {},
2606 }
2607 const macro_fn = if (tok_it.peek().?.id == .Fn) blk: {
2608 _ = tok_it.next();
2609 break :blk true;
2610 } else false;
2611
2612 (if (macro_fn)
2613 transMacroFnDefine(c, &tok_it, name, begin_loc)
2614 else
2615 transMacroDefine(c, &tok_it, name, begin_loc)) catch |err| switch (err) {
2616 error.UnsupportedTranslation,
2617 error.ParseError,
2618 => try failDecl(c, begin_loc, name, "unable to translate macro", .{}),
2619 error.OutOfMemory => |e| return e,
2620 };
2621 },
2622 else => {},
2623 }
2624 }
2625}
2626
2627fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
2628 const rp = makeRestorePoint(c);
2629 const scope = &c.global_scope.base;
2630
2631 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
2632 const mut_tok = try appendToken(c, .Keyword_const, "const");
2633 const name_tok = try appendIdentifier(c, name);
2634 const eq_tok = try appendToken(c, .Equal, "=");
2635
2636 const init_node = try parseCExpr(rp, it, source_loc, scope);
2637
2638 const node = try c.a().create(ast.Node.VarDecl);
2639 node.* = ast.Node.VarDecl{
2640 .doc_comments = null,
2641 .visib_token = visib_tok,
2642 .thread_local_token = null,
2643 .name_token = name_tok,
2644 .eq_token = eq_tok,
2645 .mut_token = mut_tok,
2646 .comptime_token = null,
2647 .extern_export_token = null,
2648 .lib_name = null,
2649 .type_node = null,
2650 .align_node = null,
2651 .section_node = null,
2652 .init_node = init_node,
2653 .semicolon_token = try appendToken(c, .Semicolon, ";"),
2654 };
2655 _ = try c.global_scope.macro_table.put(name, &node.base);
2656}
2657
2658fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
2659 const rp = makeRestorePoint(c);
2660 var fndef_scope = Scope.FnDef.init(c);
2661 const scope = &fndef_scope.base;
2662
2663 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
2664 const inline_tok = try appendToken(c, .Keyword_inline, "inline");
2665 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
2666 const name_tok = try appendIdentifier(c, name);
2667 _ = try appendToken(c, .LParen, "(");
2668
2669 if (it.next().?.id != .LParen) {
2670 return error.ParseError;
2671 }
2672 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
2673 while (true) {
2674 const param_tok = it.next().?;
2675 if (param_tok.id != .Identifier)
2676 return error.ParseError;
2677
2678 const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: {
2679 try fndef_scope.params.push(.{ .name = param_tok.bytes, .alias = alias });
2680 break :blk alias;
2681 } else param_tok.bytes;
2682
2683 const param_name_tok = try appendIdentifier(c, checked_name);
2684 _ = try appendToken(c, .Colon, ":");
2685
2686 const token_index = try appendToken(c, .Keyword_var, "var");
2687 const identifier = try c.a().create(ast.Node.Identifier);
2688 identifier.* = ast.Node.Identifier{
2689 .base = ast.Node{ .id = ast.Node.Id.Identifier },
2690 .token = token_index,
2691 };
2692
2693 const param_node = try c.a().create(ast.Node.ParamDecl);
2694 param_node.* = .{
2695 .doc_comments = null,
2696 .comptime_token = null,
2697 .noalias_token = null,
2698 .name_token = param_name_tok,
2699 .type_node = &identifier.base,
2700 .var_args_token = null,
2701 };
2702 try fn_params.push(&param_node.base);
2703
2704 if (it.peek().?.id != .Comma)
2705 break;
2706 _ = it.next();
2707 _ = try appendToken(c, .Comma, ",");
2708 }
2709
2710 if (it.next().?.id != .RParen) {
2711 return error.ParseError;
2712 }
2713
2714 _ = try appendToken(c, .RParen, ")");
2715
2716 const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
2717 type_of.rparen_token = try appendToken(c, .LParen, ")");
2718
2719 const fn_proto = try c.a().create(ast.Node.FnProto);
2720 fn_proto.* = .{
2721 .visib_token = pub_tok,
2722 .extern_export_inline_token = inline_tok,
2723 .fn_token = fn_tok,
2724 .name_token = name_tok,
2725 .params = fn_params,
2726 .return_type = .{ .Explicit = &type_of.base },
2727 .doc_comments = null,
2728 .var_args_token = null,
2729 .cc_token = null,
2730 .body_node = null,
2731 .lib_name = null,
2732 .align_expr = null,
2733 .section_expr = null,
2734 };
2735
2736 const block = try transCreateNodeBlock(c, null);
2737
2738 const return_expr = try transCreateNodeReturnExpr(c);
2739 const expr = try parseCExpr(rp, it, source_loc, scope);
2740 _ = try appendToken(c, .Semicolon, ";");
2741 try type_of.params.push(expr);
2742 return_expr.rhs = expr;
2743
2744 block.rbrace = try appendToken(c, .RBrace, "}");
2745 try block.statements.push(&return_expr.base);
2746 fn_proto.body_node = &block.base;
2747 _ = try c.global_scope.macro_table.put(name, &fn_proto.base);
2748}
2749
2750const ParseError = Error || error{
2751 ParseError,
2752 UnsupportedTranslation,
2753};
2754
2755fn parseCExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node {
2756 return parseCPrefixOpExpr(rp, it, source_loc, scope);
2757}
2758
2759fn parseCNumLit(rp: RestorePoint, tok: *CToken, source_loc: ZigClangSourceLocation) ParseError!*ast.Node {
2760 if (tok.id == .NumLitInt) {
2761 if (tok.num_lit_suffix == .None) {
2762 if (tok.bytes.len > 2 and tok.bytes[0] == '0') {
2763 switch (tok.bytes[1]) {
2764 '0'...'7' => {
2765 // octal
2766 return transCreateNodeInt(rp.c, try std.fmt.allocPrint(rp.c.a(), "0o{}", .{tok.bytes}));
2767 },
2768 else => {},
2769 }
2770 }
2771 return transCreateNodeInt(rp.c, tok.bytes);
2772 }
2773 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2774 try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) {
2775 .U => "c_uint",
2776 .L => "c_long",
2777 .LU => "c_ulong",
2778 .LL => "c_longlong",
2779 .LLU => "c_ulonglong",
2780 else => unreachable,
2781 }));
2782 _ = try appendToken(rp.c, .Comma, ",");
2783 try cast_node.params.push(try transCreateNodeInt(rp.c, tok.bytes));
2784 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2785 return &cast_node.base;
2786 } else if (tok.id == .NumLitFloat) {
2787 if (tok.num_lit_suffix == .None) {
2788 return transCreateNodeFloat(rp.c, tok.bytes);
2789 }
2790 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2791 try cast_node.params.push(try transCreateNodeIdentifier(rp.c, switch (tok.num_lit_suffix) {
2792 .F => "f32",
2793 .L => "f64",
2794 else => unreachable,
2795 }));
2796 _ = try appendToken(rp.c, .Comma, ",");
2797 try cast_node.params.push(try transCreateNodeFloat(rp.c, tok.bytes));
2798 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2799 return &cast_node.base;
2800 } else
2801 return revertAndWarn(
2802 rp,
2803 error.ParseError,
2804 source_loc,
2805 "expected number literal",
2806 .{},
2807 );
2808}
2809
2810fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node {
2811 const tok = it.next().?;
2812 switch (tok.id) {
2813 .CharLit => {
2814 const token = try appendToken(rp.c, .CharLiteral, tok.bytes);
2815 const node = try rp.c.a().create(ast.Node.CharLiteral);
2816 node.* = ast.Node.CharLiteral{
2817 .token = token,
2818 };
2819 return &node.base;
2820 },
2821 .StrLit => {
2822 const token = try appendToken(rp.c, .StringLiteral, tok.bytes);
2823 const node = try rp.c.a().create(ast.Node.StringLiteral);
2824 node.* = ast.Node.StringLiteral{
2825 .token = token,
2826 };
2827 return &node.base;
2828 },
2829 .NumLitInt, .NumLitFloat => {
2830 return parseCNumLit(rp, tok, source_loc);
2831 },
2832 .Identifier => {
2833 const name = if (scope.getAlias(tok.bytes)) |a| a else tok.bytes;
2834 return transCreateNodeIdentifier(rp.c, name);
2835 },
2836 .LParen => {
2837 const inner_node = try parseCExpr(rp, it, source_loc, scope);
2838
2839 if (it.peek().?.id == .RParen) {
2840 _ = it.next();
2841 return inner_node;
2842 }
2843
2844 // hack to get zig fmt to render a comma in builtin calls
2845 _ = try appendToken(rp.c, .Comma, ",");
2846
2847 const node_to_cast = try parseCExpr(rp, it, source_loc, scope);
2848
2849 if (it.next().?.id != .RParen) {
2850 return revertAndWarn(
2851 rp,
2852 error.ParseError,
2853 source_loc,
2854 "unable to translate C expr",
2855 .{},
2856 );
2857 }
2858
2859 //if (@typeId(@TypeOf(x)) == .Pointer)
2860 // @ptrCast(dest, x)
2861 //else if (@typeId(@TypeOf(x)) == .Integer)
2862 // @intToPtr(dest, x)
2863 //else
2864 // @as(dest, x)
2865
2866 const if_1 = try transCreateNodeIf(rp.c);
2867 const type_id_1 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId");
2868 const type_of_1 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf");
2869 try type_id_1.params.push(&type_of_1.base);
2870 try type_of_1.params.push(node_to_cast);
2871 type_of_1.rparen_token = try appendToken(rp.c, .LParen, ")");
2872 type_id_1.rparen_token = try appendToken(rp.c, .LParen, ")");
2873
2874 const cmp_1 = try rp.c.a().create(ast.Node.InfixOp);
2875 cmp_1.* = .{
2876 .op_token = try appendToken(rp.c, .EqualEqual, "=="),
2877 .lhs = &type_id_1.base,
2878 .op = .EqualEqual,
2879 .rhs = try transCreateNodeEnumLiteral(rp.c, "Pointer"),
2880 };
2881 if_1.condition = &cmp_1.base;
2882 _ = try appendToken(rp.c, .LParen, ")");
2883
2884 const ptr_cast = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
2885 try ptr_cast.params.push(inner_node);
2886 try ptr_cast.params.push(node_to_cast);
2887 ptr_cast.rparen_token = try appendToken(rp.c, .LParen, ")");
2888 if_1.body = &ptr_cast.base;
2889
2890 const else_1 = try transCreateNodeElse(rp.c);
2891 if_1.@"else" = else_1;
2892
2893 const if_2 = try transCreateNodeIf(rp.c);
2894 const type_id_2 = try transCreateNodeBuiltinFnCall(rp.c, "@typeId");
2895 const type_of_2 = try transCreateNodeBuiltinFnCall(rp.c, "@TypeOf");
2896 try type_id_2.params.push(&type_of_2.base);
2897 try type_of_2.params.push(node_to_cast);
2898 type_of_2.rparen_token = try appendToken(rp.c, .LParen, ")");
2899 type_id_2.rparen_token = try appendToken(rp.c, .LParen, ")");
2900
2901 const cmp_2 = try rp.c.a().create(ast.Node.InfixOp);
2902 cmp_2.* = .{
2903 .op_token = try appendToken(rp.c, .EqualEqual, "=="),
2904 .lhs = &type_id_2.base,
2905 .op = .EqualEqual,
2906 .rhs = try transCreateNodeEnumLiteral(rp.c, "Int"),
2907 };
2908 if_2.condition = &cmp_2.base;
2909 else_1.body = &if_2.base;
2910 _ = try appendToken(rp.c, .LParen, ")");
2911
2912 const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");
2913 try int_to_ptr.params.push(inner_node);
2914 try int_to_ptr.params.push(node_to_cast);
2915 int_to_ptr.rparen_token = try appendToken(rp.c, .LParen, ")");
2916 if_2.body = &int_to_ptr.base;
2917
2918 const else_2 = try transCreateNodeElse(rp.c);
2919 if_2.@"else" = else_2;
2920
2921 const as = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2922 try as.params.push(inner_node);
2923 try as.params.push(node_to_cast);
2924 as.rparen_token = try appendToken(rp.c, .LParen, ")");
2925 else_2.body = &as.base;
2926
2927 return &if_1.base;
2928 },
2929 else => return revertAndWarn(
2930 rp,
2931 error.UnsupportedTranslation,
2932 source_loc,
2933 "unable to translate C expr",
2934 .{},
2935 ),
2936 }
2937}
2938
2939fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node {
2940 var node = try parseCPrimaryExpr(rp, it, source_loc, scope);
2941 while (true) {
2942 const tok = it.next().?;
2943 switch (tok.id) {
2944 .Dot => {
2945 const name_tok = it.next().?;
2946 if (name_tok.id != .Identifier)
2947 return revertAndWarn(
2948 rp,
2949 error.ParseError,
2950 source_loc,
2951 "unable to translate C expr",
2952 .{},
2953 );
2954
2955 const op_token = try appendToken(rp.c, .Period, ".");
2956 const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes);
2957 const access_node = try rp.c.a().create(ast.Node.InfixOp);
2958 access_node.* = .{
2959 .op_token = op_token,
2960 .lhs = node,
2961 .op = .Period,
2962 .rhs = rhs,
2963 };
2964 node = &access_node.base;
2965 },
2966 .Asterisk => {
2967 if (it.peek().?.id == .RParen) {
2968 // type *)
2969
2970 // hack to get zig fmt to render a comma in builtin calls
2971 _ = try appendToken(rp.c, .Comma, ",");
2972
2973 const ptr = try transCreateNodePtrType(rp.c, false, false, .Identifier);
2974 ptr.rhs = node;
2975 return &ptr.base;
2976 } else {
2977 // expr * expr
2978 const op_token = try appendToken(rp.c, .Asterisk, "*");
2979 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
2980 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
2981 bitshift_node.* = .{
2982 .op_token = op_token,
2983 .lhs = node,
2984 .op = .BitShiftLeft,
2985 .rhs = rhs,
2986 };
2987 node = &bitshift_node.base;
2988 }
2989 },
2990 .Shl => {
2991 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
2992 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
2993 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
2994 bitshift_node.* = .{
2995 .op_token = op_token,
2996 .lhs = node,
2997 .op = .BitShiftLeft,
2998 .rhs = rhs,
2999 };
3000 node = &bitshift_node.base;
3001 },
3002 else => {
3003 _ = it.prev();
3004 return node;
3005 },
3006 }
3007 }
3008}
3009
3010fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node {
3011 const op_tok = it.next().?;
3012
3013 switch (op_tok.id) {
3014 .Bang => {
3015 const node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
3016 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope);
3017 return &node.base;
3018 },
3019 .Minus => {
3020 const node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
3021 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope);
3022 return &node.base;
3023 },
3024 .Tilde => {
3025 const node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
3026 node.rhs = try parseCPrefixOpExpr(rp, it, source_loc, scope);
3027 return &node.base;
3028 },
3029 .Asterisk => {
3030 const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope);
3031 const node = try rp.c.a().create(ast.Node.SuffixOp);
3032 node.* = .{
3033 .lhs = .{ .node = prefix_op_expr },
3034 .op = .Deref,
3035 .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"),
3036 };
3037 return &node.base;
3038 },
3039 else => {
3040 _ = it.prev();
3041 return try parseCSuffixOpExpr(rp, it, source_loc, scope);
3042 },
3043 }
3044}
3045
3046fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 {
3047 const tok = c.tree.tokens.at(token);
3048 return c.source_buffer.toSliceConst()[tok.start..tok.end];
3049}
3050
3051fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {
3052 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
3053 const name = if (init.cast(ast.Node.Identifier)) |id|
3054 tokenSlice(c, id.token)
3055 else
3056 return null;
3057 // TODO a.b.c
3058 if (c.global_scope.sym_table.get(name)) |kv| {
3059 if (kv.value.cast(ast.Node.VarDecl)) |val| {
3060 if (val.type_node) |type_node| {
3061 if (type_node.cast(ast.Node.PrefixOp)) |casted| {
3062 if (casted.rhs.id == .FnProto) {
3063 return casted.rhs;
3064 }
3065 }
3066 }
3067 }
3068 }
3069 return null;
3070}
3071
3072fn addMacros(c: *Context) !void {
3073 var macro_it = c.global_scope.macro_table.iterator();
3074 while (macro_it.next()) |kv| {
3075 if (getFnDecl(c, kv.value)) |proto_node| {
3076 // If a macro aliases a global variable which is a function pointer, we conclude that
3077 // the macro is intended to represent a function that assumes the function pointer
3078 // variable is non-null and calls it.
3079 try addTopLevelDecl(c, kv.key, try transCreateNodeMacroFn(c, kv.key, kv.value, proto_node));
3080 } else {
3081 try addTopLevelDecl(c, kv.key, kv.value);
3082 }
3083 }
3084}
test/translate_c.zig+559-408
...@@ -162,6 +162,270 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -162,6 +162,270 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
162 \\}162 \\}
163 });163 });
164164
165 cases.add_both("enums",
166 \\enum Foo {
167 \\ FooA,
168 \\ FooB,
169 \\ Foo1,
170 \\};
171 , &[_][]const u8{
172 \\pub const enum_Foo = extern enum {
173 \\ A,
174 \\ B,
175 \\ @"1",
176 \\};
177 ,
178 \\pub const FooA = enum_Foo.A;
179 ,
180 \\pub const FooB = enum_Foo.B;
181 ,
182 \\pub const Foo1 = enum_Foo.@"1";
183 ,
184 \\pub const Foo = enum_Foo;
185 });
186
187 cases.add_both("enums",
188 \\enum Foo {
189 \\ FooA = 2,
190 \\ FooB = 5,
191 \\ Foo1,
192 \\};
193 , &[_][]const u8{
194 \\pub const enum_Foo = extern enum {
195 \\ A = 2,
196 \\ B = 5,
197 \\ @"1" = 6,
198 \\};
199 ,
200 \\pub const FooA = enum_Foo.A;
201 ,
202 \\pub const FooB = enum_Foo.B;
203 ,
204 \\pub const Foo1 = enum_Foo.@"1";
205 ,
206 \\pub const Foo = enum_Foo;
207 });
208
209 cases.add_both("typedef of function in struct field",
210 \\typedef void lws_callback_function(void);
211 \\struct Foo {
212 \\ void (*func)(void);
213 \\ lws_callback_function *callback_http;
214 \\};
215 , &[_][]const u8{
216 \\pub const lws_callback_function = extern fn () void;
217 \\pub const struct_Foo = extern struct {
218 \\ func: ?extern fn () void,
219 \\ callback_http: ?lws_callback_function,
220 \\};
221 });
222
223 cases.add_both("pointer to struct demoted to opaque due to bit fields",
224 \\struct Foo {
225 \\ unsigned int: 1;
226 \\};
227 \\struct Bar {
228 \\ struct Foo *foo;
229 \\};
230 , &[_][]const u8{
231 \\pub const struct_Foo = @OpaqueType()
232 ,
233 \\pub const struct_Bar = extern struct {
234 \\ foo: ?*struct_Foo,
235 \\};
236 });
237
238 cases.add_both("macro with left shift",
239 \\#define REDISMODULE_READ (1<<0)
240 , &[_][]const u8{
241 \\pub const REDISMODULE_READ = 1 << 0;
242 });
243
244 cases.add_both("double define struct",
245 \\typedef struct Bar Bar;
246 \\typedef struct Foo Foo;
247 \\
248 \\struct Foo {
249 \\ Foo *a;
250 \\};
251 \\
252 \\struct Bar {
253 \\ Foo *a;
254 \\};
255 , &[_][]const u8{
256 \\pub const struct_Foo = extern struct {
257 \\ a: [*c]Foo,
258 \\};
259 ,
260 \\pub const Foo = struct_Foo;
261 ,
262 \\pub const struct_Bar = extern struct {
263 \\ a: [*c]Foo,
264 \\};
265 ,
266 \\pub const Bar = struct_Bar;
267 });
268
269 cases.add_both("simple struct",
270 \\struct Foo {
271 \\ int x;
272 \\ char *y;
273 \\};
274 , &[_][]const u8{
275 \\const struct_Foo = extern struct {
276 \\ x: c_int,
277 \\ y: [*c]u8,
278 \\};
279 ,
280 \\pub const Foo = struct_Foo;
281 });
282
283 cases.add_both("self referential struct with function pointer",
284 \\struct Foo {
285 \\ void (*derp)(struct Foo *foo);
286 \\};
287 , &[_][]const u8{
288 \\pub const struct_Foo = extern struct {
289 \\ derp: ?extern fn ([*c]struct_Foo) void,
290 \\};
291 ,
292 \\pub const Foo = struct_Foo;
293 });
294
295 cases.add_both("struct prototype used in func",
296 \\struct Foo;
297 \\struct Foo *some_func(struct Foo *foo, int x);
298 , &[_][]const u8{
299 \\pub const struct_Foo = @OpaqueType();
300 ,
301 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
302 ,
303 \\pub const Foo = struct_Foo;
304 });
305
306 cases.add_both("#define an unsigned integer literal",
307 \\#define CHANNEL_COUNT 24
308 , &[_][]const u8{
309 \\pub const CHANNEL_COUNT = 24;
310 });
311
312 cases.add_both("#define referencing another #define",
313 \\#define THING2 THING1
314 \\#define THING1 1234
315 , &[_][]const u8{
316 \\pub const THING1 = 1234;
317 ,
318 \\pub const THING2 = THING1;
319 });
320
321 cases.add_both("circular struct definitions",
322 \\struct Bar;
323 \\
324 \\struct Foo {
325 \\ struct Bar *next;
326 \\};
327 \\
328 \\struct Bar {
329 \\ struct Foo *next;
330 \\};
331 , &[_][]const u8{
332 \\pub const struct_Bar = extern struct {
333 \\ next: [*c]struct_Foo,
334 \\};
335 ,
336 \\pub const struct_Foo = extern struct {
337 \\ next: [*c]struct_Bar,
338 \\};
339 });
340
341 cases.add_both("#define string",
342 \\#define foo "a string"
343 , &[_][]const u8{
344 \\pub const foo = "a string";
345 });
346
347 cases.add_both("zig keywords in C code",
348 \\struct comptime {
349 \\ int defer;
350 \\};
351 , &[_][]const u8{
352 \\pub const struct_comptime = extern struct {
353 \\ @"defer": c_int,
354 \\};
355 ,
356 \\pub const @"comptime" = struct_comptime;
357 });
358
359 cases.add_both("macro with parens around negative number",
360 \\#define LUA_GLOBALSINDEX (-10002)
361 , &[_][]const u8{
362 \\pub const LUA_GLOBALSINDEX = -10002;
363 });
364
365 cases.add_both(
366 "u integer suffix after 0 (zero) in macro definition",
367 "#define ZERO 0U",
368 &[_][]const u8{
369 "pub const ZERO = @as(c_uint, 0);",
370 },
371 );
372
373 cases.add_both(
374 "l integer suffix after 0 (zero) in macro definition",
375 "#define ZERO 0L",
376 &[_][]const u8{
377 "pub const ZERO = @as(c_long, 0);",
378 },
379 );
380
381 cases.add_both(
382 "ul integer suffix after 0 (zero) in macro definition",
383 "#define ZERO 0UL",
384 &[_][]const u8{
385 "pub const ZERO = @as(c_ulong, 0);",
386 },
387 );
388
389 cases.add_both(
390 "lu integer suffix after 0 (zero) in macro definition",
391 "#define ZERO 0LU",
392 &[_][]const u8{
393 "pub const ZERO = @as(c_ulong, 0);",
394 },
395 );
396
397 cases.add_both(
398 "ll integer suffix after 0 (zero) in macro definition",
399 "#define ZERO 0LL",
400 &[_][]const u8{
401 "pub const ZERO = @as(c_longlong, 0);",
402 },
403 );
404
405 cases.add_both(
406 "ull integer suffix after 0 (zero) in macro definition",
407 "#define ZERO 0ULL",
408 &[_][]const u8{
409 "pub const ZERO = @as(c_ulonglong, 0);",
410 },
411 );
412
413 cases.add_both(
414 "llu integer suffix after 0 (zero) in macro definition",
415 "#define ZERO 0LLU",
416 &[_][]const u8{
417 "pub const ZERO = @as(c_ulonglong, 0);",
418 },
419 );
420
421 cases.add_both(
422 "bitwise not on u-suffixed 0 (zero) in macro definition",
423 "#define NOT_ZERO (~0U)",
424 &[_][]const u8{
425 "pub const NOT_ZERO = ~@as(c_uint, 0);",
426 },
427 );
428
165 /////////////// Cases that pass for only stage2 ////////////////429 /////////////// Cases that pass for only stage2 ////////////////
166430
167 cases.add_2("Parameterless function prototypes",431 cases.add_2("Parameterless function prototypes",
...@@ -202,21 +466,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -202,21 +466,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
202 \\}466 \\}
203 });467 });
204468
205 cases.add_2("field struct",
206 \\union OpenGLProcs {
207 \\ struct {
208 \\ int Clear;
209 \\ } gl;
210 \\};
211 , &[_][]const u8{
212 \\pub const union_OpenGLProcs = extern union {
213 \\ gl: extern struct {
214 \\ Clear: c_int,
215 \\ },
216 \\};
217 \\pub const OpenGLProcs = union_OpenGLProcs;
218 });
219
220 cases.add_2("enums",469 cases.add_2("enums",
221 \\typedef enum {470 \\typedef enum {
222 \\ a,471 \\ a,
...@@ -280,46 +529,178 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -280,46 +529,178 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
280 \\ o,529 \\ o,
281 \\ p,530 \\ p,
282 \\};531 \\};
532 ,
283 \\pub const Baz = struct_Baz;533 \\pub const Baz = struct_Baz;
284 });534 });
285535
286 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////536 cases.add_2("#define a char literal",
537 \\#define A_CHAR 'a'
538 , &[_][]const u8{
539 \\pub const A_CHAR = 'a';
540 });
287541
288 cases.add_both("typedef of function in struct field",542 cases.add_2("comment after integer literal",
289 \\typedef void lws_callback_function(void);543 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
290 \\struct Foo {
291 \\ void (*func)(void);
292 \\ lws_callback_function *callback_http;
293 \\};
294 , &[_][]const u8{544 , &[_][]const u8{
295 \\pub const lws_callback_function = extern fn () void;545 \\pub const SDL_INIT_VIDEO = 0x00000020;
296 \\pub const struct_Foo = extern struct {
297 \\ func: ?extern fn () void,
298 \\ callback_http: ?lws_callback_function,
299 \\};
300 });546 });
301547
302 cases.add_both("pointer to struct demoted to opaque due to bit fields",548 cases.add_2("u integer suffix after hex literal",
303 \\struct Foo {549 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
304 \\ unsigned int: 1;550 , &[_][]const u8{
551 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
552 });
553
554 cases.add_2("l integer suffix after hex literal",
555 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
556 , &[_][]const u8{
557 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
558 });
559
560 cases.add_2("ul integer suffix after hex literal",
561 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
562 , &[_][]const u8{
563 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
564 });
565
566 cases.add_2("lu integer suffix after hex literal",
567 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
568 , &[_][]const u8{
569 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
570 });
571
572 cases.add_2("ll integer suffix after hex literal",
573 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
574 , &[_][]const u8{
575 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020);
576 });
577
578 cases.add_2("ull integer suffix after hex literal",
579 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
580 , &[_][]const u8{
581 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
582 });
583
584 cases.add_2("llu integer suffix after hex literal",
585 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
586 , &[_][]const u8{
587 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
588 });
589
590 cases.add_2("generate inline func for #define global extern fn",
591 \\extern void (*fn_ptr)(void);
592 \\#define foo fn_ptr
593 \\
594 \\extern char (*fn_ptr2)(int, float);
595 \\#define bar fn_ptr2
596 , &[_][]const u8{
597 \\pub extern var fn_ptr: ?extern fn () void;
598 ,
599 \\pub inline fn foo() void {
600 \\ return fn_ptr.?();
601 \\}
602 ,
603 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
604 ,
605 \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 {
606 \\ return fn_ptr2.?(arg_1, arg_2);
607 \\}
608 });
609
610 cases.add_2("macros with field targets",
611 \\typedef unsigned int GLbitfield;
612 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
613 \\typedef void(*OpenGLProc)(void);
614 \\union OpenGLProcs {
615 \\ OpenGLProc ptr[1];
616 \\ struct {
617 \\ PFNGLCLEARPROC Clear;
618 \\ } gl;
305 \\};619 \\};
306 \\struct Bar {620 \\extern union OpenGLProcs glProcs;
307 \\ struct Foo *foo;621 \\#define glClearUnion glProcs.gl.Clear
622 \\#define glClearPFN PFNGLCLEARPROC
623 , &[_][]const u8{
624 \\pub const GLbitfield = c_uint;
625 ,
626 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
627 ,
628 \\pub const OpenGLProc = ?extern fn () void;
629 ,
630 \\pub const union_OpenGLProcs = extern union {
631 \\ ptr: [1]OpenGLProc,
632 \\ gl: extern struct {
633 \\ Clear: PFNGLCLEARPROC,
634 \\ },
308 \\};635 \\};
636 ,
637 \\pub extern var glProcs: union_OpenGLProcs;
638 ,
639 \\pub const glClearPFN = PFNGLCLEARPROC;
640 // , // TODO
641 // \\pub inline fn glClearUnion(arg_1: GLbitfield) void {
642 // \\ return glProcs.gl.Clear.?(arg_1);
643 // \\}
644 ,
645 \\pub const OpenGLProcs = union_OpenGLProcs;
646 });
647
648 cases.add_2("macro pointer cast",
649 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
309 , &[_][]const u8{650 , &[_][]const u8{
310 \\pub const struct_Foo = @OpaqueType()651 \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
652 });
653
654 cases.add_2("basic macro function",
655 \\extern int c;
656 \\#define BASIC(c) (c*2)
657 , &[_][]const u8{
658 \\pub extern var c: c_int;
659 ,
660 \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) {
661 \\ return c_1 * 2;
662 \\}
663 });
664
665 cases.add_2("macro escape sequences",
666 \\#define FOO "aoeu\xab derp"
667 \\#define FOO2 "aoeu\a derp"
668 , &[_][]const u8{
669 \\pub const FOO = "aoeu\xab derp";
311 ,670 ,
312 \\pub const struct_Bar = extern struct {671 \\pub const FOO2 = "aoeu\x07 derp";
313 \\ foo: ?*struct_Foo,
314 \\};
315 });672 });
316673
317 cases.add("macro with left shift",674 cases.add_2("variable aliasing",
318 \\#define REDISMODULE_READ (1<<0)675 \\static long a = 2;
676 \\static long b = 2;
677 \\static int c = 4;
678 \\void foo(char c) {
679 \\ int a;
680 \\ char b = 123;
681 \\ b = (char) a;
682 \\ {
683 \\ int d = 5;
684 \\ }
685 \\ unsigned d = 440;
686 \\}
319 , &[_][]const u8{687 , &[_][]const u8{
320 \\pub const REDISMODULE_READ = 1 << 0;688 \\pub var a: c_long = @as(c_long, 2);
689 \\pub var b: c_long = @as(c_long, 2);
690 \\pub var c: c_int = 4;
691 \\pub export fn foo(c_1: u8) void {
692 \\ var a_2: c_int = undefined;
693 \\ var b_3: u8 = @as(u8, 123);
694 \\ b_3 = @as(u8, a_2);
695 \\ {
696 \\ var d: c_int = 5;
697 \\ }
698 \\ var d: c_uint = @as(c_uint, 440);
699 \\}
321 });700 });
322701
702 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
703
323 if (builtin.os != builtin.Os.windows) {704 if (builtin.os != builtin.Os.windows) {
324 // Windows treats this as an enum with type c_int705 // Windows treats this as an enum with type c_int
325 cases.add("big negative enum init values when C ABI supports long long enums",706 cases.add("big negative enum init values when C ABI supports long long enums",
...@@ -457,31 +838,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -457,31 +838,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
457 \\}838 \\}
458 });839 });
459840
460 cases.add_both("double define struct",
461 \\typedef struct Bar Bar;
462 \\typedef struct Foo Foo;
463 \\
464 \\struct Foo {
465 \\ Foo *a;
466 \\};
467 \\
468 \\struct Bar {
469 \\ Foo *a;
470 \\};
471 , &[_][]const u8{
472 \\pub const struct_Foo = extern struct {
473 \\ a: [*c]Foo,
474 \\};
475 ,
476 \\pub const Foo = struct_Foo;
477 ,
478 \\pub const struct_Bar = extern struct {
479 \\ a: [*c]Foo,
480 \\};
481 ,
482 \\pub const Bar = struct_Bar;
483 });
484
485 cases.addAllowWarnings("simple data types",841 cases.addAllowWarnings("simple data types",
486 \\#include <stdint.h>842 \\#include <stdint.h>
487 \\int foo(char a, unsigned char b, signed char c);843 \\int foo(char a, unsigned char b, signed char c);
...@@ -506,70 +862,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -506,70 +862,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
506 \\}862 \\}
507 });863 });
508864
509 cases.add_both("enums",
510 \\enum Foo {
511 \\ FooA,
512 \\ FooB,
513 \\ Foo1,
514 \\};
515 , &[_][]const u8{
516 \\pub const enum_Foo = extern enum {
517 \\ A,
518 \\ B,
519 \\ @"1",
520 \\};
521 ,
522 \\pub const FooA = enum_Foo.A;
523 ,
524 \\pub const FooB = enum_Foo.B;
525 ,
526 \\pub const Foo1 = enum_Foo.@"1";
527 ,
528 \\pub const Foo = enum_Foo;
529 });
530
531 cases.add_both("enums",
532 \\enum Foo {
533 \\ FooA = 2,
534 \\ FooB = 5,
535 \\ Foo1,
536 \\};
537 , &[_][]const u8{
538 \\pub const enum_Foo = extern enum {
539 \\ A = 2,
540 \\ B = 5,
541 \\ @"1" = 6,
542 \\};
543 ,
544 \\pub const FooA = enum_Foo.A;
545 ,
546 \\pub const FooB = enum_Foo.B;
547 ,
548 \\pub const Foo1 = enum_Foo.@"1";
549 ,
550 \\pub const Foo = enum_Foo;
551 });
552
553 cases.add("restrict -> noalias",865 cases.add("restrict -> noalias",
554 \\void foo(void *restrict bar, void *restrict);866 \\void foo(void *restrict bar, void *restrict);
555 , &[_][]const u8{867 , &[_][]const u8{
556 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;868 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
557 });869 });
558870
559 cases.add_both("simple struct",
560 \\struct Foo {
561 \\ int x;
562 \\ char *y;
563 \\};
564 , &[_][]const u8{
565 \\const struct_Foo = extern struct {
566 \\ x: c_int,
567 \\ y: [*c]u8,
568 \\};
569 ,
570 \\pub const Foo = struct_Foo;
571 });
572
573 cases.add("qualified struct and enum",871 cases.add("qualified struct and enum",
574 \\struct Foo {872 \\struct Foo {
575 \\ int x;873 \\ int x;
...@@ -584,184 +882,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -584,184 +882,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
584 \\pub const struct_Foo = extern struct {882 \\pub const struct_Foo = extern struct {
585 \\ x: c_int,883 \\ x: c_int,
586 \\ y: c_int,884 \\ y: c_int,
587 \\};885 \\};
588 ,886 ,
589 \\pub const enum_Bar = extern enum {887 \\pub const enum_Bar = extern enum {
590 \\ A,888 \\ A,
591 \\ B,889 \\ B,
592 \\};890 \\};
593 ,891 ,
594 \\pub const BarA = enum_Bar.A;892 \\pub const BarA = enum_Bar.A;
595 ,893 ,
596 \\pub const BarB = enum_Bar.B;894 \\pub const BarB = enum_Bar.B;
597 ,895 ,
598 \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;896 \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
599 ,897 ,
600 \\pub const Foo = struct_Foo;898 \\pub const Foo = struct_Foo;
601 ,899 ,
602 \\pub const Bar = enum_Bar;900 \\pub const Bar = enum_Bar;
603 });
604
605 cases.add("constant size array",
606 \\void func(int array[20]);
607 , &[_][]const u8{
608 \\pub extern fn func(array: [*c]c_int) void;
609 });
610
611 cases.add_both("self referential struct with function pointer",
612 \\struct Foo {
613 \\ void (*derp)(struct Foo *foo);
614 \\};
615 , &[_][]const u8{
616 \\pub const struct_Foo = extern struct {
617 \\ derp: ?extern fn ([*c]struct_Foo) void,
618 \\};
619 ,
620 \\pub const Foo = struct_Foo;
621 });
622
623 cases.add_both("struct prototype used in func",
624 \\struct Foo;
625 \\struct Foo *some_func(struct Foo *foo, int x);
626 , &[_][]const u8{
627 \\pub const struct_Foo = @OpaqueType();
628 ,
629 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
630 ,
631 \\pub const Foo = struct_Foo;
632 });
633
634 cases.add("#define a char literal",
635 \\#define A_CHAR 'a'
636 , &[_][]const u8{
637 \\pub const A_CHAR = 97;
638 });
639
640 cases.add("#define an unsigned integer literal",
641 \\#define CHANNEL_COUNT 24
642 , &[_][]const u8{
643 \\pub const CHANNEL_COUNT = 24;
644 });
645
646 cases.add("#define referencing another #define",
647 \\#define THING2 THING1
648 \\#define THING1 1234
649 , &[_][]const u8{
650 \\pub const THING1 = 1234;
651 ,
652 \\pub const THING2 = THING1;
653 });
654
655 cases.add_both("circular struct definitions",
656 \\struct Bar;
657 \\
658 \\struct Foo {
659 \\ struct Bar *next;
660 \\};
661 \\
662 \\struct Bar {
663 \\ struct Foo *next;
664 \\};
665 , &[_][]const u8{
666 \\pub const struct_Bar = extern struct {
667 \\ next: [*c]struct_Foo,
668 \\};
669 ,
670 \\pub const struct_Foo = extern struct {
671 \\ next: [*c]struct_Bar,
672 \\};
673 });
674
675 cases.add("generate inline func for #define global extern fn",
676 \\extern void (*fn_ptr)(void);
677 \\#define foo fn_ptr
678 \\
679 \\extern char (*fn_ptr2)(int, float);
680 \\#define bar fn_ptr2
681 , &[_][]const u8{
682 \\pub extern var fn_ptr: ?extern fn () void;
683 ,
684 \\pub inline fn foo() void {
685 \\ return fn_ptr.?();
686 \\}
687 ,
688 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
689 ,
690 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
691 \\ return fn_ptr2.?(arg0, arg1);
692 \\}
693 });
694
695 cases.add("#define string",
696 \\#define foo "a string"
697 , &[_][]const u8{
698 \\pub const foo = "a string";
699 });
700
701 cases.add("__cdecl doesn't mess up function pointers",
702 \\void foo(void (__cdecl *fn_ptr)(void));
703 , &[_][]const u8{
704 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
705 });
706
707 cases.add("comment after integer literal",
708 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
709 , &[_][]const u8{
710 \\pub const SDL_INIT_VIDEO = 32;
711 });
712
713 cases.add("u integer suffix after hex literal",
714 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
715 , &[_][]const u8{
716 \\pub const SDL_INIT_VIDEO = @as(c_uint, 32);
717 });
718
719 cases.add("l integer suffix after hex literal",
720 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
721 , &[_][]const u8{
722 \\pub const SDL_INIT_VIDEO = @as(c_long, 32);
723 });
724
725 cases.add("ul integer suffix after hex literal",
726 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
727 , &[_][]const u8{
728 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
729 });
730
731 cases.add("lu integer suffix after hex literal",
732 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
733 , &[_][]const u8{
734 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
735 });
736
737 cases.add("ll integer suffix after hex literal",
738 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
739 , &[_][]const u8{
740 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32);
741 });
742
743 cases.add("ull integer suffix after hex literal",
744 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
745 , &[_][]const u8{
746 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
747 });901 });
748902
749 cases.add("llu integer suffix after hex literal",903 cases.add("constant size array",
750 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */904 \\void func(int array[20]);
751 , &[_][]const u8{905 , &[_][]const u8{
752 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);906 \\pub extern fn func(array: [*c]c_int) void;
753 });907 });
754908
755 cases.add_both("zig keywords in C code",909 cases.add("__cdecl doesn't mess up function pointers",
756 \\struct comptime {910 \\void foo(void (__cdecl *fn_ptr)(void));
757 \\ int defer;
758 \\};
759 , &[_][]const u8{911 , &[_][]const u8{
760 \\pub const struct_comptime = extern struct {912 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
761 \\ @"defer": c_int,
762 \\};
763 ,
764 \\pub const @"comptime" = struct_comptime;
765 });913 });
766914
767 cases.add("macro defines string literal with hex",915 cases.add("macro defines string literal with hex",
...@@ -788,12 +936,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -788,12 +936,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
788 \\pub const FOO_CHAR = 63;936 \\pub const FOO_CHAR = 63;
789 });937 });
790938
791 cases.add("macro with parens around negative number",
792 \\#define LUA_GLOBALSINDEX (-10002)
793 , &[_][]const u8{
794 \\pub const LUA_GLOBALSINDEX = -10002;
795 });
796
797 cases.addC("post increment",939 cases.addC("post increment",
798 \\unsigned foo1(unsigned a) {940 \\unsigned foo1(unsigned a) {
799 \\ a++;941 \\ a++;
...@@ -1521,44 +1663,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1521,44 +1663,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1521 \\}1663 \\}
1522 });1664 });
15231665
1524 cases.add("macros with field targets",
1525 \\typedef unsigned int GLbitfield;
1526 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
1527 \\typedef void(*OpenGLProc)(void);
1528 \\union OpenGLProcs {
1529 \\ OpenGLProc ptr[1];
1530 \\ struct {
1531 \\ PFNGLCLEARPROC Clear;
1532 \\ } gl;
1533 \\};
1534 \\extern union OpenGLProcs glProcs;
1535 \\#define glClearUnion glProcs.gl.Clear
1536 \\#define glClearPFN PFNGLCLEARPROC
1537 , &[_][]const u8{
1538 \\pub const GLbitfield = c_uint;
1539 ,
1540 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
1541 ,
1542 \\pub const OpenGLProc = ?extern fn () void;
1543 ,
1544 \\pub const union_OpenGLProcs = extern union {
1545 \\ ptr: [1]OpenGLProc,
1546 \\ gl: extern struct {
1547 \\ Clear: PFNGLCLEARPROC,
1548 \\ },
1549 \\};
1550 ,
1551 \\pub extern var glProcs: union_OpenGLProcs;
1552 ,
1553 \\pub const glClearPFN = PFNGLCLEARPROC;
1554 ,
1555 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
1556 \\ return glProcs.gl.Clear.?(arg0);
1557 \\}
1558 ,
1559 \\pub const OpenGLProcs = union_OpenGLProcs;
1560 });
1561
1562 cases.add("variable name shadowing",1666 cases.add("variable name shadowing",
1563 \\int foo(void) {1667 \\int foo(void) {
1564 \\ int x = 1;1668 \\ int x = 1;
...@@ -1625,12 +1729,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1625,12 +1729,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1625 \\}1729 \\}
1626 });1730 });
16271731
1628 cases.add("macro pointer cast",
1629 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1630 , &[_][]const u8{
1631 \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
1632 });
1633
1634 cases.add("if on non-bool",1732 cases.add("if on non-bool",
1635 \\enum SomeEnum { A, B, C };1733 \\enum SomeEnum { A, B, C };
1636 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {1734 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
...@@ -1732,70 +1830,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1732,70 +1830,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1732 \\}1830 \\}
1733 });1831 });
17341832
1735 cases.addC(
1736 "u integer suffix after 0 (zero) in macro definition",
1737 "#define ZERO 0U",
1738 &[_][]const u8{
1739 "pub const ZERO = @as(c_uint, 0);",
1740 },
1741 );
1742
1743 cases.addC(
1744 "l integer suffix after 0 (zero) in macro definition",
1745 "#define ZERO 0L",
1746 &[_][]const u8{
1747 "pub const ZERO = @as(c_long, 0);",
1748 },
1749 );
1750
1751 cases.addC(
1752 "ul integer suffix after 0 (zero) in macro definition",
1753 "#define ZERO 0UL",
1754 &[_][]const u8{
1755 "pub const ZERO = @as(c_ulong, 0);",
1756 },
1757 );
1758
1759 cases.addC(
1760 "lu integer suffix after 0 (zero) in macro definition",
1761 "#define ZERO 0LU",
1762 &[_][]const u8{
1763 "pub const ZERO = @as(c_ulong, 0);",
1764 },
1765 );
1766
1767 cases.addC(
1768 "ll integer suffix after 0 (zero) in macro definition",
1769 "#define ZERO 0LL",
1770 &[_][]const u8{
1771 "pub const ZERO = @as(c_longlong, 0);",
1772 },
1773 );
1774
1775 cases.addC(
1776 "ull integer suffix after 0 (zero) in macro definition",
1777 "#define ZERO 0ULL",
1778 &[_][]const u8{
1779 "pub const ZERO = @as(c_ulonglong, 0);",
1780 },
1781 );
1782
1783 cases.addC(
1784 "llu integer suffix after 0 (zero) in macro definition",
1785 "#define ZERO 0LLU",
1786 &[_][]const u8{
1787 "pub const ZERO = @as(c_ulonglong, 0);",
1788 },
1789 );
1790
1791 cases.addC(
1792 "bitwise not on u-suffixed 0 (zero) in macro definition",
1793 "#define NOT_ZERO (~0U)",
1794 &[_][]const u8{
1795 "pub const NOT_ZERO = ~@as(c_uint, 0);",
1796 },
1797 );
1798
1799 cases.addC("implicit casts",1833 cases.addC("implicit casts",
1800 \\#include <stdbool.h>1834 \\#include <stdbool.h>
1801 \\1835 \\
...@@ -1936,4 +1970,121 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1936,4 +1970,121 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1936 \\pub export fn foo() void {}1970 \\pub export fn foo() void {}
1937 \\pub export fn bar() void {}1971 \\pub export fn bar() void {}
1938 });1972 });
1973
1974 cases.add("#define a char literal",
1975 \\#define A_CHAR 'a'
1976 , &[_][]const u8{
1977 \\pub const A_CHAR = 97;
1978 });
1979
1980 cases.add("generate inline func for #define global extern fn",
1981 \\extern void (*fn_ptr)(void);
1982 \\#define foo fn_ptr
1983 \\
1984 \\extern char (*fn_ptr2)(int, float);
1985 \\#define bar fn_ptr2
1986 , &[_][]const u8{
1987 \\pub extern var fn_ptr: ?extern fn () void;
1988 ,
1989 \\pub inline fn foo() void {
1990 \\ return fn_ptr.?();
1991 \\}
1992 ,
1993 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
1994 ,
1995 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
1996 \\ return fn_ptr2.?(arg0, arg1);
1997 \\}
1998 });
1999 cases.add("comment after integer literal",
2000 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2001 , &[_][]const u8{
2002 \\pub const SDL_INIT_VIDEO = 32;
2003 });
2004
2005 cases.add("u integer suffix after hex literal",
2006 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2007 , &[_][]const u8{
2008 \\pub const SDL_INIT_VIDEO = @as(c_uint, 32);
2009 });
2010
2011 cases.add("l integer suffix after hex literal",
2012 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2013 , &[_][]const u8{
2014 \\pub const SDL_INIT_VIDEO = @as(c_long, 32);
2015 });
2016
2017 cases.add("ul integer suffix after hex literal",
2018 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2019 , &[_][]const u8{
2020 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2021 });
2022
2023 cases.add("lu integer suffix after hex literal",
2024 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2025 , &[_][]const u8{
2026 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2027 });
2028
2029 cases.add("ll integer suffix after hex literal",
2030 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2031 , &[_][]const u8{
2032 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32);
2033 });
2034
2035 cases.add("ull integer suffix after hex literal",
2036 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2037 , &[_][]const u8{
2038 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2039 });
2040
2041 cases.add("llu integer suffix after hex literal",
2042 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2043 , &[_][]const u8{
2044 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2045 });
2046
2047 cases.add("macros with field targets",
2048 \\typedef unsigned int GLbitfield;
2049 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
2050 \\typedef void(*OpenGLProc)(void);
2051 \\union OpenGLProcs {
2052 \\ OpenGLProc ptr[1];
2053 \\ struct {
2054 \\ PFNGLCLEARPROC Clear;
2055 \\ } gl;
2056 \\};
2057 \\extern union OpenGLProcs glProcs;
2058 \\#define glClearUnion glProcs.gl.Clear
2059 \\#define glClearPFN PFNGLCLEARPROC
2060 , &[_][]const u8{
2061 \\pub const GLbitfield = c_uint;
2062 ,
2063 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
2064 ,
2065 \\pub const OpenGLProc = ?extern fn () void;
2066 ,
2067 \\pub const union_OpenGLProcs = extern union {
2068 \\ ptr: [1]OpenGLProc,
2069 \\ gl: extern struct {
2070 \\ Clear: PFNGLCLEARPROC,
2071 \\ },
2072 \\};
2073 ,
2074 \\pub extern var glProcs: union_OpenGLProcs;
2075 ,
2076 \\pub const glClearPFN = PFNGLCLEARPROC;
2077 ,
2078 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
2079 \\ return glProcs.gl.Clear.?(arg0);
2080 \\}
2081 ,
2082 \\pub const OpenGLProcs = union_OpenGLProcs;
2083 });
2084
2085 cases.add("macro pointer cast",
2086 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
2087 , &[_][]const u8{
2088 \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
2089 });
1939}2090}