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
signaturebadge-question-mark 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();
7575pub const struct_ZigClangFunctionType = @OpaqueType();
7676pub const struct_ZigClangPredefinedExpr = @OpaqueType();
7777pub const struct_ZigClangInitListExpr = @OpaqueType();
78pub const ZigClangPreprocessingRecord = @OpaqueType();
7879
7980pub const ZigClangBO = extern enum {
8081 PtrMemD,
......@@ -717,11 +718,23 @@ pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
717718 opaque: *c_void,
718719};
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
720733pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
721734pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
722735pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
723736pub 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;
725738pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType;
726739pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext;
727740pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager;
......@@ -751,14 +764,14 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE
751764pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator;
752765pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl;
753766pub 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;
755768pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
756769pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
757770pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType;
758771pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType;
759772pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass;
760773pub 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;
762775pub extern fn ZigClangQualType_eq(self: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool;
763776pub extern fn ZigClangQualType_isConstQualified(self: struct_ZigClangQualType) bool;
764777pub extern fn ZigClangQualType_isVolatileQualified(self: struct_ZigClangQualType) bool;
......@@ -786,7 +799,7 @@ pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;
786799pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;
787800pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;
788801pub 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;
790803pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;
791804
792805pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;
......@@ -918,25 +931,25 @@ pub const struct_ZigClangAPValueLValueBase = extern struct {
918931 Version: c_uint,
919932};
920933
921pub extern fn ZigClangErrorMsg_delete(ptr: [*c]Stage2ErrorMsg, len: usize) void;
934pub extern fn ZigClangErrorMsg_delete(ptr: [*]Stage2ErrorMsg, len: usize) void;
922935
923936pub extern fn ZigClangLoadFromCommandLine(
924937 args_begin: [*]?[*]const u8,
925938 args_end: [*]?[*]const u8,
926939 errors_ptr: *[*]Stage2ErrorMsg,
927940 errors_len: *usize,
928 resources_path: [*c]const u8,
941 resources_path: [*:0]const u8,
929942) ?*ZigClangASTUnit;
930943
931944pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind;
932945pub 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
936949pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator;
937950pub 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
941954pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
942955pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator;
......@@ -1004,7 +1017,7 @@ pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigC
10041017pub extern fn ZigClangDecayedType_getDecayedType(*const ZigClangDecayedType) ZigClangQualType;
10051018
10061019pub 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
10091022pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;
10101023
......@@ -1014,3 +1027,12 @@ pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) str
10141027
10151028pub extern fn ZigClangEnumConstantDecl_getInitExpr(*const ZigClangEnumConstantDecl) ?*const ZigClangExpr;
10161029pub 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(
9393 out_errors_len: *usize,
9494 args_begin: [*]?[*]const u8,
9595 args_end: [*]?[*]const u8,
96 resources_path: [*]const u8,
96 resources_path: [*:0]const u8,
9797) Error {
9898 var errors: []translate_c.ClangErrMsg = undefined;
9999 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;
66const ast = std.zig.ast;
77const Token = std.zig.Token;
88usingnamespace @import("clang.zig");
9const ctok = @import("c_tokenizer.zig");
10const CToken = ctok.CToken;
911
1012const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1113
......@@ -31,7 +33,7 @@ fn addrEql(a: usize, b: usize) bool {
3133 return a == b;
3234}
3335
34const SymbolTable = std.StringHashMap(void);
36const SymbolTable = std.StringHashMap(*ast.Node);
3537const AliasList = std.SegmentedList(struct {
3638 alias: []const u8,
3739 name: []const u8,
......@@ -43,59 +45,151 @@ const Scope = struct {
4345
4446 const Id = enum {
4547 Switch,
46 Var,
4748 Block,
4849 Root,
4950 While,
51 FnDef,
52 Ref,
5053 };
54
5155 const Switch = struct {
5256 base: Scope,
5357 };
5458
55 const Var = struct {
59 /// used when getting a member `a.b`
60 const Ref = struct {
5661 base: Scope,
57 c_name: []const u8,
58 zig_name: []const u8,
5962 };
6063
6164 const Block = struct {
6265 base: Scope,
6366 block_node: *ast.Node.Block,
67 variables: AliasList,
6468
6569 /// 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 {
6771 const block = try c.a().create(Block);
68 block.* = Block{
69 .base = Scope{
70 .id = Id.Block,
72 block.* = .{
73 .base = .{
74 .id = .Block,
7175 .parent = parent,
7276 },
73 .block_node = try c.a().create(ast.Node.Block),
74 };
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,
77 .block_node = block_node,
78 .variables = AliasList.init(c.a()),
8179 };
8280 return block;
8381 }
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 }
84100 };
85101
86102 const Root = struct {
87103 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 }
88121 };
89122
90123 const While = struct {
91124 base: Scope,
92125 };
93};
94126
95const TransResult = struct {
96 node: *ast.Node,
97 node_scope: *Scope,
98 child_scope: *Scope,
127 const FnDef = struct {
128 base: Scope,
129 params: AliasList,
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 }
99193};
100194
101195const Context = struct {
......@@ -105,7 +199,6 @@ const Context = struct {
105199 source_manager: *ZigClangSourceManager,
106200 decl_table: DeclTable,
107201 alias_list: AliasList,
108 sym_table: SymbolTable,
109202 global_scope: *Scope.Root,
110203 ptr_params: std.BufSet,
111204 clang_context: *ZigClangASTContext,
......@@ -142,7 +235,7 @@ pub fn translate(
142235 args_begin: [*]?[*]const u8,
143236 args_end: [*]?[*]const u8,
144237 errors: *[]ClangErrMsg,
145 resources_path: [*]const u8,
238 resources_path: [*:0]const u8,
146239) !*ast.Tree {
147240 const ast_unit = ZigClangLoadFromCommandLine(
148241 args_begin,
......@@ -192,24 +285,22 @@ pub fn translate(
192285 .err = undefined,
193286 .decl_table = DeclTable.init(arena),
194287 .alias_list = AliasList.init(arena),
195 .sym_table = SymbolTable.init(arena),
196288 .global_scope = try arena.create(Scope.Root),
197289 .ptr_params = std.BufSet.init(arena),
198290 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
199291 };
200 context.global_scope.* = Scope.Root{
201 .base = Scope{
202 .id = Scope.Id.Root,
203 .parent = null,
204 },
205 };
292 context.global_scope.* = Scope.Root.init(&context);
206293
207294 if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) {
208295 return context.err;
209296 }
297
298 try transPreprocessorEntities(&context, ast_unit);
299
300 try addMacros(&context);
210301 var it = context.alias_list.iterator(0);
211302 while (it.next()) |alias| {
212 if (!context.sym_table.contains(alias.alias)) {
303 if (!context.global_scope.sym_table.contains(alias.alias)) {
213304 try createAlias(&context, alias);
214305 }
215306 }
......@@ -268,7 +359,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
268359 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
269360 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
270361 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;
272364 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
273365 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
274366 const decl_ctx = FnDeclContext{
......@@ -314,14 +406,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
314406
315407 // actual function definition with body
316408 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) {
318410 error.OutOfMemory => |e| return e,
319411 error.UnsupportedTranslation,
320412 error.UnsupportedType,
321413 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
322414 };
323 assert(result.node.id == ast.Node.Id.Block);
324 proto_node.body_node = result.node;
415 assert(body_node.id == .Block);
416 proto_node.body_node = body_node;
325417
326418 return addTopLevelDecl(c, fn_name, &proto_node.base);
327419}
......@@ -336,7 +428,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
336428 else
337429 try appendToken(c, .Keyword_threadlocal, "threadlocal");
338430
339 var scope = &c.global_scope.base;
431 const scope = &c.global_scope.base;
340432 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
341433 _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);
342434 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
......@@ -372,17 +464,16 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
372464
373465 if (ZigClangVarDecl_hasInit(var_decl)) {
374466 eq_tok = try appendToken(c, .Equal, "=");
375 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| blk: {
376 var res = transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
467 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
468 transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
377469 error.UnsupportedTranslation,
378470 error.UnsupportedType,
379471 => {
380472 return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{});
381473 },
382474 error.OutOfMemory => |e| return e,
383 };
384 break :blk res.node;
385 } else
475 }
476 else
386477 try transCreateNodeUndefinedLiteral(c);
387478 } else if (storage_class != .Extern) {
388479 return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{});
......@@ -548,7 +639,7 @@ fn transStmt(
548639 stmt: *const ZigClangStmt,
549640 result_used: ResultUsed,
550641 lrvalue: LRValue,
551) TransError!TransResult {
642) TransError!*ast.Node {
552643 const sc = ZigClangStmt_getStmtClass(stmt);
553644 switch (sc) {
554645 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),
......@@ -580,7 +671,7 @@ fn transBinaryOperator(
580671 scope: *Scope,
581672 stmt: *const ZigClangBinaryOperator,
582673 result_used: ResultUsed,
583) TransError!TransResult {
674) TransError!*ast.Node {
584675 const op = ZigClangBinaryOperator_getOpcode(stmt);
585676 const qt = ZigClangBinaryOperator_getType(stmt);
586677 switch (op) {
......@@ -591,67 +682,43 @@ fn transBinaryOperator(
591682 "TODO: handle more C binary operators: {}",
592683 .{op},
593684 ),
594 .Assign => return TransResult{
595 .node = &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,
596 .child_scope = scope,
597 .node_scope = scope,
598 },
685 .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,
599686 .Add => {
600687 const node = if (cIsUnsignedInteger(qt))
601688 try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)
602689 else
603690 try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);
604 return maybeSuppressResult(rp, scope, result_used, TransResult{
605 .node = node,
606 .child_scope = scope,
607 .node_scope = scope,
608 });
691 return maybeSuppressResult(rp, scope, result_used, node);
609692 },
610693 .Sub => {
611694 const node = if (cIsUnsignedInteger(qt))
612695 try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)
613696 else
614697 try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);
615 return maybeSuppressResult(rp, scope, result_used, TransResult{
616 .node = node,
617 .child_scope = scope,
618 .node_scope = scope,
619 });
698 return maybeSuppressResult(rp, scope, result_used, node);
620699 },
621700 .Mul => {
622701 const node = if (cIsUnsignedInteger(qt))
623702 try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)
624703 else
625704 try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);
626 return maybeSuppressResult(rp, scope, result_used, TransResult{
627 .node = node,
628 .child_scope = scope,
629 .node_scope = scope,
630 });
705 return maybeSuppressResult(rp, scope, result_used, node);
631706 },
632707 .Div => {
633708 if (!cIsUnsignedInteger(qt)) {
634709 // signed integer division uses @divTrunc
635710 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
636711 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);
638713 _ = try appendToken(rp.c, .Comma, ",");
639714 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);
641716 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
642 return maybeSuppressResult(rp, scope, result_used, TransResult{
643 .node = &div_trunc_node.base,
644 .child_scope = scope,
645 .node_scope = scope,
646 });
717 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
647718 } else {
648719 // unsigned/float division uses the operator
649720 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true);
650 return maybeSuppressResult(rp, scope, result_used, TransResult{
651 .node = node,
652 .child_scope = scope,
653 .node_scope = scope,
654 });
721 return maybeSuppressResult(rp, scope, result_used, node);
655722 }
656723 },
657724 .Rem => {
......@@ -659,24 +726,16 @@ fn transBinaryOperator(
659726 // signed integer division uses @rem
660727 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
661728 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);
663730 _ = try appendToken(rp.c, .Comma, ",");
664731 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);
666733 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
667 return maybeSuppressResult(rp, scope, result_used, TransResult{
668 .node = &rem_node.base,
669 .child_scope = scope,
670 .node_scope = scope,
671 });
734 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
672735 } else {
673736 // unsigned/float division uses the operator
674737 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);
675 return maybeSuppressResult(rp, scope, result_used, TransResult{
676 .node = node,
677 .child_scope = scope,
678 .node_scope = scope,
679 });
738 return maybeSuppressResult(rp, scope, result_used, node);
680739 }
681740 },
682741 .Shl,
......@@ -720,33 +779,22 @@ fn transCompoundStmtInline(
720779 parent_scope: *Scope,
721780 stmt: *const ZigClangCompoundStmt,
722781 block_node: *ast.Node.Block,
723) TransError!TransResult {
782) TransError!void {
724783 var it = ZigClangCompoundStmt_body_begin(stmt);
725784 const end_it = ZigClangCompoundStmt_body_end(stmt);
726 var scope = parent_scope;
727785 while (it != end_it) : (it += 1) {
728 const result = try transStmt(rp, parent_scope, it.*, .unused, .r_value);
729 scope = result.child_scope;
730 if (result.node != &block_node.base)
731 try block_node.statements.push(result.node);
786 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
787 if (result != &block_node.base)
788 try block_node.statements.push(result);
732789 }
733 return TransResult{
734 .node = &block_node.base,
735 .child_scope = scope,
736 .node_scope = scope,
737 };
738790}
739791
740fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) !TransResult {
741 const lbrace_tok = try appendToken(rp.c, .LBrace, "{");
742 const block_scope = try Scope.Block.create(rp.c, scope, lbrace_tok);
743 const inline_result = try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
744 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
745 return TransResult{
746 .node = &block_scope.block_node.base,
747 .node_scope = inline_result.node_scope,
748 .child_scope = inline_result.child_scope,
749 };
792fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
793 const block_node = try transCreateNodeBlock(rp.c, null);
794 const block_scope = try Scope.Block.init(rp.c, scope, block_node);
795 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node);
796 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
797 return &block_node.base;
750798}
751799
752800fn transCStyleCastExprClass(
......@@ -755,7 +803,7 @@ fn transCStyleCastExprClass(
755803 stmt: *const ZigClangCStyleCastExpr,
756804 result_used: ResultUsed,
757805 lrvalue: LRValue,
758) !TransResult {
806) TransError!*ast.Node {
759807 const sub_expr = ZigClangCStyleCastExpr_getSubExpr(stmt);
760808 const cast_node = (try transCCast(
761809 rp,
......@@ -763,27 +811,21 @@ fn transCStyleCastExprClass(
763811 ZigClangCStyleCastExpr_getBeginLoc(stmt),
764812 ZigClangCStyleCastExpr_getType(stmt),
765813 ZigClangExpr_getType(sub_expr),
766 (try transExpr(rp, scope, sub_expr, .used, lrvalue)).node,
814 try transExpr(rp, scope, sub_expr, .used, lrvalue),
767815 ));
768 const cast_res = TransResult{
769 .node = cast_node,
770 .child_scope = scope,
771 .node_scope = scope,
772 };
773 return maybeSuppressResult(rp, scope, result_used, cast_res);
816 return maybeSuppressResult(rp, scope, result_used, cast_node);
774817}
775818
776fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) !TransResult {
819fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {
777820 const c = rp.c;
778 const block_scope = findBlockScope(parent_scope);
779 var scope = parent_scope;
821 const block_scope = scope.findBlockScope();
780822
781823 var it = ZigClangDeclStmt_decl_begin(stmt);
782824 const end_it = ZigClangDeclStmt_decl_end(stmt);
783825 while (it != end_it) : (it += 1) {
784 switch (ZigClangDecl_getKind(it.*)) {
826 switch (ZigClangDecl_getKind(it[0])) {
785827 .Var => {
786 const var_decl = @ptrCast(*const ZigClangVarDecl, it.*);
828 const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]);
787829
788830 const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None)
789831 null
......@@ -794,18 +836,14 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
794836 try appendToken(c, .Keyword_const, "const")
795837 else
796838 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(
798840 @ptrCast(*const ZigClangDecl, var_decl),
799841 ));
800 const name_token = try appendIdentifier(c, c_name);
801
802 const var_scope = try c.a().create(Scope.Var);
803 var_scope.* = Scope.Var{
804 .base = Scope{ .id = .Var, .parent = scope },
805 .c_name = c_name,
806 .zig_name = c_name, // TODO: getWantedName
807 };
808 scope = &var_scope.base;
842 const checked_name = if (try scope.createAlias(c, name)) |a| blk: {
843 try block_scope.variables.push(.{ .name = name, .alias = a });
844 break :blk a;
845 } else name;
846 const name_token = try appendIdentifier(c, checked_name);
809847
810848 const colon_token = try appendToken(c, .Colon, ":");
811849 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));
......@@ -813,7 +851,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
813851
814852 const eq_token = try appendToken(c, .Equal, "=");
815853 const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
816 (try transExpr(rp, scope, expr, .used, .r_value)).node
854 try transExpr(rp, scope, expr, .used, .r_value)
817855 else
818856 try transCreateNodeUndefinedLiteral(c);
819857 const semicolon_token = try appendToken(c, .Semicolon, ";");
......@@ -837,7 +875,6 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
837875 };
838876 try block_scope.block_node.statements.push(&node.base);
839877 },
840
841878 else => |kind| return revertAndWarn(
842879 rp,
843880 error.UnsupportedTranslation,
......@@ -847,12 +884,7 @@ fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDe
847884 ),
848885 }
849886 }
850
851 return TransResult{
852 .node = &block_scope.block_node.base,
853 .node_scope = scope,
854 .child_scope = scope,
855 };
887 return &block_scope.block_node.base;
856888}
857889
858890fn transDeclRefExpr(
......@@ -860,17 +892,12 @@ fn transDeclRefExpr(
860892 scope: *Scope,
861893 expr: *const ZigClangDeclRefExpr,
862894 lrvalue: LRValue,
863) !TransResult {
895) TransError!*ast.Node {
864896 const value_decl = ZigClangDeclRefExpr_getDecl(expr);
865 const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
866 const zig_name = transLookupZigIdentifier(scope, c_name);
867 if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name);
868 const node = try transCreateNodeIdentifier(rp.c, zig_name);
869 return TransResult{
870 .node = node,
871 .node_scope = scope,
872 .child_scope = scope,
873 };
897 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
898 const checked_name = if (scope.getAlias(name)) |a| a else name;
899 if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name);
900 return transCreateNodeIdentifier(rp.c, checked_name);
874901}
875902
876903fn transImplicitCastExpr(
......@@ -878,7 +905,7 @@ fn transImplicitCastExpr(
878905 scope: *Scope,
879906 expr: *const ZigClangImplicitCastExpr,
880907 result_used: ResultUsed,
881) !TransResult {
908) TransError!*ast.Node {
882909 const c = rp.c;
883910 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);
884911 const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value);
......@@ -886,20 +913,12 @@ fn transImplicitCastExpr(
886913 .BitCast => {
887914 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));
888915 const src_type = getExprQualType(c, sub_expr);
889 return TransResult{
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 };
916 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
894917 },
895918 .IntegralCast => {
896919 const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr));
897920 const src_type = ZigClangExpr_getType(sub_expr);
898 return TransResult{
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 };
921 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
903922 },
904923 .FunctionToPointerDecay, .ArrayToPointerDecay => {
905924 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
......@@ -908,11 +927,7 @@ fn transImplicitCastExpr(
908927 return transExpr(rp, scope, sub_expr, .used, .r_value);
909928 },
910929 .NullToPointer => {
911 return TransResult{
912 .node = try transCreateNodeNullLiteral(rp.c),
913 .node_scope = scope,
914 .child_scope = scope,
915 };
930 return transCreateNodeNullLiteral(rp.c);
916931 },
917932 else => |kind| return revertAndWarn(
918933 rp,
......@@ -929,37 +944,27 @@ fn transIntegerLiteral(
929944 scope: *Scope,
930945 expr: *const ZigClangIntegerLiteral,
931946 result_used: ResultUsed,
932) !TransResult {
947) TransError!*ast.Node {
933948 var eval_result: ZigClangExprEvalResult = undefined;
934949 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
935950 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
936951 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
937952 }
938953 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
939 const res = TransResult{
940 .node = node,
941 .child_scope = scope,
942 .node_scope = scope,
943 };
944 return maybeSuppressResult(rp, scope, result_used, res);
954 return maybeSuppressResult(rp, scope, result_used, node);
945955}
946956
947957fn transReturnStmt(
948958 rp: RestorePoint,
949959 scope: *Scope,
950960 expr: *const ZigClangReturnStmt,
951) !TransResult {
961) TransError!*ast.Node {
952962 const node = try transCreateNodeReturnExpr(rp.c);
953963 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
954 const ret_node = node.cast(ast.Node.ControlFlowExpression).?;
955 ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node;
964 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
956965 }
957966 _ = try appendToken(rp.c, .Semicolon, ";");
958 return TransResult{
959 .node = node,
960 .child_scope = scope,
961 .node_scope = scope,
962 };
967 return &node.base;
963968}
964969
965970fn transStringLiteral(
......@@ -967,7 +972,7 @@ fn transStringLiteral(
967972 scope: *Scope,
968973 stmt: *const ZigClangStringLiteral,
969974 result_used: ResultUsed,
970) !TransResult {
975) TransError!*ast.Node {
971976 const kind = ZigClangStringLiteral_getKind(stmt);
972977 switch (kind) {
973978 .Ascii, .UTF8 => {
......@@ -989,12 +994,7 @@ fn transStringLiteral(
989994 node.* = ast.Node.StringLiteral{
990995 .token = token,
991996 };
992 const res = TransResult{
993 .node = &node.base,
994 .child_scope = scope,
995 .node_scope = scope,
996 };
997 return maybeSuppressResult(rp, scope, result_used, res);
997 return maybeSuppressResult(rp, scope, result_used, &node.base);
998998 },
999999 .UTF16, .UTF32, .Wide => return revertAndWarn(
10001000 rp,
......@@ -1088,7 +1088,7 @@ fn transExpr(
10881088 expr: *const ZigClangExpr,
10891089 used: ResultUsed,
10901090 lrvalue: LRValue,
1091) TransError!TransResult {
1091) TransError!*ast.Node {
10921092 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);
10931093}
10941094
......@@ -1097,7 +1097,7 @@ fn transInitListExpr(
10971097 scope: *Scope,
10981098 expr: *const ZigClangInitListExpr,
10991099 used: ResultUsed,
1100) TransError!TransResult {
1100) TransError!*ast.Node {
11011101 const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr));
11021102 const qual_type = ZigClangQualType_getTypePtr(qt);
11031103 const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr));
......@@ -1128,16 +1128,12 @@ fn transInitListExpr(
11281128 var i: c_uint = 0;
11291129 while (i < init_count) : (i += 1) {
11301130 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));
11321132 _ = try appendToken(rp.c, .Comma, ",");
11331133 }
11341134 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
11351135 if (leftover_count == 0) {
1136 return TransResult{
1137 .node = &init_node.base,
1138 .child_scope = scope,
1139 .node_scope = scope,
1140 };
1136 return &init_node.base;
11411137 }
11421138 cat_tok = try appendToken(rp.c, .PlusPlus, "++");
11431139 }
......@@ -1145,7 +1141,7 @@ fn transInitListExpr(
11451141 const dot_tok = try appendToken(rp.c, .Period, ".");
11461142 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
11471143 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));
11491145 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
11501146
11511147 const rhs_node = if (leftover_count == 1)
......@@ -1163,11 +1159,7 @@ fn transInitListExpr(
11631159 };
11641160
11651161 if (init_count == 0) {
1166 return TransResult{
1167 .node = rhs_node,
1168 .child_scope = scope,
1169 .node_scope = scope,
1170 };
1162 return rhs_node;
11711163 }
11721164
11731165 const cat_node = try rp.c.a().create(ast.Node.InfixOp);
......@@ -1177,11 +1169,7 @@ fn transInitListExpr(
11771169 .op = .ArrayCat,
11781170 .rhs = rhs_node,
11791171 };
1180 return TransResult{
1181 .node = &cat_node.base,
1182 .child_scope = scope,
1183 .node_scope = scope,
1184 };
1172 return &cat_node.base;
11851173}
11861174
11871175fn transImplicitValueInitExpr(
......@@ -1189,7 +1177,7 @@ fn transImplicitValueInitExpr(
11891177 scope: *Scope,
11901178 expr: *const ZigClangExpr,
11911179 used: ResultUsed,
1192) TransError!TransResult {
1180) TransError!*ast.Node {
11931181 const source_loc = ZigClangExpr_getBeginLoc(expr);
11941182 const qt = getExprQualType(rp.c, expr);
11951183 const ty = ZigClangQualType_getTypePtr(qt);
......@@ -1197,9 +1185,7 @@ fn transImplicitValueInitExpr(
11971185 .Builtin => blk: {
11981186 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
11991187 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1200 .Bool => {
1201 break :blk try transCreateNodeBoolLiteral(rp.c, false);
1202 },
1188 .Bool => return transCreateNodeBoolLiteral(rp.c, false),
12031189 .Char_U,
12041190 .UChar,
12051191 .Char_S,
......@@ -1220,37 +1206,13 @@ fn transImplicitValueInitExpr(
12201206 .Float128,
12211207 .Float16,
12221208 .LongDouble,
1223 => {
1224 break :blk try transCreateNodeInt(rp.c, 0);
1225 },
1209 => return transCreateNodeInt(rp.c, 0),
12261210 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
12271211 }
12281212 },
1229 .Pointer => try transCreateNodeNullLiteral(rp.c),
1213 .Pointer => return transCreateNodeNullLiteral(rp.c),
12301214 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}),
12311215 };
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 }
12541216}
12551217
12561218fn transCPtrCast(
......@@ -1294,8 +1256,8 @@ fn maybeSuppressResult(
12941256 rp: RestorePoint,
12951257 scope: *Scope,
12961258 used: ResultUsed,
1297 result: TransResult,
1298) !TransResult {
1259 result: *ast.Node,
1260) TransError!*ast.Node {
12991261 if (used == .used) return result;
13001262 // NOTE: This is backwards, but the semicolon must immediately follow the node.
13011263 _ = try appendToken(rp.c, .Semicolon, ";");
......@@ -1306,18 +1268,14 @@ fn maybeSuppressResult(
13061268 .op_token = op_token,
13071269 .lhs = lhs,
13081270 .op = .Assign,
1309 .rhs = result.node,
1310 };
1311 return TransResult{
1312 .node = &op_node.base,
1313 .child_scope = scope,
1314 .node_scope = scope,
1271 .rhs = result,
13151272 };
1273 return &op_node.base;
13161274}
13171275
13181276fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
13191277 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);
13211279}
13221280
13231281fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
......@@ -1716,11 +1674,11 @@ fn transCreateNodeAssign(
17161674 _ = try appendToken(rp.c, .Semicolon, ";");
17171675
17181676 const node = try rp.c.a().create(ast.Node.InfixOp);
1719 node.* = ast.Node.InfixOp{
1677 node.* = .{
17201678 .op_token = eq_token,
1721 .lhs = lhs_node.node,
1679 .lhs = lhs_node,
17221680 .op = .Assign,
1723 .rhs = rhs_node.node,
1681 .rhs = rhs_node,
17241682 };
17251683 return node;
17261684 }
......@@ -1757,7 +1715,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
17571715 _ = try appendToken(c, .LParen, "(");
17581716 const node = try c.a().create(ast.Node.SuffixOp);
17591717 node.* = ast.Node.SuffixOp{
1760 .lhs = fn_expr,
1718 .lhs = .{ .node = fn_expr },
17611719 .op = ast.Node.SuffixOp.Op{
17621720 .Call = ast.Node.SuffixOp.Op.Call{
17631721 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
......@@ -1800,9 +1758,9 @@ fn transCreateNodeInfixOp(
18001758 const node = try rp.c.a().create(ast.Node.InfixOp);
18011759 node.* = ast.Node.InfixOp{
18021760 .op_token = op_token,
1803 .lhs = lhs.node,
1761 .lhs = lhs,
18041762 .op = op,
1805 .rhs = rhs.node,
1763 .rhs = rhs,
18061764 };
18071765 if (!grouped) return &node.base;
18081766 const rparen = try appendToken(rp.c, .RParen, ")");
......@@ -1871,7 +1829,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
18711829 return &node.base;
18721830}
18731831
1874fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
1832fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
18751833 const ltoken = try appendToken(c, .Keyword_return, "return");
18761834 const node = try c.a().create(ast.Node.ControlFlowExpression);
18771835 node.* = ast.Node.ControlFlowExpression{
......@@ -1879,7 +1837,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node {
18791837 .kind = .Return,
18801838 .rhs = null,
18811839 };
1882 return &node.base;
1840 return node;
18831841}
18841842
18851843fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
......@@ -1934,19 +1892,158 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
19341892 return &node.base;
19351893}
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
19371904fn 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);
19391917 _ = try appendToken(c, .LParen, "(");
1940 const rparen_tok = try appendToken(c, .RParen, ")");
19411918
1942 const call_node = try c.a().create(ast.Node.BuiltinCall);
1943 call_node.* = ast.Node.BuiltinCall{
1944 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
1945 .builtin_token = builtin_tok,
1946 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
1947 .rparen_token = rparen_tok,
1919 const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?;
1920
1921 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
1922 var it = proto_alias.params.iterator(0);
1923 while (it.next()) |pn| {
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,
19481963 };
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;
19502047}
19512048
19522049const RestorePoint = struct {
......@@ -1972,28 +2069,28 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
19722069 switch (ZigClangType_getTypeClass(ty)) {
19732070 .Builtin => {
19742071 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1975 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1976 .Void => return transCreateNodeIdentifier(rp.c, "c_void"),
1977 .Bool => return transCreateNodeIdentifier(rp.c, "bool"),
1978 .Char_U, .UChar, .Char_S, .Char8 => return transCreateNodeIdentifier(rp.c, "u8"),
1979 .SChar => return transCreateNodeIdentifier(rp.c, "i8"),
1980 .UShort => return transCreateNodeIdentifier(rp.c, "c_ushort"),
1981 .UInt => return transCreateNodeIdentifier(rp.c, "c_uint"),
1982 .ULong => return transCreateNodeIdentifier(rp.c, "c_ulong"),
1983 .ULongLong => return transCreateNodeIdentifier(rp.c, "c_ulonglong"),
1984 .Short => return transCreateNodeIdentifier(rp.c, "c_short"),
1985 .Int => return transCreateNodeIdentifier(rp.c, "c_int"),
1986 .Long => return transCreateNodeIdentifier(rp.c, "c_long"),
1987 .LongLong => return transCreateNodeIdentifier(rp.c, "c_longlong"),
1988 .UInt128 => return transCreateNodeIdentifier(rp.c, "u128"),
1989 .Int128 => return transCreateNodeIdentifier(rp.c, "i128"),
1990 .Float => return transCreateNodeIdentifier(rp.c, "f32"),
1991 .Double => return transCreateNodeIdentifier(rp.c, "f64"),
1992 .Float128 => return transCreateNodeIdentifier(rp.c, "f128"),
1993 .Float16 => return transCreateNodeIdentifier(rp.c, "f16"),
1994 .LongDouble => return transCreateNodeIdentifier(rp.c, "c_longdouble"),
2072 return transCreateNodeIdentifier(rp.c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2073 .Void => "c_void",
2074 .Bool => "bool",
2075 .Char_U, .UChar, .Char_S, .Char8 => "u8",
2076 .SChar => "i8",
2077 .UShort => "c_ushort",
2078 .UInt => "c_uint",
2079 .ULong => "c_ulong",
2080 .ULongLong => "c_ulonglong",
2081 .Short => "c_short",
2082 .Int => "c_int",
2083 .Long => "c_long",
2084 .LongLong => "c_longlong",
2085 .UInt128 => "u128",
2086 .Int128 => "i128",
2087 .Float => "f32",
2088 .Double => "f64",
2089 .Float128 => "f128",
2090 .Float16 => "f16",
2091 .LongDouble => "c_longdouble",
19952092 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
1996 }
2093 });
19972094 },
19982095 .FunctionProto => {
19992096 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
......@@ -2076,6 +2173,13 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
20762173 .Record => {
20772174 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 // };
20792183 const record_decl = ZigClangRecordType_getDecl(record_ty);
20802184 if (try getContainerName(rp, record_decl)) |name|
20812185 return transCreateNodeIdentifier(rp.c, name)
......@@ -2203,6 +2307,9 @@ fn finishTransFnProto(
22032307 // TODO check for always_inline attribute
22042308 // TODO check for align attribute
22052309
2310 var fndef_scope = Scope.FnDef.init(rp.c);
2311 const scope = &fndef_scope.base;
2312
22062313 // pub extern fn name(...) T
22072314 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
22082315 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
......@@ -2228,13 +2335,17 @@ fn finishTransFnProto(
22282335 const param_name_tok: ?ast.TokenIndex = blk: {
22292336 if (fn_decl != null) {
22302337 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)));
2232 if (param_name.len > 0) {
2233 // TODO: If len == 0, auto-generate arg1, arg2, etc? Or leave the name blank?
2234 const result = try appendIdentifier(rp.c, param_name);
2235 _ = try appendToken(rp.c, .Colon, ":");
2236 break :blk result;
2237 }
2338 var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
2339 if (param_name.len < 1)
2340 param_name = "arg"[0..];
2341 const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: {
2342 try fndef_scope.params.push(.{ .name = param_name, .alias = a });
2343 break :blk a;
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;
22382349 }
22392350 break :blk null;
22402351 };
......@@ -2444,3 +2555,530 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
24442555pub fn freeErrors(errors: []ClangErrMsg) void {
24452556 ZigClangErrorMsg_delete(errors.ptr, errors.len);
24462557}
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 {
162162 \\}
163163 });
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
165429 /////////////// Cases that pass for only stage2 ////////////////
166430
167431 cases.add_2("Parameterless function prototypes",
......@@ -202,21 +466,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
202466 \\}
203467 });
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
220469 cases.add_2("enums",
221470 \\typedef enum {
222471 \\ a,
......@@ -280,46 +529,178 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
280529 \\ o,
281530 \\ p,
282531 \\};
532 ,
283533 \\pub const Baz = struct_Baz;
284534 });
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",
289 \\typedef void lws_callback_function(void);
290 \\struct Foo {
291 \\ void (*func)(void);
292 \\ lws_callback_function *callback_http;
293 \\};
542 cases.add_2("comment after integer literal",
543 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
294544 , &[_][]const u8{
295 \\pub const lws_callback_function = extern fn () void;
296 \\pub const struct_Foo = extern struct {
297 \\ func: ?extern fn () void,
298 \\ callback_http: ?lws_callback_function,
299 \\};
545 \\pub const SDL_INIT_VIDEO = 0x00000020;
300546 });
301547
302 cases.add_both("pointer to struct demoted to opaque due to bit fields",
303 \\struct Foo {
304 \\ unsigned int: 1;
548 cases.add_2("u integer suffix after hex literal",
549 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
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;
305619 \\};
306 \\struct Bar {
307 \\ struct Foo *foo;
620 \\extern union OpenGLProcs glProcs;
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 \\ },
308635 \\};
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)
309650 , &[_][]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";
311670 ,
312 \\pub const struct_Bar = extern struct {
313 \\ foo: ?*struct_Foo,
314 \\};
671 \\pub const FOO2 = "aoeu\x07 derp";
315672 });
316673
317 cases.add("macro with left shift",
318 \\#define REDISMODULE_READ (1<<0)
674 cases.add_2("variable aliasing",
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 \\}
319687 , &[_][]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 \\}
321700 });
322701
702 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
703
323704 if (builtin.os != builtin.Os.windows) {
324705 // Windows treats this as an enum with type c_int
325706 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 {
457838 \\}
458839 });
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
485841 cases.addAllowWarnings("simple data types",
486842 \\#include <stdint.h>
487843 \\int foo(char a, unsigned char b, signed char c);
......@@ -506,70 +862,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
506862 \\}
507863 });
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
553865 cases.add("restrict -> noalias",
554866 \\void foo(void *restrict bar, void *restrict);
555867 , &[_][]const u8{
556868 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
557869 });
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
573871 cases.add("qualified struct and enum",
574872 \\struct Foo {
575873 \\ int x;
......@@ -584,184 +882,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
584882 \\pub const struct_Foo = extern struct {
585883 \\ x: c_int,
586884 \\ y: c_int,
587 \\};
588 ,
589 \\pub const enum_Bar = extern enum {
590 \\ A,
591 \\ B,
592 \\};
593 ,
594 \\pub const BarA = enum_Bar.A;
595 ,
596 \\pub const BarB = enum_Bar.B;
597 ,
598 \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
599 ,
600 \\pub const Foo = struct_Foo;
601 ,
602 \\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);
885 \\};
886 ,
887 \\pub const enum_Bar = extern enum {
888 \\ A,
889 \\ B,
890 \\};
891 ,
892 \\pub const BarA = enum_Bar.A;
893 ,
894 \\pub const BarB = enum_Bar.B;
895 ,
896 \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
897 ,
898 \\pub const Foo = struct_Foo;
899 ,
900 \\pub const Bar = enum_Bar;
747901 });
748902
749 cases.add("llu integer suffix after hex literal",
750 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
903 cases.add("constant size array",
904 \\void func(int array[20]);
751905 , &[_][]const u8{
752 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
906 \\pub extern fn func(array: [*c]c_int) void;
753907 });
754908
755 cases.add_both("zig keywords in C code",
756 \\struct comptime {
757 \\ int defer;
758 \\};
909 cases.add("__cdecl doesn't mess up function pointers",
910 \\void foo(void (__cdecl *fn_ptr)(void));
759911 , &[_][]const u8{
760 \\pub const struct_comptime = extern struct {
761 \\ @"defer": c_int,
762 \\};
763 ,
764 \\pub const @"comptime" = struct_comptime;
912 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
765913 });
766914
767915 cases.add("macro defines string literal with hex",
......@@ -788,12 +936,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
788936 \\pub const FOO_CHAR = 63;
789937 });
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
797939 cases.addC("post increment",
798940 \\unsigned foo1(unsigned a) {
799941 \\ a++;
......@@ -1521,44 +1663,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15211663 \\}
15221664 });
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
15621666 cases.add("variable name shadowing",
15631667 \\int foo(void) {
15641668 \\ int x = 1;
......@@ -1625,12 +1729,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16251729 \\}
16261730 });
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
16341732 cases.add("if on non-bool",
16351733 \\enum SomeEnum { A, B, C };
16361734 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
......@@ -1732,70 +1830,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17321830 \\}
17331831 });
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
17991833 cases.addC("implicit casts",
18001834 \\#include <stdbool.h>
18011835 \\
......@@ -1936,4 +1970,121 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19361970 \\pub export fn foo() void {}
19371971 \\pub export fn bar() void {}
19381972 });
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 });
19392090}