authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-22 16:12:56-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-12-22 16:12:56-05:00
log28dbdba37eed0cfd875cfc337446da3048743dd9
tree71d3d4479809da72c5410e7dd49855805f25abe5
parentba1d213f480eb0cb7c8641a8d8cb1d6763e82438
parent9d31b65b34a222ff8b11d5bcaefcfc3c22ef4250
signature Signed by PGP key 4AEE18F83AFDEB23

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

Translate-c-2 the rest

10 files changed, 5146 insertions(+), 2288 deletions(-)

lib/std/fmt.zig+3-1
......@@ -582,7 +582,9 @@ pub fn formatAsciiChar(
582582 comptime Errors: type,
583583 output: fn (@TypeOf(context), []const u8) Errors!void,
584584) Errors!void {
585 return output(context, @as(*const [1]u8, &c)[0..]);
585 if (std.ascii.isPrint(c))
586 return output(context, @as(*const [1]u8, &c)[0..]);
587 return format(context, Errors, output, "\\x{x:0<2}", .{c});
586588}
587589
588590pub fn formatBuf(
lib/std/zig/ast.zig+16-16
......@@ -1431,13 +1431,13 @@ pub const Node = struct {
14311431 AssignBitShiftRight,
14321432 AssignBitXor,
14331433 AssignDiv,
1434 AssignMinus,
1435 AssignMinusWrap,
1434 AssignSub,
1435 AssignSubWrap,
14361436 AssignMod,
1437 AssignPlus,
1438 AssignPlusWrap,
1439 AssignTimes,
1440 AssignTimesWarp,
1437 AssignAdd,
1438 AssignAddWrap,
1439 AssignMul,
1440 AssignMulWrap,
14411441 BangEqual,
14421442 BitAnd,
14431443 BitOr,
......@@ -1456,8 +1456,8 @@ pub const Node = struct {
14561456 LessThan,
14571457 MergeErrorSets,
14581458 Mod,
1459 Mult,
1460 MultWrap,
1459 Mul,
1460 MulWrap,
14611461 Period,
14621462 Range,
14631463 Sub,
......@@ -1490,13 +1490,13 @@ pub const Node = struct {
14901490 Op.AssignBitShiftRight,
14911491 Op.AssignBitXor,
14921492 Op.AssignDiv,
1493 Op.AssignMinus,
1494 Op.AssignMinusWrap,
1493 Op.AssignSub,
1494 Op.AssignSubWrap,
14951495 Op.AssignMod,
1496 Op.AssignPlus,
1497 Op.AssignPlusWrap,
1498 Op.AssignTimes,
1499 Op.AssignTimesWarp,
1496 Op.AssignAdd,
1497 Op.AssignAddWrap,
1498 Op.AssignMul,
1499 Op.AssignMulWrap,
15001500 Op.BangEqual,
15011501 Op.BitAnd,
15021502 Op.BitOr,
......@@ -1514,8 +1514,8 @@ pub const Node = struct {
15141514 Op.LessThan,
15151515 Op.MergeErrorSets,
15161516 Op.Mod,
1517 Op.Mult,
1518 Op.MultWrap,
1517 Op.Mul,
1518 Op.MulWrap,
15191519 Op.Period,
15201520 Op.Range,
15211521 Op.Sub,
lib/std/zig/parse.zig+8-8
......@@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
19811981
19821982 const token = nextToken(it);
19831983 const op = switch (token.ptr.id) {
1984 .AsteriskEqual => Op{ .AssignTimes = {} },
1984 .AsteriskEqual => Op{ .AssignMul = {} },
19851985 .SlashEqual => Op{ .AssignDiv = {} },
19861986 .PercentEqual => Op{ .AssignMod = {} },
1987 .PlusEqual => Op{ .AssignPlus = {} },
1988 .MinusEqual => Op{ .AssignMinus = {} },
1987 .PlusEqual => Op{ .AssignAdd = {} },
1988 .MinusEqual => Op{ .AssignSub = {} },
19891989 .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },
19901990 .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },
19911991 .AmpersandEqual => Op{ .AssignBitAnd = {} },
19921992 .CaretEqual => Op{ .AssignBitXor = {} },
19931993 .PipeEqual => Op{ .AssignBitOr = {} },
1994 .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} },
1995 .PlusPercentEqual => Op{ .AssignPlusWrap = {} },
1996 .MinusPercentEqual => Op{ .AssignMinusWrap = {} },
1994 .AsteriskPercentEqual => Op{ .AssignMulWrap = {} },
1995 .PlusPercentEqual => Op{ .AssignAddWrap = {} },
1996 .MinusPercentEqual => Op{ .AssignSubWrap = {} },
19971997 .Equal => Op{ .Assign = {} },
19981998 else => {
19991999 putBackToken(it, token.index);
......@@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
21202120 const token = nextToken(it);
21212121 const op = switch (token.ptr.id) {
21222122 .PipePipe => ops{ .BoolOr = {} },
2123 .Asterisk => ops{ .Mult = {} },
2123 .Asterisk => ops{ .Mul = {} },
21242124 .Slash => ops{ .Div = {} },
21252125 .Percent => ops{ .Mod = {} },
21262126 .AsteriskAsterisk => ops{ .ArrayMult = {} },
2127 .AsteriskPercent => ops{ .MultWrap = {} },
2127 .AsteriskPercent => ops{ .MulWrap = {} },
21282128 else => {
21292129 putBackToken(it, token.index);
21302130 return null;
lib/std/zig/render.zig+1-1
......@@ -1635,7 +1635,7 @@ fn renderExpression(
16351635 .If => {
16361636 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
16371637
1638 const lparen = tree.prevToken(if_node.condition.firstToken());
1638 const lparen = tree.nextToken(if_node.if_token);
16391639 const rparen = tree.nextToken(if_node.condition.lastToken());
16401640
16411641 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if
src-self-hosted/c_tokenizer.zig+214-114
......@@ -27,6 +27,10 @@ pub const CToken = struct {
2727 Lt,
2828 Comma,
2929 Fn,
30 Arrow,
31 LBrace,
32 RBrace,
33 Pipe,
3034 };
3135
3236 pub const NumLitSuffix = enum {
......@@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken {
7175 }
7276 } else return tok;
7377 var bytes = try allocator.alloc(u8, tok.bytes.len * 2);
74 var escape = false;
78 var state: enum {
79 Start,
80 Escape,
81 Hex,
82 Octal,
83 } = .Start;
7584 var i: usize = 0;
85 var count: u8 = 0;
86 var num: u8 = 0;
7687 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;
88 switch (state) {
89 .Escape => {
90 switch (c) {
91 'n', 'r', 't', '\\', '\'', '\"' => {
92 bytes[i] = c;
93 },
94 '0'...'7' => {
95 count += 1;
96 num += c - '0';
97 state = .Octal;
98 bytes[i] = 'x';
99 },
100 'x' => {
101 state = .Hex;
102 bytes[i] = 'x';
103 },
104 'a' => {
105 bytes[i] = 'x';
106 i += 1;
107 bytes[i] = '0';
108 i += 1;
109 bytes[i] = '7';
110 },
111 'b' => {
112 bytes[i] = 'x';
113 i += 1;
114 bytes[i] = '0';
115 i += 1;
116 bytes[i] = '8';
117 },
118 'f' => {
119 bytes[i] = 'x';
120 i += 1;
121 bytes[i] = '0';
122 i += 1;
123 bytes[i] = 'C';
124 },
125 'v' => {
126 bytes[i] = 'x';
127 i += 1;
128 bytes[i] = '0';
129 i += 1;
130 bytes[i] = 'B';
131 },
132 '?' => {
133 i -= 1;
134 bytes[i] = '?';
135 },
136 'u', 'U' => {
137 // TODO unicode escape sequences
138 return error.TokenizingFailed;
139 },
140 else => {
141 // unknown escape sequence
142 return error.TokenizingFailed;
143 },
144 }
145 i += 1;
146 if (state == .Escape)
147 state = .Start;
148 },
149 .Start => {
150 if (c == '\\') {
151 state = .Escape;
152 }
153 bytes[i] = c;
154 i += 1;
155 },
156 .Hex => {
157 switch (c) {
158 '0'...'9' => {
159 num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed;
160 num += c - '0';
161 },
162 'a'...'f' => {
163 num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed;
164 num += c - 'a' + 10;
165 },
166 'A'...'F' => {
167 num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed;
168 num += c - 'A' + 10;
169 },
170 else => {
171 i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2});
172 num = 0;
173 if (c == '\\')
174 state = .Escape
175 else
176 state = .Start;
177 bytes[i] = c;
178 i += 1;
179 },
180 }
181 },
182 .Octal => {
183 switch (c) {
184 '0'...'7' => {
185 count += 1;
186 num = std.math.mul(u8, num, 8) catch return error.TokenizingFailed;
187 num += c - '0';
188 if (count < 3)
189 continue;
190 },
191 else => {},
192 }
193 i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2});
194 state = .Start;
195 count = 0;
196 num = 0;
197 },
135198 }
136199 }
200 if (state == .Hex or state == .Octal)
201 i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2});
137202 return CToken{
138203 .id = tok.id,
139204 .bytes = bytes[0..i],
......@@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
164229 NumLitIntSuffixL,
165230 NumLitIntSuffixLL,
166231 NumLitIntSuffixUL,
232 Minus,
233 Done,
167234 } = .Start;
168235
169236 var result = CToken{
......@@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
178245 const c = chars[i.*];
179246 if (c == 0) {
180247 switch (state) {
181 .Start => {
182 return result;
183 },
184248 .Identifier,
185249 .Decimal,
186250 .Hex,
......@@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
193257 result.bytes = chars[begin_index..i.*];
194258 return result;
195259 },
260 .Start,
261 .Minus,
262 .Done,
196263 .NumLitIntSuffixU,
197264 .NumLitIntSuffixL,
198265 .NumLitIntSuffixUL,
......@@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
212279 => return error.TokenizingFailed,
213280 }
214281 }
215 i.* += 1;
216282 switch (state) {
217283 .Start => {
218284 switch (c) {
......@@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
220286 '\'' => {
221287 state = .CharLit;
222288 result.id = .CharLit;
223 begin_index = i.* - 1;
289 begin_index = i.*;
224290 },
225291 '\"' => {
226292 state = .String;
227293 result.id = .StrLit;
228 begin_index = i.* - 1;
294 begin_index = i.*;
229295 },
230296 '/' => {
231297 state = .OpenComment;
......@@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
239305 'a'...'z', 'A'...'Z', '_' => {
240306 state = .Identifier;
241307 result.id = .Identifier;
242 begin_index = i.* - 1;
308 begin_index = i.*;
243309 },
244310 '1'...'9' => {
245311 state = .Decimal;
246312 result.id = .NumLitInt;
247 begin_index = i.* - 1;
313 begin_index = i.*;
248314 },
249315 '0' => {
250316 state = .GotZero;
251317 result.id = .NumLitInt;
252 begin_index = i.* - 1;
318 begin_index = i.*;
253319 },
254320 '.' => {
255321 result.id = .Dot;
256 return result;
322 state = .Done;
257323 },
258324 '<' => {
259325 result.id = .Lt;
......@@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
261327 },
262328 '(' => {
263329 result.id = .LParen;
264 return result;
330 state = .Done;
265331 },
266332 ')' => {
267333 result.id = .RParen;
268 return result;
334 state = .Done;
269335 },
270336 '*' => {
271337 result.id = .Asterisk;
272 return result;
338 state = .Done;
273339 },
274340 '-' => {
341 state = .Minus;
275342 result.id = .Minus;
276 return result;
277343 },
278344 '!' => {
279345 result.id = .Bang;
280 return result;
346 state = .Done;
281347 },
282348 '~' => {
283349 result.id = .Tilde;
284 return result;
350 state = .Done;
285351 },
286352 ',' => {
287353 result.id = .Comma;
288 return result;
354 state = .Done;
355 },
356 '[' => {
357 result.id = .LBrace;
358 state = .Done;
359 },
360 ']' => {
361 result.id = .RBrace;
362 state = .Done;
363 },
364 '|' => {
365 result.id = .Pipe;
366 state = .Done;
289367 },
290368 else => return error.TokenizingFailed,
291369 }
292370 },
371 .Done => return result,
372 .Minus => {
373 switch (c) {
374 '>' => {
375 result.id = .Arrow;
376 state = .Done;
377 },
378 else => {
379 return result;
380 },
381 }
382 },
293383 .GotLt => {
294384 switch (c) {
295385 '<' => {
296386 result.id = .Shl;
297 return result;
387 state = .Done;
298388 },
299389 else => {
300390 return result;
......@@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
310400 'f',
311401 'F',
312402 => {
313 i.* -= 1;
314403 result.num_lit_suffix = .F;
315404 result.bytes = chars[begin_index..i.*];
316 return result;
405 state = .Done;
317406 },
318407 'l', 'L' => {
319 i.* -= 1;
320408 result.num_lit_suffix = .L;
321409 result.bytes = chars[begin_index..i.*];
322 return result;
410 state = .Done;
323411 },
324412 else => {
325 i.* -= 1;
326413 result.bytes = chars[begin_index..i.*];
327414 return result;
328415 },
......@@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
352439 '0'...'9' => {},
353440 'f', 'F' => {
354441 result.num_lit_suffix = .F;
355 result.bytes = chars[begin_index .. i.* - 1];
356 return result;
442 result.bytes = chars[begin_index..i.*];
443 state = .Done;
357444 },
358445 'l', 'L' => {
359446 result.num_lit_suffix = .L;
360 result.bytes = chars[begin_index .. i.* - 1];
361 return result;
447 result.bytes = chars[begin_index..i.*];
448 state = .Done;
362449 },
363450 else => {
364 i.* -= 1;
365451 result.bytes = chars[begin_index..i.*];
366452 return result;
367453 },
......@@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
374460 'u', 'U' => {
375461 state = .NumLitIntSuffixU;
376462 result.num_lit_suffix = .U;
377 result.bytes = chars[begin_index .. i.* - 1];
463 result.bytes = chars[begin_index..i.*];
378464 },
379465 'l', 'L' => {
380466 state = .NumLitIntSuffixL;
381467 result.num_lit_suffix = .L;
382 result.bytes = chars[begin_index .. i.* - 1];
468 result.bytes = chars[begin_index..i.*];
383469 },
384470 '.' => {
385471 result.id = .NumLitFloat;
386472 state = .Float;
387473 },
388474 else => {
389 i.* -= 1;
390475 result.bytes = chars[begin_index..i.*];
391476 return result;
392477 },
......@@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
407492 'u', 'U' => {
408493 state = .NumLitIntSuffixU;
409494 result.num_lit_suffix = .U;
410 result.bytes = chars[begin_index .. i.* - 1];
495 result.bytes = chars[begin_index..i.*];
411496 },
412497 'l', 'L' => {
413498 state = .NumLitIntSuffixL;
414499 result.num_lit_suffix = .L;
415 result.bytes = chars[begin_index .. i.* - 1];
500 result.bytes = chars[begin_index..i.*];
416501 },
417502 else => {
418503 i.* -= 1;
......@@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
425510 '0'...'7' => {},
426511 '8', '9' => return error.TokenizingFailed,
427512 else => {
428 i.* -= 1;
429513 result.bytes = chars[begin_index..i.*];
430514 return result;
431515 },
......@@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
438522 // marks the number literal as unsigned
439523 state = .NumLitIntSuffixU;
440524 result.num_lit_suffix = .U;
441 result.bytes = chars[begin_index .. i.* - 1];
525 result.bytes = chars[begin_index..i.*];
442526 },
443527 'l', 'L' => {
444528 // marks the number literal as long
445529 state = .NumLitIntSuffixL;
446530 result.num_lit_suffix = .L;
447 result.bytes = chars[begin_index .. i.* - 1];
531 result.bytes = chars[begin_index..i.*];
448532 },
449533 else => {
450 i.* -= 1;
451534 result.bytes = chars[begin_index..i.*];
452535 return result;
453536 },
......@@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
461544 // marks the number literal as unsigned
462545 state = .NumLitIntSuffixU;
463546 result.num_lit_suffix = .U;
464 result.bytes = chars[begin_index .. i.* - 1];
547 result.bytes = chars[begin_index..i.*];
465548 },
466549 'l', 'L' => {
467550 // marks the number literal as long
468551 state = .NumLitIntSuffixL;
469552 result.num_lit_suffix = .L;
470 result.bytes = chars[begin_index .. i.* - 1];
553 result.bytes = chars[begin_index..i.*];
471554 },
472555 else => {
473 i.* -= 1;
474556 result.bytes = chars[begin_index..i.*];
475557 return result;
476558 },
......@@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
483565 state = .NumLitIntSuffixUL;
484566 },
485567 else => {
486 i.* -= 1;
487568 return result;
488569 },
489570 }
......@@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
496577 },
497578 'u', 'U' => {
498579 result.num_lit_suffix = .LU;
499 return result;
580 state = .Done;
500581 },
501582 else => {
502 i.* -= 1;
503583 return result;
504584 },
505585 }
......@@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
508588 switch (c) {
509589 'u', 'U' => {
510590 result.num_lit_suffix = .LLU;
511 return result;
591 state = .Done;
512592 },
513593 else => {
514 i.* -= 1;
515594 return result;
516595 },
517596 }
......@@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
520599 switch (c) {
521600 'l', 'L' => {
522601 result.num_lit_suffix = .LLU;
523 return result;
602 state = .Done;
524603 },
525604 else => {
526 i.* -= 1;
527605 return result;
528606 },
529607 }
......@@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
532610 switch (c) {
533611 '_', 'a'...'z', 'A'...'Z', '0'...'9' => {},
534612 else => {
535 i.* -= 1;
536613 result.bytes = chars[begin_index..i.*];
537614 return result;
538615 },
539616 }
540617 },
541 .String => { // TODO char escapes
618 .String => {
542619 switch (c) {
543620 '\"' => {
544 result.bytes = chars[begin_index..i.*];
545 return result;
621 result.bytes = chars[begin_index .. i.* + 1];
622 state = .Done;
546623 },
547624 else => {},
548625 }
......@@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
550627 .CharLit => {
551628 switch (c) {
552629 '\'' => {
553 result.bytes = chars[begin_index..i.*];
554 return result;
630 result.bytes = chars[begin_index .. i.* + 1];
631 state = .Done;
555632 },
556633 else => {},
557634 }
......@@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
566643 },
567644 else => {
568645 result.id = .Slash;
569 return result;
646 state = .Done;
570647 },
571648 }
572649 },
......@@ -598,6 +675,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
598675 }
599676 },
600677 }
678 i.* += 1;
601679 }
602680 unreachable;
603681}
......@@ -645,7 +723,7 @@ test "tokenize macro" {
645723 expect(it.next() == null);
646724 tl.shrink(0);
647725
648 const src5 = "FOO 0l";
726 const src5 = "FOO 0ull";
649727 try tokenizeCMacro(&tl, src5);
650728 it = tl.iterator(0);
651729 expect(it.next().?.id == .Identifier);
......@@ -654,3 +732,25 @@ test "tokenize macro" {
654732 expect(it.next() == null);
655733 tl.shrink(0);
656734}
735
736test "escape sequences" {
737 var buf: [1024]u8 = undefined;
738 var alloc = std.heap.FixedBufferAllocator.init(buf[0..]);
739 const a = &alloc.allocator;
740 expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{
741 .id = .StrLit,
742 .bytes = "\\x0077",
743 })).bytes, "\\x77"));
744 expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{
745 .id = .StrLit,
746 .bytes = "\\24500",
747 })).bytes, "\\xa500"));
748 expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{
749 .id = .StrLit,
750 .bytes = "\\x0077 abc",
751 })).bytes, "\\x77 abc"));
752 expect(std.mem.eql(u8, (try zigifyEscapeSequences(a, .{
753 .id = .StrLit,
754 .bytes = "\\045abc",
755 })).bytes, "\\x25abc"));
756}
src-self-hosted/clang.zig+99-7
......@@ -76,6 +76,10 @@ pub const struct_ZigClangFunctionType = @OpaqueType();
7676pub const struct_ZigClangPredefinedExpr = @OpaqueType();
7777pub const struct_ZigClangInitListExpr = @OpaqueType();
7878pub const ZigClangPreprocessingRecord = @OpaqueType();
79pub const ZigClangFloatingLiteral = @OpaqueType();
80pub const ZigClangConstantExpr = @OpaqueType();
81pub const ZigClangCharacterLiteral = @OpaqueType();
82pub const ZigClangStmtExpr = @OpaqueType();
7983
8084pub const ZigClangBO = extern enum {
8185 PtrMemD,
......@@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum {
710714 UTF32,
711715};
712716
717pub const ZigClangCharacterLiteral_CharacterKind = extern enum {
718 Ascii,
719 Wide,
720 UTF8,
721 UTF16,
722 UTF32,
723};
724
713725pub const ZigClangRecordDecl_field_iterator = extern struct {
714726 opaque: *c_void,
715727};
......@@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum {
730742 InclusionDirectiveKind,
731743};
732744
745pub const ZigClangExpr_ConstExprUsage = extern enum {
746 EvaluateForCodeGen,
747 EvaluateForMangling,
748};
749
733750pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
734751pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
735752pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
......@@ -744,6 +761,8 @@ pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumTyp
744761pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
745762pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
746763pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl;
764pub extern fn ZigClangFunctionDecl_getCanonicalDecl(self: ?*const struct_ZigClangFunctionDecl) ?*const struct_ZigClangFunctionDecl;
765pub extern fn ZigClangVarDecl_getCanonicalDecl(self: ?*const struct_ZigClangVarDecl) ?*const struct_ZigClangVarDecl;
747766pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl;
748767pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl;
749768pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation;
......@@ -791,16 +810,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList
791810pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;
792811pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint;
793812pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind;
794pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPSInt;
813pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) *const struct_ZigClangAPSInt;
795814pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint;
796815pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint;
797816pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase;
798pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;
799pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;
800pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;
801pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;
802pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64;
803pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;
817pub extern fn ZigClangAPSInt_isSigned(self: *const struct_ZigClangAPSInt) bool;
818pub extern fn ZigClangAPSInt_isNegative(self: *const struct_ZigClangAPSInt) bool;
819pub extern fn ZigClangAPSInt_negate(self: *const struct_ZigClangAPSInt) *const struct_ZigClangAPSInt;
820pub extern fn ZigClangAPSInt_free(self: *const struct_ZigClangAPSInt) void;
821pub extern fn ZigClangAPSInt_getRawData(self: *const struct_ZigClangAPSInt) [*:0]const u64;
822pub extern fn ZigClangAPSInt_getNumWords(self: *const struct_ZigClangAPSInt) c_uint;
804823
805824pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;
806825pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;
......@@ -822,6 +841,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy
822841pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool;
823842pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint;
824843pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType;
844pub extern fn ZigClangFunctionProtoType_getReturnType(self: *const ZigClangFunctionProtoType) ZigClangQualType;
825845
826846pub const ZigClangSourceLocation = struct_ZigClangSourceLocation;
827847pub const ZigClangQualType = struct_ZigClangQualType;
......@@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple
976996pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType;
977997pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt;
978998pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl;
999pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl;
9791000
9801001pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
9811002
......@@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti
10361057pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8;
10371058pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
10381059pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
1060
1061pub extern fn ZigClangIfStmt_getThen(*const ZigClangIfStmt) *const ZigClangStmt;
1062pub extern fn ZigClangIfStmt_getElse(*const ZigClangIfStmt) ?*const ZigClangStmt;
1063pub extern fn ZigClangIfStmt_getCond(*const ZigClangIfStmt) *const ZigClangStmt;
1064
1065pub extern fn ZigClangWhileStmt_getCond(*const ZigClangWhileStmt) *const ZigClangExpr;
1066pub extern fn ZigClangWhileStmt_getBody(*const ZigClangWhileStmt) *const ZigClangStmt;
1067
1068pub extern fn ZigClangDoStmt_getCond(*const ZigClangDoStmt) *const ZigClangExpr;
1069pub extern fn ZigClangDoStmt_getBody(*const ZigClangDoStmt) *const ZigClangStmt;
1070
1071pub extern fn ZigClangForStmt_getInit(*const ZigClangForStmt) ?*const ZigClangStmt;
1072pub extern fn ZigClangForStmt_getCond(*const ZigClangForStmt) ?*const ZigClangExpr;
1073pub extern fn ZigClangForStmt_getInc(*const ZigClangForStmt) ?*const ZigClangExpr;
1074pub extern fn ZigClangForStmt_getBody(*const ZigClangForStmt) *const ZigClangStmt;
1075
1076pub extern fn ZigClangAPFloat_toString(self: *const ZigClangAPFloat, precision: c_uint, maxPadding: c_uint, truncateZero: bool) [*:0]const u8;
1077pub extern fn ZigClangAPFloat_getValueAsApproximateDouble(*const ZigClangFloatingLiteral) f64;
1078
1079pub extern fn ZigClangConditionalOperator_getCond(*const ZigClangConditionalOperator) *const ZigClangExpr;
1080pub extern fn ZigClangConditionalOperator_getTrueExpr(*const ZigClangConditionalOperator) *const ZigClangExpr;
1081pub extern fn ZigClangConditionalOperator_getFalseExpr(*const ZigClangConditionalOperator) *const ZigClangExpr;
1082
1083pub extern fn ZigClangSwitchStmt_getConditionVariableDeclStmt(*const ZigClangSwitchStmt) ?*const ZigClangDeclStmt;
1084pub extern fn ZigClangSwitchStmt_getCond(*const ZigClangSwitchStmt) *const ZigClangExpr;
1085pub extern fn ZigClangSwitchStmt_getBody(*const ZigClangSwitchStmt) *const ZigClangStmt;
1086pub extern fn ZigClangSwitchStmt_isAllEnumCasesCovered(*const ZigClangSwitchStmt) bool;
1087
1088pub extern fn ZigClangCaseStmt_getLHS(*const ZigClangCaseStmt) *const ZigClangExpr;
1089pub extern fn ZigClangCaseStmt_getRHS(*const ZigClangCaseStmt) ?*const ZigClangExpr;
1090pub extern fn ZigClangCaseStmt_getBeginLoc(*const ZigClangCaseStmt) ZigClangSourceLocation;
1091pub extern fn ZigClangCaseStmt_getSubStmt(*const ZigClangCaseStmt) *const ZigClangStmt;
1092
1093pub extern fn ZigClangDefaultStmt_getSubStmt(*const ZigClangDefaultStmt) *const ZigClangStmt;
1094
1095pub extern fn ZigClangExpr_EvaluateAsConstantExpr(*const ZigClangExpr, *ZigClangExprEvalResult, ZigClangExpr_ConstExprUsage, *const ZigClangASTContext) bool;
1096
1097pub extern fn ZigClangPredefinedExpr_getFunctionName(*const ZigClangPredefinedExpr) *const ZigClangStringLiteral;
1098
1099pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiteral) ZigClangSourceLocation;
1100pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind;
1101pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint;
1102
1103pub extern fn ZigClangStmtExpr_getSubStmt(*const ZigClangStmtExpr) *const ZigClangCompoundStmt;
1104
1105pub extern fn ZigClangMemberExpr_getBase(*const ZigClangMemberExpr) *const ZigClangExpr;
1106pub extern fn ZigClangMemberExpr_isArrow(*const ZigClangMemberExpr) bool;
1107pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const ZigClangValueDecl;
1108
1109pub extern fn ZigClangArraySubscriptExpr_getBase(*const ZigClangArraySubscriptExpr) *const ZigClangExpr;
1110pub extern fn ZigClangArraySubscriptExpr_getIdx(*const ZigClangArraySubscriptExpr) *const ZigClangExpr;
1111
1112pub extern fn ZigClangCallExpr_getCallee(*const ZigClangCallExpr) *const ZigClangExpr;
1113pub extern fn ZigClangCallExpr_getNumArgs(*const ZigClangCallExpr) c_uint;
1114pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const ZigClangExpr;
1115
1116pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangQualType;
1117pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangSourceLocation;
1118
1119pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigClangUO;
1120pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType;
1121pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr;
1122pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation;
1123
1124pub extern fn ZigClangCompoundAssignOperator_getType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
1125pub extern fn ZigClangCompoundAssignOperator_getComputationLHSType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
1126pub extern fn ZigClangCompoundAssignOperator_getComputationResultType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
1127pub extern fn ZigClangCompoundAssignOperator_getBeginLoc(*const ZigClangCompoundAssignOperator) ZigClangSourceLocation;
1128pub extern fn ZigClangCompoundAssignOperator_getOpcode(*const ZigClangCompoundAssignOperator) ZigClangBO;
1129pub extern fn ZigClangCompoundAssignOperator_getLHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;
1130pub extern fn ZigClangCompoundAssignOperator_getRHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;
src-self-hosted/translate_c.zig+2384-820
......@@ -8,6 +8,7 @@ const Token = std.zig.Token;
88usingnamespace @import("clang.zig");
99const ctok = @import("c_tokenizer.zig");
1010const CToken = ctok.CToken;
11const mem = std.mem;
1112
1213const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1314
......@@ -47,35 +48,34 @@ const Scope = struct {
4748 Switch,
4849 Block,
4950 Root,
50 While,
51 FnDef,
52 Ref,
51 Condition,
52 Loop,
5353 };
5454
5555 const Switch = struct {
5656 base: Scope,
57 };
58
59 /// used when getting a member `a.b`
60 const Ref = struct {
61 base: Scope,
57 pending_block: *ast.Node.Block,
58 cases: *ast.Node.Switch.CaseList,
59 has_default: bool = false,
6260 };
6361
6462 const Block = struct {
6563 base: Scope,
6664 block_node: *ast.Node.Block,
6765 variables: AliasList,
66 label: ?[]const u8,
6867
69 /// Don't forget to set rbrace token later
70 fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block {
68 /// Don't forget to set rbrace token and block_node later
69 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block {
7170 const block = try c.a().create(Block);
7271 block.* = .{
7372 .base = .{
7473 .id = .Block,
7574 .parent = parent,
7675 },
77 .block_node = block_node,
76 .block_node = undefined,
7877 .variables = AliasList.init(c.a()),
78 .label = label,
7979 };
8080 return block;
8181 }
......@@ -83,7 +83,7 @@ const Scope = struct {
8383 fn getAlias(scope: *Block, name: []const u8) ?[]const u8 {
8484 var it = scope.variables.iterator(0);
8585 while (it.next()) |p| {
86 if (std.mem.eql(u8, p.name, name))
86 if (mem.eql(u8, p.name, name))
8787 return p.alias;
8888 }
8989 return scope.base.parent.?.getAlias(name);
......@@ -92,7 +92,7 @@ const Scope = struct {
9292 fn contains(scope: *Block, name: []const u8) bool {
9393 var it = scope.variables.iterator(0);
9494 while (it.next()) |p| {
95 if (std.mem.eql(u8, p.name, name))
95 if (mem.eql(u8, p.name, name))
9696 return true;
9797 }
9898 return scope.base.parent.?.contains(name);
......@@ -120,52 +120,23 @@ const Scope = struct {
120120 }
121121 };
122122
123 const While = struct {
124 base: Scope,
125 };
126
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,
123 fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block {
124 var scope = inner;
125 while (true) {
126 switch (scope.id) {
127 .Root => unreachable,
128 .Block => return @fieldParentPtr(Block, "base", scope),
129 .Condition => {
130 // comma operator used
131 return try Block.init(c, scope, "blk");
136132 },
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;
133 else => scope = scope.parent.?,
146134 }
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);
164135 }
165136 }
166137
167138 fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 {
168 if (scope.contains(name)) {
139 if (isZigPrimitiveType(name) or scope.contains(name)) {
169140 return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() });
170141 }
171142 return null;
......@@ -174,22 +145,41 @@ const Scope = struct {
174145 fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 {
175146 return switch (scope.id) {
176147 .Root => null,
177 .Ref => null,
178 .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
179148 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
180 else => @panic("TODO Scope.getAlias"),
149 .Switch, .Loop, .Condition => scope.parent.?.getAlias(name),
181150 };
182151 }
183152
184153 fn contains(scope: *Scope, name: []const u8) bool {
185154 return switch (scope.id) {
186 .Ref => false,
187155 .Root => @fieldParentPtr(Root, "base", scope).contains(name),
188 .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
189156 .Block => @fieldParentPtr(Block, "base", scope).contains(name),
190 else => @panic("TODO Scope.contains"),
157 .Switch, .Loop, .Condition => scope.parent.?.contains(name),
191158 };
192159 }
160
161 fn getBreakableScope(inner: *Scope) *Scope {
162 var scope = inner;
163 while (true) {
164 switch (scope.id) {
165 .Root => unreachable,
166 .Switch => return scope,
167 .Loop => return scope,
168 else => scope = scope.parent.?,
169 }
170 }
171 }
172
173 fn getSwitch(inner: *Scope) *Scope.Switch {
174 var scope = inner;
175 while (true) {
176 switch (scope.id) {
177 .Root => unreachable,
178 .Switch => return @fieldParentPtr(Switch, "base", scope),
179 else => scope = scope.parent.?,
180 }
181 }
182 }
193183};
194184
195185const Context = struct {
......@@ -200,7 +190,6 @@ const Context = struct {
200190 decl_table: DeclTable,
201191 alias_list: AliasList,
202192 global_scope: *Scope.Root,
203 ptr_params: std.BufSet,
204193 clang_context: *ZigClangASTContext,
205194 mangle_count: u64 = 0,
206195
......@@ -209,13 +198,13 @@ const Context = struct {
209198 return c.mangle_count;
210199 }
211200
212 fn a(c: *Context) *std.mem.Allocator {
201 fn a(c: *Context) *mem.Allocator {
213202 return &c.tree.arena_allocator.allocator;
214203 }
215204
216205 /// Convert a null-terminated C string to a slice allocated in the arena
217206 fn str(c: *Context, s: [*:0]const u8) ![]u8 {
218 return std.mem.dupe(c.a(), u8, std.mem.toSliceConst(u8, s));
207 return mem.dupe(c.a(), u8, mem.toSliceConst(u8, s));
219208 }
220209
221210 /// Convert a clang source location to a file:line:column string
......@@ -231,7 +220,7 @@ const Context = struct {
231220};
232221
233222pub fn translate(
234 backing_allocator: *std.mem.Allocator,
223 backing_allocator: *mem.Allocator,
235224 args_begin: [*]?[*]const u8,
236225 args_end: [*]?[*]const u8,
237226 errors: *[]ClangErrMsg,
......@@ -286,7 +275,6 @@ pub fn translate(
286275 .decl_table = DeclTable.init(arena),
287276 .alias_list = AliasList.init(arena),
288277 .global_scope = try arena.create(Scope.Root),
289 .ptr_params = std.BufSet.init(arena),
290278 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
291279 };
292280 context.global_scope.* = Scope.Root.init(&context);
......@@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
333321 return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));
334322 },
335323 .Typedef => {
336 return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
324 _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
337325 },
338326 .Enum => {
339327 _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl));
340328 },
341329 .Record => {
342 return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
330 _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
343331 },
344332 .Var => {
345333 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
......@@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
352340}
353341
354342fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
355 if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice
356 const rp = makeRestorePoint(c);
357343 const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));
358 _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name);
344 if (c.global_scope.sym_table.contains(fn_name))
345 return; // Avoid processing this decl twice
346 const rp = makeRestorePoint(c);
359347 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);
360 const fn_qt = ZigClangFunctionDecl_getType(fn_decl);
361 const fn_type = ZigClangQualType_getTypePtr(fn_qt);
362 var fndef_scope = Scope.FnDef.init(c);
363 var scope = &fndef_scope.base;
364348 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
365349 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
366350 const decl_ctx = FnDeclContext{
367351 .fn_name = fn_name,
368352 .has_body = has_body,
369353 .storage_class = storage_class,
370 .scope = &scope,
371354 .is_export = switch (storage_class) {
372355 .None => has_body,
373356 .Extern, .Static => false,
......@@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
377360 else => unreachable,
378361 },
379362 };
363
364 var fn_qt = ZigClangFunctionDecl_getType(fn_decl);
365 var fn_type = ZigClangQualType_getTypePtr(fn_qt);
366 if (ZigClangType_getTypeClass(fn_type) == .Attributed) {
367 const attr_type = @ptrCast(*const ZigClangAttributedType, fn_type);
368 fn_qt = ZigClangAttributedType_getEquivalentType(attr_type);
369 fn_type = ZigClangQualType_getTypePtr(fn_qt);
370 }
371
380372 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
381373 .FunctionProto => blk: {
382374 const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type);
......@@ -396,7 +388,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
396388 error.OutOfMemory => |e| return e,
397389 };
398390 },
399 else => unreachable,
391 else => return failDecl(c, fn_decl_loc, fn_name, "unable to resolve function type {}", .{ZigClangType_getTypeClass(fn_type)}),
400392 };
401393
402394 if (!decl_ctx.has_body) {
......@@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
406398
407399 // actual function definition with body
408400 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);
409 const body_node = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) {
401 const block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null);
402 var scope = &block_scope.base;
403 const block_node = try transCreateNodeBlock(rp.c, null);
404 block_scope.block_node = block_node;
405
406 var it = proto_node.params.iterator(0);
407 while (it.next()) |p| {
408 const param = @fieldParentPtr(ast.Node.ParamDecl, "base", p.*);
409 const param_name = tokenSlice(c, param.name_token orelse
410 return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name}));
411
412 const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: {
413 try block_scope.variables.push(.{ .name = param_name, .alias = a });
414 break :blk a;
415 } else param_name;
416 const arg_name = try std.fmt.allocPrint(c.a(), "_arg_{}", .{checked_param_name});
417
418 const node = try transCreateNodeVarDecl(c, false, false, checked_param_name);
419 node.eq_token = try appendToken(c, .Equal, "=");
420 node.init_node = try transCreateNodeIdentifier(c, arg_name);
421 node.semicolon_token = try appendToken(c, .Semicolon, ";");
422 try block_node.statements.push(&node.base);
423 param.name_token = try appendIdentifier(c, arg_name);
424 _ = try appendToken(c, .Colon, ":");
425 }
426
427 transCompoundStmtInline(rp, &block_scope.base, @ptrCast(*const ZigClangCompoundStmt, body_stmt), block_node) catch |err| switch (err) {
410428 error.OutOfMemory => |e| return e,
411429 error.UnsupportedTranslation,
412430 error.UnsupportedType,
413431 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
414432 };
415 assert(body_node.id == .Block);
416 proto_node.body_node = body_node;
417
433 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
434 proto_node.body_node = &block_node.base;
418435 return addTopLevelDecl(c, fn_name, &proto_node.base);
419436}
420437
421438fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
422 if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice
439 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
440 if (c.global_scope.sym_table.contains(var_name))
441 return; // Avoid processing this decl twice
423442 const rp = makeRestorePoint(c);
424443 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
425444
......@@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
429448 try appendToken(c, .Keyword_threadlocal, "threadlocal");
430449
431450 const scope = &c.global_scope.base;
432 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));
433 _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);
451
452 // TODO https://github.com/ziglang/zig/issues/3756
453 // TODO https://github.com/ziglang/zig/issues/1802
454 const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "_{}", .{var_name}) else var_name;
434455 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
435456
436457 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
......@@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
449470 else
450471 try appendToken(c, .Keyword_var, "var");
451472
452 const name_tok = try appendIdentifier(c, var_name);
473 const name_tok = try appendIdentifier(c, checked_name);
453474
454475 _ = try appendToken(c, .Colon, ":");
455476 const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) {
456477 error.UnsupportedType => {
457 return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{});
478 return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});
458479 },
459480 error.OutOfMemory => |e| return e,
460481 };
......@@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
469490 error.UnsupportedTranslation,
470491 error.UnsupportedType,
471492 => {
472 return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{});
493 return failDecl(c, var_decl_loc, checked_name, "unable to translate initializer", .{});
473494 },
474495 error.OutOfMemory => |e| return e,
475496 }
476497 else
477498 try transCreateNodeUndefinedLiteral(c);
478499 } else if (storage_class != .Extern) {
479 return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{});
500 return failDecl(c, var_decl_loc, checked_name, "non-extern variable has no initializer", .{});
480501 }
481502
482503 const node = try c.a().create(ast.Node.VarDecl);
......@@ -496,269 +517,538 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
496517 .init_node = init_node,
497518 .semicolon_token = try appendToken(c, .Semicolon, ";"),
498519 };
499 return addTopLevelDecl(c, var_name, &node.base);
520 return addTopLevelDecl(c, checked_name, &node.base);
500521}
501522
502fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {
503 if (c.decl_table.contains(
504 @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)),
505 )) return; // Avoid processing this decl twice
523fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, builtin_name: []const u8) !*ast.Node {
524 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), builtin_name);
525 return transCreateNodeIdentifier(c, builtin_name);
526}
527
528fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!?*ast.Node {
529 if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv|
530 return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
506531 const rp = makeRestorePoint(c);
507 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
508 const const_tok = try appendToken(c, .Keyword_const, "const");
509532
510533 const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
534
535 if (mem.eql(u8, typedef_name, "uint8_t"))
536 return transTypeDefAsBuiltin(c, typedef_decl, "u8")
537 else if (mem.eql(u8, typedef_name, "int8_t"))
538 return transTypeDefAsBuiltin(c, typedef_decl, "i8")
539 else if (mem.eql(u8, typedef_name, "uint16_t"))
540 return transTypeDefAsBuiltin(c, typedef_decl, "u16")
541 else if (mem.eql(u8, typedef_name, "int16_t"))
542 return transTypeDefAsBuiltin(c, typedef_decl, "i16")
543 else if (mem.eql(u8, typedef_name, "uint32_t"))
544 return transTypeDefAsBuiltin(c, typedef_decl, "u32")
545 else if (mem.eql(u8, typedef_name, "int32_t"))
546 return transTypeDefAsBuiltin(c, typedef_decl, "i32")
547 else if (mem.eql(u8, typedef_name, "uint64_t"))
548 return transTypeDefAsBuiltin(c, typedef_decl, "u64")
549 else if (mem.eql(u8, typedef_name, "int64_t"))
550 return transTypeDefAsBuiltin(c, typedef_decl, "i64")
551 else if (mem.eql(u8, typedef_name, "intptr_t"))
552 return transTypeDefAsBuiltin(c, typedef_decl, "isize")
553 else if (mem.eql(u8, typedef_name, "uintptr_t"))
554 return transTypeDefAsBuiltin(c, typedef_decl, "usize")
555 else if (mem.eql(u8, typedef_name, "ssize_t"))
556 return transTypeDefAsBuiltin(c, typedef_decl, "isize")
557 else if (mem.eql(u8, typedef_name, "size_t"))
558 return transTypeDefAsBuiltin(c, typedef_decl, "usize");
559
511560 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name);
512 const name_tok = try appendIdentifier(c, typedef_name);
513 const eq_tok = try appendToken(c, .Equal, "=");
561 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
562 const const_tok = try appendToken(c, .Keyword_const, "const");
563 const node = try transCreateNodeVarDecl(c, true, true, typedef_name);
564 node.eq_token = try appendToken(c, .Equal, "=");
514565
515566 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
516567 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
517 const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
568 node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
518569 error.UnsupportedType => {
519 return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
570 try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
571 return null;
520572 },
521573 error.OutOfMemory => |e| return e,
522574 };
523
524 const node = try c.a().create(ast.Node.VarDecl);
525 node.* = ast.Node.VarDecl{
526 .doc_comments = null,
527 .visib_token = visib_tok,
528 .thread_local_token = null,
529 .name_token = name_tok,
530 .eq_token = eq_tok,
531 .mut_token = const_tok,
532 .comptime_token = null,
533 .extern_export_token = null,
534 .lib_name = null,
535 .type_node = null,
536 .align_node = null,
537 .section_node = null,
538 .init_node = type_node,
539 .semicolon_token = try appendToken(c, .Semicolon, ";"),
540 };
575 node.semicolon_token = try appendToken(c, .Semicolon, ";");
541576 try addTopLevelDecl(c, typedef_name, &node.base);
577 return transCreateNodeIdentifier(c, typedef_name);
542578}
543579
544fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {
545 if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice
546 const rp = makeRestorePoint(c);
547
548 const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
549
550 const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
551 "union"
552 else if (ZigClangRecordDecl_isStruct(record_decl))
553 "struct"
554 else
555 return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
580fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
581 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|
582 return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
583 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
556584
557 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
558 return;
585 var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
586 var is_unnamed = false;
587 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) {
588 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
589 is_unnamed = true;
590 }
559591
560 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
561 const const_tok = try appendToken(c, .Keyword_const, "const");
592 var container_kind_name: []const u8 = undefined;
593 var container_kind: std.zig.Token.Id = undefined;
594 if (ZigClangRecordDecl_isUnion(record_decl)) {
595 container_kind_name = "union";
596 container_kind = .Keyword_union;
597 } else if (ZigClangRecordDecl_isStruct(record_decl)) {
598 container_kind_name = "struct";
599 container_kind = .Keyword_struct;
600 } else {
601 try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name});
602 return null;
603 }
562604
563605 const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
564606 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
565 const name_tok = try appendIdentifier(c, name);
566607
567 const eq_tok = try appendToken(c, .Equal, "=");
568 const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) {
569 error.UnsupportedType => {
570 return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{});
571 },
572 error.OutOfMemory => |e| return e,
573 };
574 const semicolon_token = try appendToken(c, .Semicolon, ";");
608 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
575609
576 const node = try c.a().create(ast.Node.VarDecl);
577 node.* = ast.Node.VarDecl{
578 .doc_comments = null,
579 .visib_token = visib_tok,
580 .thread_local_token = null,
581 .name_token = name_tok,
582 .eq_token = eq_tok,
583 .mut_token = const_tok,
584 .comptime_token = null,
585 .extern_export_token = null,
586 .lib_name = null,
587 .type_node = null,
588 .align_node = null,
589 .section_node = null,
590 .init_node = init_node,
591 .semicolon_token = semicolon_token,
610 node.eq_token = try appendToken(c, .Equal, "=");
611
612 var semicolon: ast.TokenIndex = undefined;
613 node.init_node = blk: {
614 const rp = makeRestorePoint(c);
615 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
616 const opaque = try transCreateNodeOpaqueType(c);
617 semicolon = try appendToken(c, .Semicolon, ";");
618 break :blk opaque;
619 };
620
621 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
622 const container_tok = try appendToken(c, container_kind, container_kind_name);
623 const lbrace_token = try appendToken(c, .LBrace, "{");
624
625 const container_node = try c.a().create(ast.Node.ContainerDecl);
626 container_node.* = .{
627 .layout_token = extern_tok,
628 .kind_token = container_tok,
629 .init_arg_expr = .None,
630 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
631 .lbrace_token = lbrace_token,
632 .rbrace_token = undefined,
633 };
634
635 var it = ZigClangRecordDecl_field_begin(record_def);
636 const end_it = ZigClangRecordDecl_field_end(record_def);
637 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
638 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
639 const field_loc = ZigClangFieldDecl_getLocation(field_decl);
640
641 if (ZigClangFieldDecl_isBitField(field_decl)) {
642 const opaque = try transCreateNodeOpaqueType(c);
643 semicolon = try appendToken(c, .Semicolon, ";");
644 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
645 break :blk opaque;
646 }
647 const raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)));
648 if (raw_name.len < 1) continue; // fix weird windows bug?
649 const field_name = try appendIdentifier(c, raw_name);
650 _ = try appendToken(c, .Colon, ":");
651 const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {
652 error.UnsupportedType => {
653 try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name});
654 return null;
655 },
656 else => |e| return e,
657 };
658
659 const field_node = try c.a().create(ast.Node.ContainerField);
660 field_node.* = .{
661 .doc_comments = null,
662 .comptime_token = null,
663 .name_token = field_name,
664 .type_expr = field_type,
665 .value_expr = null,
666 .align_expr = null,
667 };
668
669 try container_node.fields_and_decls.push(&field_node.base);
670 _ = try appendToken(c, .Comma, ",");
671 }
672 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
673 semicolon = try appendToken(c, .Semicolon, ";");
674 break :blk &container_node.base;
592675 };
676 node.semicolon_token = semicolon;
593677
594678 try addTopLevelDecl(c, name, &node.base);
595 try c.alias_list.push(.{ .alias = bare_name, .name = name });
679 if (!is_unnamed)
680 try c.alias_list.push(.{ .alias = bare_name, .name = name });
681 return transCreateNodeIdentifier(c, name);
596682}
597683
598fn createAlias(c: *Context, alias: var) !void {
599 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
600 const mut_tok = try appendToken(c, .Keyword_const, "const");
601 const name_tok = try appendIdentifier(c, alias.alias);
684fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
685 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
686 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
687 const rp = makeRestorePoint(c);
688 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
602689
603 const eq_tok = try appendToken(c, .Equal, "=");
604 const init_node = try transCreateNodeIdentifier(c, alias.name);
690 var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
691 var is_unnamed = false;
692 if (bare_name.len == 0) {
693 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
694 is_unnamed = true;
695 }
605696
606 const node = try c.a().create(ast.Node.VarDecl);
607 node.* = ast.Node.VarDecl{
608 .doc_comments = null,
609 .visib_token = visib_tok,
610 .thread_local_token = null,
611 .name_token = name_tok,
612 .eq_token = eq_tok,
613 .mut_token = mut_tok,
614 .comptime_token = null,
615 .extern_export_token = null,
616 .lib_name = null,
617 .type_node = null,
618 .align_node = null,
619 .section_node = null,
620 .init_node = init_node,
621 .semicolon_token = try appendToken(c, .Semicolon, ";"),
622 };
623 return addTopLevelDecl(c, alias.alias, &node.base);
624}
697 const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
698 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
699 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
700 node.eq_token = try appendToken(c, .Equal, "=");
625701
626const ResultUsed = enum {
627 used,
628 unused,
629};
702 node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
703 var pure_enum = true;
704 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
705 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
706 while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
707 const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
708 if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| {
709 pure_enum = false;
710 break;
711 }
712 }
630713
631const LRValue = enum {
632 l_value,
633 r_value,
634};
714 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
715 const container_tok = try appendToken(c, .Keyword_enum, "enum");
635716
636fn transStmt(
637 rp: RestorePoint,
638 scope: *Scope,
639 stmt: *const ZigClangStmt,
640 result_used: ResultUsed,
641 lrvalue: LRValue,
642) TransError!*ast.Node {
643 const sc = ZigClangStmt_getStmtClass(stmt);
644 switch (sc) {
645 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),
646 .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)),
647 .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const ZigClangCStyleCastExpr, stmt), result_used, lrvalue),
648 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),
649 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),
650 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used),
651 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used),
652 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),
653 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
654 .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue),
655 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),
656 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
657 else => {
658 return revertAndWarn(
659 rp,
660 error.UnsupportedTranslation,
661 ZigClangStmt_getBeginLoc(stmt),
662 "TODO implement translation of stmt class {}",
663 .{@tagName(sc)},
664 );
665 },
666 }
667}
717 const container_node = try c.a().create(ast.Node.ContainerDecl);
718 container_node.* = .{
719 .layout_token = extern_tok,
720 .kind_token = container_tok,
721 .init_arg_expr = .None,
722 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
723 .lbrace_token = undefined,
724 .rbrace_token = undefined,
725 };
668726
669fn transBinaryOperator(
670 rp: RestorePoint,
671 scope: *Scope,
672 stmt: *const ZigClangBinaryOperator,
673 result_used: ResultUsed,
674) TransError!*ast.Node {
675 const op = ZigClangBinaryOperator_getOpcode(stmt);
676 const qt = ZigClangBinaryOperator_getType(stmt);
677 switch (op) {
678 .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(
679 rp,
680 error.UnsupportedTranslation,
681 ZigClangBinaryOperator_getBeginLoc(stmt),
682 "TODO: handle more C binary operators: {}",
683 .{op},
684 ),
685 .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,
686 .Add => {
687 const node = if (cIsUnsignedInteger(qt))
688 try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)
727 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
728
729 // TODO only emit this tag type if the enum tag type is not the default.
730 // I don't know what the default is, need to figure out how clang is deciding.
731 // it appears to at least be different across gcc/msvc
732 if (!isCBuiltinType(int_type, .UInt) and
733 !isCBuiltinType(int_type, .Int))
734 {
735 _ = try appendToken(c, .LParen, "(");
736 container_node.init_arg_expr = .{
737 .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
738 error.UnsupportedType => {
739 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
740 return null;
741 },
742 else => |e| return e,
743 },
744 };
745 _ = try appendToken(c, .RParen, ")");
746 }
747
748 container_node.lbrace_token = try appendToken(c, .LBrace, "{");
749
750 it = ZigClangEnumDecl_enumerator_begin(enum_def);
751 end_it = ZigClangEnumDecl_enumerator_end(enum_def);
752 while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
753 const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
754
755 const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const)));
756
757 const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))
758 enum_val_name[bare_name.len..]
689759 else
690 try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);
691 return maybeSuppressResult(rp, scope, result_used, node);
760 enum_val_name;
761
762 const field_name_tok = try appendIdentifier(c, field_name);
763
764 const int_node = if (!pure_enum) blk: {
765 _ = try appendToken(c, .Colon, "=");
766 break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
767 } else
768 null;
769
770 const field_node = try c.a().create(ast.Node.ContainerField);
771 field_node.* = .{
772 .doc_comments = null,
773 .comptime_token = null,
774 .name_token = field_name_tok,
775 .type_expr = null,
776 .value_expr = int_node,
777 .align_expr = null,
778 };
779
780 try container_node.fields_and_decls.push(&field_node.base);
781 _ = try appendToken(c, .Comma, ",");
782 // In C each enum value is in the global namespace. So we put them there too.
783 // At this point we can rely on the enum emitting successfully.
784 const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name);
785 tld_node.eq_token = try appendToken(c, .Equal, "=");
786 tld_node.init_node = try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
787 tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
788 try addTopLevelDecl(c, field_name, &tld_node.base);
789 }
790 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
791
792 break :blk &container_node.base;
793 } else
794 try transCreateNodeOpaqueType(c);
795
796 node.semicolon_token = try appendToken(c, .Semicolon, ";");
797
798 try addTopLevelDecl(c, name, &node.base);
799 if (!is_unnamed)
800 try c.alias_list.push(.{ .alias = bare_name, .name = name });
801 return transCreateNodeIdentifier(c, name);
802}
803
804fn createAlias(c: *Context, alias: var) !void {
805 const node = try transCreateNodeVarDecl(c, true, true, alias.alias);
806 node.eq_token = try appendToken(c, .Equal, "=");
807 node.init_node = try transCreateNodeIdentifier(c, alias.name);
808 node.semicolon_token = try appendToken(c, .Semicolon, ";");
809 return addTopLevelDecl(c, alias.alias, &node.base);
810}
811
812const ResultUsed = enum {
813 used,
814 unused,
815};
816
817const LRValue = enum {
818 l_value,
819 r_value,
820};
821
822fn transStmt(
823 rp: RestorePoint,
824 scope: *Scope,
825 stmt: *const ZigClangStmt,
826 result_used: ResultUsed,
827 lrvalue: LRValue,
828) TransError!*ast.Node {
829 const sc = ZigClangStmt_getStmtClass(stmt);
830 switch (sc) {
831 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used),
832 .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)),
833 .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const ZigClangCStyleCastExpr, stmt), result_used, lrvalue),
834 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),
835 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),
836 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used),
837 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used),
838 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),
839 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
840 .ParenExprClass => {
841 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue);
842 if (expr.id == .GroupedExpression) return expr;
843 const node = try rp.c.a().create(ast.Node.GroupedExpression);
844 node.* = .{
845 .lparen = try appendToken(rp.c, .LParen, "("),
846 .expr = expr,
847 .rparen = try appendToken(rp.c, .RParen, ")"),
848 };
849 return &node.base;
692850 },
693 .Sub => {
694 const node = if (cIsUnsignedInteger(qt))
695 try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)
696 else
697 try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);
698 return maybeSuppressResult(rp, scope, result_used, node);
851 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),
852 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
853 .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)),
854 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
855 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
856 .NullStmtClass => {
857 const block = try transCreateNodeBlock(rp.c, null);
858 block.rbrace = try appendToken(rp.c, .RBrace, "}");
859 return &block.base;
699860 },
700 .Mul => {
701 const node = if (cIsUnsignedInteger(qt))
702 try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)
703 else
704 try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);
705 return maybeSuppressResult(rp, scope, result_used, node);
861 .ContinueStmtClass => return try transCreateNodeContinue(rp.c),
862 .BreakStmtClass => return transBreak(rp, scope),
863 .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)),
864 .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const ZigClangFloatingLiteral, stmt), result_used),
865 .ConditionalOperatorClass => return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used),
866 .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const ZigClangSwitchStmt, stmt)),
867 .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const ZigClangCaseStmt, stmt)),
868 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
869 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
870 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),
871 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used),
872 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),
873 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),
874 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
875 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
876 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),
877 .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used),
878 .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used),
879 else => {
880 return revertAndWarn(
881 rp,
882 error.UnsupportedTranslation,
883 ZigClangStmt_getBeginLoc(stmt),
884 "TODO implement translation of stmt class {}",
885 .{@tagName(sc)},
886 );
887 },
888 }
889}
890
891fn transBinaryOperator(
892 rp: RestorePoint,
893 scope: *Scope,
894 stmt: *const ZigClangBinaryOperator,
895 result_used: ResultUsed,
896) TransError!*ast.Node {
897 const op = ZigClangBinaryOperator_getOpcode(stmt);
898 const qt = ZigClangBinaryOperator_getType(stmt);
899 var op_token: ast.TokenIndex = undefined;
900 var op_id: ast.Node.InfixOp.Op = undefined;
901 switch (op) {
902 .Assign => return transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
903 .Comma => {
904 const block_scope = try scope.findBlockScope(rp.c);
905 const expr = block_scope.base.parent == scope;
906 const lparen = if (expr) blk: {
907 const l = try appendToken(rp.c, .LParen, "(");
908 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
909 break :blk l;
910 } else undefined;
911
912 const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value);
913 try block_scope.block_node.statements.push(lhs);
914
915 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
916 if (expr) {
917 _ = try appendToken(rp.c, .Semicolon, ";");
918 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
919 break_node.rhs = rhs;
920 try block_scope.block_node.statements.push(&break_node.base);
921 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
922 const rparen = try appendToken(rp.c, .RParen, ")");
923 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
924 grouped_expr.* = .{
925 .lparen = lparen,
926 .expr = &block_scope.block_node.base,
927 .rparen = rparen,
928 };
929 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
930 } else {
931 return maybeSuppressResult(rp, scope, result_used, rhs);
932 }
706933 },
707934 .Div => {
708935 if (!cIsUnsignedInteger(qt)) {
709936 // signed integer division uses @divTrunc
710937 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
711 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
712 try div_trunc_node.params.push(lhs);
938 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
713939 _ = try appendToken(rp.c, .Comma, ",");
714940 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
715941 try div_trunc_node.params.push(rhs);
716942 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
717943 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
718 } else {
719 // unsigned/float division uses the operator
720 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true);
721 return maybeSuppressResult(rp, scope, result_used, node);
722944 }
723945 },
724946 .Rem => {
725947 if (!cIsUnsignedInteger(qt)) {
726948 // signed integer division uses @rem
727949 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
728 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
729 try rem_node.params.push(lhs);
950 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
730951 _ = try appendToken(rp.c, .Comma, ",");
731952 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
732953 try rem_node.params.push(rhs);
733954 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
734955 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
956 }
957 },
958 .Shl => {
959 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
960 return maybeSuppressResult(rp, scope, result_used, node);
961 },
962 .Shr => {
963 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
964 return maybeSuppressResult(rp, scope, result_used, node);
965 },
966 .LAnd => {
967 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true);
968 return maybeSuppressResult(rp, scope, result_used, node);
969 },
970 .LOr => {
971 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true);
972 return maybeSuppressResult(rp, scope, result_used, node);
973 },
974 else => {},
975 }
976 const lhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
977 switch (op) {
978 .Add => {
979 if (cIsUnsignedInteger(qt)) {
980 op_token = try appendToken(rp.c, .PlusPercent, "+%");
981 op_id = .AddWrap;
735982 } else {
736 // unsigned/float division uses the operator
737 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);
738 return maybeSuppressResult(rp, scope, result_used, node);
983 op_token = try appendToken(rp.c, .Plus, "+");
984 op_id = .Add;
739985 }
740986 },
741 .Shl,
742 .Shr,
743 .LT,
744 .GT,
745 .LE,
746 .GE,
747 .EQ,
748 .NE,
749 .And,
750 .Xor,
751 .Or,
752 .LAnd,
753 .LOr,
754 .Comma,
755 => return revertAndWarn(
756 rp,
757 error.UnsupportedTranslation,
758 ZigClangBinaryOperator_getBeginLoc(stmt),
759 "TODO: handle more C binary operators: {}",
760 .{op},
761 ),
987 .Sub => {
988 if (cIsUnsignedInteger(qt)) {
989 op_token = try appendToken(rp.c, .MinusPercent, "-%");
990 op_id = .SubWrap;
991 } else {
992 op_token = try appendToken(rp.c, .Minus, "-");
993 op_id = .Sub;
994 }
995 },
996 .Mul => {
997 if (cIsUnsignedInteger(qt)) {
998 op_token = try appendToken(rp.c, .AsteriskPercent, "*%");
999 op_id = .MulWrap;
1000 } else {
1001 op_token = try appendToken(rp.c, .Asterisk, "*");
1002 op_id = .Mul;
1003 }
1004 },
1005 .Div => {
1006 // unsigned/float division uses the operator
1007 op_id = .Div;
1008 op_token = try appendToken(rp.c, .Slash, "/");
1009 },
1010 .Rem => {
1011 // unsigned/float division uses the operator
1012 op_id = .Mod;
1013 op_token = try appendToken(rp.c, .Percent, "%");
1014 },
1015 .LT => {
1016 op_id = .LessThan;
1017 op_token = try appendToken(rp.c, .AngleBracketLeft, "<");
1018 },
1019 .GT => {
1020 op_id = .GreaterThan;
1021 op_token = try appendToken(rp.c, .AngleBracketRight, ">");
1022 },
1023 .LE => {
1024 op_id = .LessOrEqual;
1025 op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<=");
1026 },
1027 .GE => {
1028 op_id = .GreaterOrEqual;
1029 op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">=");
1030 },
1031 .EQ => {
1032 op_id = .EqualEqual;
1033 op_token = try appendToken(rp.c, .EqualEqual, "==");
1034 },
1035 .NE => {
1036 op_id = .BangEqual;
1037 op_token = try appendToken(rp.c, .BangEqual, "!=");
1038 },
1039 .And => {
1040 op_id = .BitAnd;
1041 op_token = try appendToken(rp.c, .Ampersand, "&");
1042 },
1043 .Xor => {
1044 op_id = .BitXor;
1045 op_token = try appendToken(rp.c, .Caret, "^");
1046 },
1047 .Or => {
1048 op_id = .BitOr;
1049 op_token = try appendToken(rp.c, .Pipe, "|");
1050 },
1051 .Assign,
7621052 .MulAssign,
7631053 .DivAssign,
7641054 .RemAssign,
......@@ -772,6 +1062,9 @@ fn transBinaryOperator(
7721062 => unreachable,
7731063 else => unreachable,
7741064 }
1065
1066 const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
1067 return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true);
7751068}
7761069
7771070fn transCompoundStmtInline(
......@@ -790,11 +1083,11 @@ fn transCompoundStmtInline(
7901083}
7911084
7921085fn 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;
1086 const block_scope = try Scope.Block.init(rp.c, scope, null);
1087 block_scope.block_node = try transCreateNodeBlock(rp.c, null);
1088 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
1089 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1090 return &block_scope.block_node.base;
7981091}
7991092
8001093fn transCStyleCastExprClass(
......@@ -818,7 +1111,7 @@ fn transCStyleCastExprClass(
8181111
8191112fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {
8201113 const c = rp.c;
821 const block_scope = scope.findBlockScope();
1114 const block_scope = scope.findBlockScope(c) catch unreachable;
8221115
8231116 var it = ZigClangDeclStmt_decl_begin(stmt);
8241117 const end_it = ZigClangDeclStmt_decl_end(stmt);
......@@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
8321125 else
8331126 try appendToken(c, .Keyword_threadlocal, "threadlocal");
8341127 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
835 const mut_token = if (ZigClangQualType_isConstQualified(qual_type))
836 try appendToken(c, .Keyword_const, "const")
837 else
838 try appendToken(c, .Keyword_var, "var");
8391128 const name = try c.str(ZigClangDecl_getName_bytes_begin(
8401129 @ptrCast(*const ZigClangDecl, var_decl),
8411130 ));
......@@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
8431132 try block_scope.variables.push(.{ .name = name, .alias = a });
8441133 break :blk a;
8451134 } else name;
846 const name_token = try appendIdentifier(c, checked_name);
1135 const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), checked_name);
8471136
848 const colon_token = try appendToken(c, .Colon, ":");
1137 _ = try appendToken(c, .Colon, ":");
8491138 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));
850 const type_node = try transQualType(rp, qual_type, loc);
1139 node.type_node = try transQualType(rp, qual_type, loc);
8511140
852 const eq_token = try appendToken(c, .Equal, "=");
853 const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
1141 node.eq_token = try appendToken(c, .Equal, "=");
1142 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
8541143 try transExpr(rp, scope, expr, .used, .r_value)
8551144 else
8561145 try transCreateNodeUndefinedLiteral(c);
857 const semicolon_token = try appendToken(c, .Semicolon, ";");
858
859 const node = try c.a().create(ast.Node.VarDecl);
860 node.* = ast.Node.VarDecl{
861 .doc_comments = null,
862 .visib_token = null,
863 .thread_local_token = thread_local_token,
864 .name_token = name_token,
865 .eq_token = eq_token,
866 .mut_token = mut_token,
867 .comptime_token = null,
868 .extern_export_token = null,
869 .lib_name = null,
870 .type_node = type_node,
871 .align_node = null, // TODO ?*Node,
872 .section_node = null,
873 .init_node = init_node,
874 .semicolon_token = semicolon_token,
875 };
1146 if (isBoolRes(init_node)) {
1147 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1148 try builtin_node.params.push(init_node);
1149 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1150 init_node = &builtin_node.base;
1151 }
1152 node.init_node = init_node;
1153 node.semicolon_token = try appendToken(c, .Semicolon, ";");
8761154 try block_scope.block_node.statements.push(&node.base);
8771155 },
8781156 else => |kind| return revertAndWarn(
......@@ -896,7 +1174,6 @@ fn transDeclRefExpr(
8961174 const value_decl = ZigClangDeclRefExpr_getDecl(expr);
8971175 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
8981176 const checked_name = if (scope.getAlias(name)) |a| a else name;
899 if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name);
9001177 return transCreateNodeIdentifier(rp.c, checked_name);
9011178}
9021179
......@@ -909,25 +1186,58 @@ fn transImplicitCastExpr(
9091186 const c = rp.c;
9101187 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);
9111188 const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value);
1189 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));
1190 const src_type = getExprQualType(c, sub_expr);
9121191 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {
913 .BitCast => {
914 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));
915 const src_type = getExprQualType(c, sub_expr);
1192 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => {
9161193 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
9171194 },
918 .IntegralCast => {
919 const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr));
920 const src_type = ZigClangExpr_getType(sub_expr);
921 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
922 },
923 .FunctionToPointerDecay, .ArrayToPointerDecay => {
1195 .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => {
9241196 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
9251197 },
926 .LValueToRValue, .NoOp => {
927 return transExpr(rp, scope, sub_expr, .used, .r_value);
928 },
9291198 .NullToPointer => {
930 return transCreateNodeNullLiteral(rp.c);
1199 return try transCreateNodeNullLiteral(rp.c);
1200 },
1201 .PointerToBoolean => {
1202 // @ptrToInt(val) != 0
1203 const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
1204 try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value));
1205 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
1206
1207 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1208 const rhs_node = try transCreateNodeInt(rp.c, 0);
1209 return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false);
1210 },
1211 .IntegralToBoolean => {
1212 // val != 0
1213 const node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1214
1215 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1216 const rhs_node = try transCreateNodeInt(rp.c, 0);
1217 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, result_used, false);
1218 },
1219 .PointerToIntegral => {
1220 // @intCast(dest_type, @ptrToInt(val))
1221 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
1222 try cast_node.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr)));
1223 _ = try appendToken(rp.c, .Comma, ",");
1224
1225 const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt");
1226 try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value));
1227 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
1228 try cast_node.params.push(&ptr_to_int.base);
1229 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1230 return maybeSuppressResult(rp, scope, result_used, &cast_node.base);
1231 },
1232 .IntegralToPointer => {
1233 // @intToPtr(dest_type, val)
1234 const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr");
1235 try int_to_ptr.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr)));
1236 _ = try appendToken(rp.c, .Comma, ",");
1237
1238 try int_to_ptr.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value));
1239 int_to_ptr.rparen_token = try appendToken(rp.c, .RParen, ")");
1240 return maybeSuppressResult(rp, scope, result_used, &int_to_ptr.base);
9311241 },
9321242 else => |kind| return revertAndWarn(
9331243 rp,
......@@ -939,50 +1249,195 @@ fn transImplicitCastExpr(
9391249 }
9401250}
9411251
942fn transIntegerLiteral(
1252fn transBoolExpr(
9431253 rp: RestorePoint,
9441254 scope: *Scope,
945 expr: *const ZigClangIntegerLiteral,
946 result_used: ResultUsed,
1255 expr: *const ZigClangExpr,
1256 used: ResultUsed,
1257 lrvalue: LRValue,
1258 grouped: bool,
9471259) TransError!*ast.Node {
948 var eval_result: ZigClangExprEvalResult = undefined;
949 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
950 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
951 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1260 const lparen = if (grouped)
1261 try appendToken(rp.c, .LParen, "(")
1262 else
1263 undefined;
1264 var res = try transExpr(rp, scope, expr, used, lrvalue);
1265
1266 if (isBoolRes(res)) {
1267 if (!grouped and res.id == .GroupedExpression) {
1268 const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);
1269 res = group.expr;
1270 // get zig fmt to work properly
1271 tokenSlice(rp.c, group.lparen)[0] = ')';
1272 }
1273 return res;
1274 }
1275
1276 const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
1277 const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used);
1278
1279 if (grouped) {
1280 const rparen = try appendToken(rp.c, .RParen, ")");
1281 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
1282 grouped_expr.* = .{
1283 .lparen = lparen,
1284 .expr = node,
1285 .rparen = rparen,
1286 };
1287 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
1288 } else {
1289 return maybeSuppressResult(rp, scope, used, node);
9521290 }
953 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
954 return maybeSuppressResult(rp, scope, result_used, node);
9551291}
9561292
957fn transReturnStmt(
958 rp: RestorePoint,
959 scope: *Scope,
960 expr: *const ZigClangReturnStmt,
961) TransError!*ast.Node {
962 const node = try transCreateNodeReturnExpr(rp.c);
963 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
964 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
1293fn isBoolRes(res: *ast.Node) bool {
1294 switch (res.id) {
1295 .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
1296 .BoolOr,
1297 .BoolAnd,
1298 .EqualEqual,
1299 .BangEqual,
1300 .LessThan,
1301 .GreaterThan,
1302 .LessOrEqual,
1303 .GreaterOrEqual,
1304 => return true,
1305
1306 else => {},
1307 },
1308 .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
1309 .BoolNot => return true,
1310
1311 else => {},
1312 },
1313 .BoolLiteral => return true,
1314 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1315 else => {},
9651316 }
966 _ = try appendToken(rp.c, .Semicolon, ";");
967 return &node.base;
1317 return false;
9681318}
9691319
970fn transStringLiteral(
1320fn finishBoolExpr(
9711321 rp: RestorePoint,
9721322 scope: *Scope,
973 stmt: *const ZigClangStringLiteral,
974 result_used: ResultUsed,
1323 loc: ZigClangSourceLocation,
1324 ty: *const ZigClangType,
1325 node: *ast.Node,
1326 used: ResultUsed,
9751327) TransError!*ast.Node {
976 const kind = ZigClangStringLiteral_getKind(stmt);
977 switch (kind) {
978 .Ascii, .UTF8 => {
979 var len: usize = undefined;
980 const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len);
981 const str = bytes_ptr[0..len];
982
983 var char_buf: [4]u8 = undefined;
984 len = 0;
985 for (str) |c| len += escapeChar(c, &char_buf).len;
1328 switch (ZigClangType_getTypeClass(ty)) {
1329 .Builtin => {
1330 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1331
1332 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1333 .Bool => return node,
1334 .Char_U,
1335 .UChar,
1336 .Char_S,
1337 .SChar,
1338 .UShort,
1339 .UInt,
1340 .ULong,
1341 .ULongLong,
1342 .Short,
1343 .Int,
1344 .Long,
1345 .LongLong,
1346 .UInt128,
1347 .Int128,
1348 .Float,
1349 .Double,
1350 .Float128,
1351 .LongDouble,
1352 .WChar_U,
1353 .Char8,
1354 .Char16,
1355 .Char32,
1356 .WChar_S,
1357 .Float16,
1358 => {
1359 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1360 const rhs_node = try transCreateNodeInt(rp.c, 0);
1361 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1362 },
1363 .NullPtr => {
1364 const op_token = try appendToken(rp.c, .EqualEqual, "==");
1365 const rhs_node = try transCreateNodeNullLiteral(rp.c);
1366 return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
1367 },
1368 else => {},
1369 }
1370 },
1371 .Pointer => {
1372 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1373 const rhs_node = try transCreateNodeNullLiteral(rp.c);
1374 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1375 },
1376 .Typedef => {
1377 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
1378 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
1379 const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
1380 return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used);
1381 },
1382 .Enum => {
1383 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1384 const rhs_node = try transCreateNodeInt(rp.c, 0);
1385 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1386 },
1387 .Elaborated => {
1388 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
1389 const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty);
1390 return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used);
1391 },
1392 else => {},
1393 }
1394 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
1395}
1396
1397fn transIntegerLiteral(
1398 rp: RestorePoint,
1399 scope: *Scope,
1400 expr: *const ZigClangIntegerLiteral,
1401 result_used: ResultUsed,
1402) TransError!*ast.Node {
1403 var eval_result: ZigClangExprEvalResult = undefined;
1404 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
1405 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
1406 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1407 }
1408 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1409 return maybeSuppressResult(rp, scope, result_used, node);
1410}
1411
1412fn transReturnStmt(
1413 rp: RestorePoint,
1414 scope: *Scope,
1415 expr: *const ZigClangReturnStmt,
1416) TransError!*ast.Node {
1417 const node = try transCreateNodeReturnExpr(rp.c);
1418 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
1419 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
1420 }
1421 _ = try appendToken(rp.c, .Semicolon, ";");
1422 return &node.base;
1423}
1424
1425fn transStringLiteral(
1426 rp: RestorePoint,
1427 scope: *Scope,
1428 stmt: *const ZigClangStringLiteral,
1429 result_used: ResultUsed,
1430) TransError!*ast.Node {
1431 const kind = ZigClangStringLiteral_getKind(stmt);
1432 switch (kind) {
1433 .Ascii, .UTF8 => {
1434 var len: usize = undefined;
1435 const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len);
1436 const str = bytes_ptr[0..len];
1437
1438 var char_buf: [4]u8 = undefined;
1439 len = 0;
1440 for (str) |c| len += escapeChar(c, &char_buf).len;
9861441
9871442 const buf = try rp.c.a().alloc(u8, len + "\"\"".len);
9881443 buf[0] = '"';
......@@ -991,7 +1446,7 @@ fn transStringLiteral(
9911446
9921447 const token = try appendToken(rp.c, .StringLiteral, buf);
9931448 const node = try rp.c.a().create(ast.Node.StringLiteral);
994 node.* = ast.Node.StringLiteral{
1449 node.* = .{
9951450 .token = token,
9961451 };
9971452 return maybeSuppressResult(rp, scope, result_used, &node.base);
......@@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
10191474 var i: usize = 0;
10201475 for (s) |c| {
10211476 const escaped = escapeChar(c, &char_buf);
1022 std.mem.copy(u8, buf[i..], escaped);
1477 mem.copy(u8, buf[i..], escaped);
10231478 i += escaped.len;
10241479 }
10251480}
10261481
10271482// Returns either a string literal or a slice of `buf`.
10281483fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
1029 // TODO: https://github.com/ziglang/zig/issues/2749
1030 const escaped = switch (c) {
1031 // Printable ASCII except for ' " \
1032 ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..],
1033 '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..],
1034 '\n' => return "\\n"[0..],
1035 '\r' => return "\\r"[0..],
1036 '\t' => return "\\t"[0..],
1037 else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable,
1484 return switch (c) {
1485 '\"' => "\\\""[0..],
1486 '\'' => "\\'"[0..],
1487 '\\' => "\\\\"[0..],
1488 '\n' => "\\n"[0..],
1489 '\r' => "\\r"[0..],
1490 '\t' => "\\t"[0..],
1491 else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable,
10381492 };
1039 std.mem.copy(u8, char_buf, escaped);
1040 return char_buf[0..escaped.len];
10411493}
10421494
10431495fn transCCast(
......@@ -1071,6 +1523,55 @@ fn transCCast(
10711523 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
10721524 return &builtin_node.base;
10731525 }
1526 if (cIsFloating(src_type) and cIsFloating(dst_type)) {
1527 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast");
1528 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1529 _ = try appendToken(rp.c, .Comma, ",");
1530 try builtin_node.params.push(expr);
1531 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1532 return &builtin_node.base;
1533 }
1534 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
1535 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt");
1536 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1537 _ = try appendToken(rp.c, .Comma, ",");
1538 try builtin_node.params.push(expr);
1539 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1540 return &builtin_node.base;
1541 }
1542 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
1543 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat");
1544 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1545 _ = try appendToken(rp.c, .Comma, ",");
1546 try builtin_node.params.push(expr);
1547 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1548 return &builtin_node.base;
1549 }
1550 if (ZigClangQualType_getTypeClass(src_type) == .Elaborated) {
1551 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(src_type));
1552 return transCCast(rp, scope, loc, dst_type, ZigClangElaboratedType_getNamedType(elaborated_ty), expr);
1553 }
1554 if (ZigClangQualType_getTypeClass(dst_type) == .Elaborated) {
1555 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(dst_type));
1556 return transCCast(rp, scope, loc, ZigClangElaboratedType_getNamedType(elaborated_ty), src_type, expr);
1557 }
1558 if (ZigClangQualType_getTypeClass(dst_type) == .Enum)
1559 {
1560 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum");
1561 try builtin_node.params.push(try transQualType(rp, dst_type, loc));
1562 _ = try appendToken(rp.c, .Comma, ",");
1563 try builtin_node.params.push(expr);
1564 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1565 return &builtin_node.base;
1566 }
1567 if (ZigClangQualType_getTypeClass(src_type) == .Enum and
1568 ZigClangQualType_getTypeClass(dst_type) != .Enum)
1569 {
1570 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt");
1571 try builtin_node.params.push(expr);
1572 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1573 return &builtin_node.base;
1574 }
10741575 // TODO: maybe widen to increase size
10751576 // TODO: maybe bitcast to change sign
10761577 // TODO: maybe truncate to reduce size
......@@ -1124,7 +1625,7 @@ fn transInitListExpr(
11241625 var cat_tok: ast.TokenIndex = undefined;
11251626 if (init_count != 0) {
11261627 const dot_tok = try appendToken(rp.c, .Period, ".");
1127 init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
1628 init_node = try transCreateNodeContainerInitializer(rp.c, dot_tok);
11281629 var i: c_uint = 0;
11291630 while (i < init_count) : (i += 1) {
11301631 const elem_expr = ZigClangInitListExpr_getInit(expr, i);
......@@ -1139,7 +1640,7 @@ fn transInitListExpr(
11391640 }
11401641
11411642 const dot_tok = try appendToken(rp.c, .Period, ".");
1142 var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok);
1643 var filler_init_node = try transCreateNodeContainerInitializer(rp.c, dot_tok);
11431644 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);
11441645 try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value));
11451646 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
......@@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr(
11851686 .Builtin => blk: {
11861687 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
11871688 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1188 .Bool => return transCreateNodeBoolLiteral(rp.c, false),
1689 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),
11891690 .Char_U,
11901691 .UChar,
11911692 .Char_S,
......@@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr(
12151716 };
12161717}
12171718
1218fn transCPtrCast(
1719fn transIfStmt(
12191720 rp: RestorePoint,
1220 loc: ZigClangSourceLocation,
1221 dst_type: ZigClangQualType,
1222 src_type: ZigClangQualType,
1223 expr: *ast.Node,
1224) !*ast.Node {
1225 const ty = ZigClangQualType_getTypePtr(dst_type);
1226 const child_type = ZigClangType_getPointeeType(ty);
1721 scope: *Scope,
1722 stmt: *const ZigClangIfStmt,
1723) TransError!*ast.Node {
1724 // if (c) t
1725 // if (c) t else e
1726 const if_node = try transCreateNodeIf(rp.c);
12271727
1228 // Implicit downcasting from higher to lower alignment values is forbidden,
1229 // use @alignCast to side-step this problem
1230 const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
1231 const dst_type_node = try transType(rp, ty, loc);
1232 try ptrcast_node.params.push(dst_type_node);
1233 _ = try appendToken(rp.c, .Comma, ",");
1728 var cond_scope = Scope{
1729 .parent = scope,
1730 .id = .Condition,
1731 };
1732 if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);
1733 _ = try appendToken(rp.c, .RParen, ")");
12341734
1235 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
1236 // void has 1-byte alignment, so @alignCast is not needed
1237 try ptrcast_node.params.push(expr);
1238 } else {
1239 const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");
1240 const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");
1241 const child_type_node = try transQualType(rp, child_type, loc);
1242 try alignof_node.params.push(child_type_node);
1243 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1244 try aligncast_node.params.push(&alignof_node.base);
1245 _ = try appendToken(rp.c, .Comma, ",");
1246 try aligncast_node.params.push(expr);
1247 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1248 try ptrcast_node.params.push(&aligncast_node.base);
1249 }
1250 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1735 if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);
12511736
1252 return &ptrcast_node.base;
1737 if (ZigClangIfStmt_getElse(stmt)) |expr| {
1738 if_node.@"else" = try transCreateNodeElse(rp.c);
1739 if_node.@"else".?.body = try transStmt(rp, scope, expr, .unused, .r_value);
1740 }
1741 _ = try appendToken(rp.c, .Semicolon, ";");
1742 return &if_node.base;
12531743}
12541744
1255fn maybeSuppressResult(
1745fn transWhileLoop(
12561746 rp: RestorePoint,
12571747 scope: *Scope,
1258 used: ResultUsed,
1259 result: *ast.Node,
1748 stmt: *const ZigClangWhileStmt,
12601749) TransError!*ast.Node {
1261 if (used == .used) return result;
1262 // NOTE: This is backwards, but the semicolon must immediately follow the node.
1263 _ = try appendToken(rp.c, .Semicolon, ";");
1264 const lhs = try transCreateNodeIdentifier(rp.c, "_");
1265 const op_token = try appendToken(rp.c, .Equal, "=");
1266 const op_node = try rp.c.a().create(ast.Node.InfixOp);
1267 op_node.* = ast.Node.InfixOp{
1268 .op_token = op_token,
1269 .lhs = lhs,
1270 .op = .Assign,
1271 .rhs = result,
1750 const while_node = try transCreateNodeWhile(rp.c);
1751
1752 var cond_scope = Scope{
1753 .parent = scope,
1754 .id = .Condition,
12721755 };
1273 return &op_node.base;
1274}
1756 while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);
1757 _ = try appendToken(rp.c, .RParen, ")");
12751758
1276fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
1277 try c.tree.root_node.decls.push(decl_node);
1278 _ = try c.global_scope.sym_table.put(name, decl_node);
1759 var loop_scope = Scope{
1760 .parent = scope,
1761 .id = .Loop,
1762 };
1763 while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
1764 return &while_node.base;
12791765}
12801766
1281fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
1282 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
1283}
1767fn transDoWhileLoop(
1768 rp: RestorePoint,
1769 scope: *Scope,
1770 stmt: *const ZigClangDoStmt,
1771) TransError!*ast.Node {
1772 const while_node = try transCreateNodeWhile(rp.c);
1773
1774 while_node.condition = try transCreateNodeBoolLiteral(rp.c, true);
1775 _ = try appendToken(rp.c, .RParen, ")");
1776 var new = false;
1777 var loop_scope = Scope{
1778 .parent = scope,
1779 .id = .Loop,
1780 };
12841781
1285fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node {
1286 const rp = makeRestorePoint(c);
1782 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
1783 // there's already a block in C, so we'll append our condition to it.
1784 // c: do {
1785 // c: a;
1786 // c: b;
1787 // c: } while(c);
1788 // zig: while (true) {
1789 // zig: a;
1790 // zig: b;
1791 // zig: if (!cond) break;
1792 // zig: }
1793 break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
1794 } else blk: {
1795 // the C statement is without a block, so we need to create a block to contain it.
1796 // c: do
1797 // c: a;
1798 // c: while(c);
1799 // zig: while (true) {
1800 // zig: a;
1801 // zig: if (!cond) break;
1802 // zig: }
1803 new = true;
1804 const block = try transCreateNodeBlock(rp.c, null);
1805 try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));
1806 break :blk block;
1807 };
12871808
1288 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
1809 // if (!cond) break;
1810 const if_node = try transCreateNodeIf(rp.c);
1811 var cond_scope = Scope{
1812 .parent = scope,
1813 .id = .Condition,
1814 };
1815 const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
1816 prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
1817 _ = try appendToken(rp.c, .RParen, ")");
1818 if_node.condition = &prefix_op.base;
1819 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
1820 _ = try appendToken(rp.c, .Semicolon, ";");
12891821
1290 var container_kind_name: []const u8 = undefined;
1291 var container_kind: std.zig.Token.Id = undefined;
1822 try body_node.statements.push(&if_node.base);
1823 if (new)
1824 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1825 while_node.body = &body_node.base;
1826 return &while_node.base;
1827}
12921828
1293 if (ZigClangRecordDecl_isUnion(record_decl)) {
1294 container_kind_name = "union";
1295 container_kind = .Keyword_union;
1296 } else if (ZigClangRecordDecl_isStruct(record_decl)) {
1297 container_kind_name = "struct";
1298 container_kind = .Keyword_struct;
1299 } else {
1300 return revertAndWarn(
1301 rp,
1302 error.UnsupportedType,
1303 record_loc,
1304 "unsupported record type",
1305 .{},
1306 );
1829fn transForLoop(
1830 rp: RestorePoint,
1831 scope: *Scope,
1832 stmt: *const ZigClangForStmt,
1833) TransError!*ast.Node {
1834 var loop_scope = Scope{
1835 .parent = scope,
1836 .id = .Loop,
1837 };
1838 var block = false;
1839 var block_scope: ?*Scope.Block = null;
1840 if (ZigClangForStmt_getInit(stmt)) |init| {
1841 block_scope = try Scope.Block.init(rp.c, scope, null);
1842 block_scope.?.block_node = try transCreateNodeBlock(rp.c, null);
1843 loop_scope.parent = &block_scope.?.base;
1844 _ = try transStmt(rp, &loop_scope, init, .unused, .r_value);
13071845 }
1308
1309 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
1310 return transCreateNodeOpaqueType(c);
1846 var cond_scope = Scope{
1847 .parent = scope,
1848 .id = .Condition,
13111849 };
13121850
1313 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
1314 const container_tok = try appendToken(c, container_kind, container_kind_name);
1315 const lbrace_token = try appendToken(c, .LBrace, "{");
1851 const while_node = try transCreateNodeWhile(rp.c);
1852 while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|
1853 try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false)
1854 else
1855 try transCreateNodeBoolLiteral(rp.c, true);
1856 _ = try appendToken(rp.c, .RParen, ")");
1857
1858 if (ZigClangForStmt_getInc(stmt)) |incr| {
1859 _ = try appendToken(rp.c, .Colon, ":");
1860 _ = try appendToken(rp.c, .LParen, "(");
1861 while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value);
1862 _ = try appendToken(rp.c, .RParen, ")");
1863 }
1864
1865 while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
1866 if (block_scope != null) {
1867 try block_scope.?.block_node.statements.push(&while_node.base);
1868 block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1869 return &block_scope.?.block_node.base;
1870 } else
1871 return &while_node.base;
1872}
13161873
1317 const container_node = try c.a().create(ast.Node.ContainerDecl);
1318 container_node.* = .{
1319 .layout_token = extern_tok,
1320 .kind_token = container_tok,
1321 .init_arg_expr = .None,
1322 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
1323 .lbrace_token = lbrace_token,
1324 .rbrace_token = undefined,
1874fn transSwitch(
1875 rp: RestorePoint,
1876 scope: *Scope,
1877 stmt: *const ZigClangSwitchStmt,
1878) TransError!*ast.Node {
1879 const switch_node = try transCreateNodeSwitch(rp.c);
1880 var switch_scope = Scope.Switch{
1881 .base = .{
1882 .id = .Switch,
1883 .parent = scope,
1884 },
1885 .cases = &switch_node.cases,
1886 .pending_block = undefined,
13251887 };
13261888
1327 var it = ZigClangRecordDecl_field_begin(record_def);
1328 const end_it = ZigClangRecordDecl_field_end(record_def);
1329 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
1330 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
1331 const field_loc = ZigClangFieldDecl_getLocation(field_decl);
1889 var cond_scope = Scope{
1890 .parent = scope,
1891 .id = .Condition,
1892 };
1893 switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value);
1894 _ = try appendToken(rp.c, .RParen, ")");
1895 _ = try appendToken(rp.c, .LBrace, "{");
1896 switch_node.rbrace = try appendToken(rp.c, .RBrace, "}");
13321897
1333 if (ZigClangFieldDecl_isBitField(field_decl)) {
1334 rp.activate();
1335 const node = try transCreateNodeOpaqueType(c);
1336 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
1337 return node;
1338 }
1898 const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
1899 // tmp block that all statements will go before being picked up by a case or default
1900 const block = try transCreateNodeBlock(rp.c, null);
1901 block_scope.block_node = block;
13391902
1340 const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
1341 _ = try appendToken(c, .Colon, ":");
1342 const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc);
1903 const switch_block = try transCreateNodeBlock(rp.c, null);
1904 try switch_block.statements.push(&switch_node.base);
1905 switch_scope.pending_block = switch_block;
13431906
1344 const field_node = try c.a().create(ast.Node.ContainerField);
1345 field_node.* = .{
1346 .doc_comments = null,
1347 .comptime_token = null,
1348 .name_token = field_name,
1349 .type_expr = field_type,
1350 .value_expr = null,
1351 .align_expr = null,
1352 };
1907 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
1908 _ = try appendToken(rp.c, .Semicolon, ";");
13531909
1354 try container_node.fields_and_decls.push(&field_node.base);
1355 _ = try appendToken(c, .Comma, ",");
1910 // take all pending statements
1911 var it = last.cast(ast.Node.Block).?.statements.iterator(0);
1912 while (it.next()) |n| {
1913 try switch_scope.pending_block.statements.push(n.*);
13561914 }
13571915
1358 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
1359 return &container_node.base;
1916 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");
1917 _ = try appendToken(rp.c, .Colon, ":");
1918 if (!switch_scope.has_default) {
1919 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
1920 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;
1921 _ = try appendToken(rp.c, .Comma, ",");
1922 try switch_node.cases.push(&else_prong.base);
1923 }
1924 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
1925 return &switch_scope.pending_block.base;
13601926}
13611927
1362fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
1363 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
1364 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
1365 const rp = makeRestorePoint(c);
1366 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
1928fn transCase(
1929 rp: RestorePoint,
1930 scope: *Scope,
1931 stmt: *const ZigClangCaseStmt,
1932) TransError!*ast.Node {
1933 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
1934 const switch_scope = scope.getSwitch();
1935 const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});
1936 _ = try appendToken(rp.c, .Semicolon, ";");
13671937
1368 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1369 const const_tok = try appendToken(c, .Keyword_const, "const");
1938 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
1939 const lhs_node = try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
1940 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
1941 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
13701942
1371 var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
1372 var is_unnamed = false;
1373 if (bare_name.len == 0) {
1374 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
1375 is_unnamed = true;
1943 const node = try rp.c.a().create(ast.Node.InfixOp);
1944 node.* = .{
1945 .op_token = ellips,
1946 .lhs = lhs_node,
1947 .op = .Range,
1948 .rhs = rhs_node,
1949 };
1950 break :blk &node.base;
1951 } else
1952 try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
1953
1954 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
1955 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
1956 _ = try appendToken(rp.c, .Comma, ",");
1957 try switch_scope.cases.push(&switch_prong.base);
1958
1959 const block = try transCreateNodeBlock(rp.c, null);
1960 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
1961 _ = try appendToken(rp.c, .Colon, ":");
1962 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
1963 try block.statements.push(&switch_scope.pending_block.base);
1964
1965 // take all pending statements
1966 var it = block_scope.block_node.statements.iterator(0);
1967 while (it.next()) |n| {
1968 try switch_scope.pending_block.statements.push(n.*);
13761969 }
1970 block_scope.block_node.statements.shrink(0);
13771971
1378 const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
1379 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
1380 const name_tok = try appendIdentifier(c, name);
1381 const eq_tok = try appendToken(c, .Equal, "=");
1972 switch_scope.pending_block = block;
13821973
1383 const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
1384 var pure_enum = true;
1385 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
1386 var end_it = ZigClangEnumDecl_enumerator_end(enum_def);
1387 while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
1388 const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
1389 if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| {
1390 pure_enum = false;
1391 break;
1392 }
1393 }
1974 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
1975}
13941976
1395 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
1396 const container_tok = try appendToken(c, .Keyword_enum, "enum");
1977fn transDefault(
1978 rp: RestorePoint,
1979 scope: *Scope,
1980 stmt: *const ZigClangDefaultStmt,
1981) TransError!*ast.Node {
1982 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
1983 const switch_scope = scope.getSwitch();
1984 const label = "__default";
1985 switch_scope.has_default = true;
1986 _ = try appendToken(rp.c, .Semicolon, ";");
13971987
1398 const container_node = try c.a().create(ast.Node.ContainerDecl);
1399 container_node.* = .{
1400 .layout_token = extern_tok,
1401 .kind_token = container_tok,
1402 .init_arg_expr = .None,
1403 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
1404 .lbrace_token = undefined,
1405 .rbrace_token = undefined,
1406 };
1988 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
1989 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
1990 _ = try appendToken(rp.c, .Comma, ",");
1991 try switch_scope.cases.push(&else_prong.base);
1992
1993 const block = try transCreateNodeBlock(rp.c, null);
1994 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
1995 _ = try appendToken(rp.c, .Colon, ":");
1996 switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}");
1997 try block.statements.push(&switch_scope.pending_block.base);
1998
1999 // take all pending statements
2000 var it = block_scope.block_node.statements.iterator(0);
2001 while (it.next()) |n| {
2002 try switch_scope.pending_block.statements.push(n.*);
2003 }
2004 block_scope.block_node.statements.shrink(0);
14072005
1408 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
2006 switch_scope.pending_block = block;
2007 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
2008}
14092009
1410 // TODO only emit this tag type if the enum tag type is not the default.
1411 // I don't know what the default is, need to figure out how clang is deciding.
1412 // it appears to at least be different across gcc/msvc
1413 if (!isCBuiltinType(int_type, .UInt) and
1414 !isCBuiltinType(int_type, .Int))
1415 {
1416 _ = try appendToken(c, .LParen, "(");
1417 container_node.init_arg_expr = .{
1418 .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
1419 error.UnsupportedType => {
1420 if (is_unnamed) {
1421 try emitWarning(c, enum_loc, "unable to translate enum tag type", .{});
1422 } else {
1423 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
1424 }
1425 return null;
1426 },
1427 else => |e| return e,
1428 },
2010fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, used: ResultUsed) TransError!*ast.Node {
2011 var result: ZigClangExprEvalResult = undefined;
2012 if (!ZigClangExpr_EvaluateAsConstantExpr(expr, &result, .EvaluateForCodeGen, rp.c.clang_context))
2013 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangExpr_getBeginLoc(expr), "invalid constant expression", .{});
2014 return maybeSuppressResult(rp, scope, used, try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)));
2015}
2016
2017fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPredefinedExpr, used: ResultUsed) TransError!*ast.Node {
2018 return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used);
2019}
2020
2021fn transCharLiteral(
2022 rp: RestorePoint,
2023 scope: *Scope,
2024 stmt: *const ZigClangCharacterLiteral,
2025 result_used: ResultUsed,
2026) TransError!*ast.Node {
2027 const kind = ZigClangCharacterLiteral_getKind(stmt);
2028 switch (kind) {
2029 .Ascii, .UTF8 => {
2030 const val = ZigClangCharacterLiteral_getValue(stmt);
2031 if (kind == .Ascii) {
2032 // C has a somewhat obscure feature called multi-character character
2033 // constant
2034 if (val > 255)
2035 return transCreateNodeInt(rp.c, val);
2036 }
2037 var char_buf: [4]u8 = undefined;
2038 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
2039 const node = try rp.c.a().create(ast.Node.CharLiteral);
2040 node.* = .{
2041 .token = token,
14292042 };
1430 _ = try appendToken(c, .RParen, ")");
2043 return maybeSuppressResult(rp, scope, result_used, &node.base);
2044 },
2045 .UTF16, .UTF32, .Wide => return revertAndWarn(
2046 rp,
2047 error.UnsupportedTranslation,
2048 ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)),
2049 "TODO: support character literal kind {}",
2050 .{kind},
2051 ),
2052 else => unreachable,
2053 }
2054}
2055
2056fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node {
2057 const comp = ZigClangStmtExpr_getSubStmt(stmt);
2058 if (used == .unused) {
2059 return transCompoundStmt(rp, scope, comp);
2060 }
2061 const lparen = try appendToken(rp.c, .LParen, "(");
2062 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2063 const block = try transCreateNodeBlock(rp.c, "blk");
2064 block_scope.block_node = block;
2065
2066 var it = ZigClangCompoundStmt_body_begin(comp);
2067 const end_it = ZigClangCompoundStmt_body_end(comp);
2068 while (it != end_it - 1) : (it += 1) {
2069 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
2070 if (result != &block.base)
2071 try block.statements.push(result);
2072 }
2073 const break_node = try transCreateNodeBreak(rp.c, "blk");
2074 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
2075 _ = try appendToken(rp.c, .Semicolon, ";");
2076 try block.statements.push(&break_node.base);
2077 block.rbrace = try appendToken(rp.c, .RBrace, "}");
2078 const rparen = try appendToken(rp.c, .RParen, ")");
2079 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
2080 grouped_expr.* = .{
2081 .lparen = lparen,
2082 .expr = &block.base,
2083 .rparen = rparen,
2084 };
2085 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
2086}
2087
2088fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberExpr, result_used: ResultUsed) TransError!*ast.Node {
2089 var container_node = try transExpr(rp, scope, ZigClangMemberExpr_getBase(stmt), .used, .r_value);
2090
2091 if (ZigClangMemberExpr_isArrow(stmt)) {
2092 container_node = try transCreateNodePtrDeref(rp.c, container_node);
2093 }
2094
2095 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt))));
2096 const node = try transCreateNodeFieldAccess(rp.c, container_node, name);
2097 return maybeSuppressResult(rp, scope, result_used, node);
2098}
2099
2100fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArraySubscriptExpr, result_used: ResultUsed) TransError!*ast.Node {
2101 const container_node = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getBase(stmt), .used, .r_value);
2102 const node = try transCreateNodeArrayAccess(rp.c, container_node);
2103 node.op.ArrayAccess = try transExpr(rp, scope, ZigClangArraySubscriptExpr_getIdx(stmt), .used, .r_value);
2104 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2105 return maybeSuppressResult(rp, scope, result_used, &node.base);
2106}
2107
2108fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, result_used: ResultUsed) TransError!*ast.Node {
2109 const callee = ZigClangCallExpr_getCallee(stmt);
2110 var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value);
2111
2112 var is_ptr = false;
2113 const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(callee), &is_ptr);
2114
2115 const fn_expr = if (is_ptr and fn_ty != null) blk: {
2116 if (ZigClangExpr_getStmtClass(callee) == .ImplicitCastExprClass) {
2117 const implicit_cast = @ptrCast(*const ZigClangImplicitCastExpr, callee);
2118
2119 if (ZigClangImplicitCastExpr_getCastKind(implicit_cast) == .FunctionToPointerDecay) {
2120 const subexpr = ZigClangImplicitCastExpr_getSubExpr(implicit_cast);
2121 if (ZigClangExpr_getStmtClass(subexpr) == .DeclRefExprClass) {
2122 const decl_ref = @ptrCast(*const ZigClangDeclRefExpr, subexpr);
2123 const named_decl = ZigClangDeclRefExpr_getFoundDecl(decl_ref);
2124 if (ZigClangDecl_getKind(@ptrCast(*const ZigClangDecl, named_decl)) == .Function) {
2125 break :blk raw_fn_expr;
2126 }
2127 }
2128 }
14312129 }
2130 break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr);
2131 } else
2132 raw_fn_expr;
2133 const node = try transCreateNodeFnCall(rp.c, fn_expr);
14322134
1433 container_node.lbrace_token = try appendToken(c, .LBrace, "{");
2135 const num_args = ZigClangCallExpr_getNumArgs(stmt);
2136 const args = ZigClangCallExpr_getArgs(stmt);
2137 var i: usize = 0;
2138 while (i < num_args) : (i += 1) {
2139 if (i != 0) {
2140 _ = try appendToken(rp.c, .Comma, ",");
2141 }
2142 const arg = try transExpr(rp, scope, args[i], .used, .r_value);
2143 try node.op.Call.params.push(arg);
2144 }
2145 node.rtoken = try appendToken(rp.c, .RParen, ")");
14342146
1435 it = ZigClangEnumDecl_enumerator_begin(enum_def);
1436 end_it = ZigClangEnumDecl_enumerator_end(enum_def);
1437 while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {
1438 const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);
2147 if (fn_ty) |ty| {
2148 const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty));
2149 const ret_ty = ZigClangQualType_getTypePtr(canon);
2150 if (ZigClangType_isVoidType(ret_ty)) {
2151 _ = try appendToken(rp.c, .Semicolon, ";");
2152 return &node.base;
2153 }
2154 }
14392155
1440 const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const)));
2156 return maybeSuppressResult(rp, scope, result_used, &node.base);
2157}
14412158
1442 const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name))
1443 enum_val_name[bare_name.len..]
1444 else
1445 enum_val_name;
2159fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType {
2160 const canon = ZigClangQualType_getCanonicalType(qt);
2161 var ty = ZigClangQualType_getTypePtr(canon);
2162 is_ptr.* = false;
14462163
1447 const field_name_tok = try appendIdentifier(c, field_name);
2164 if (ZigClangType_getTypeClass(ty) == .Pointer) {
2165 is_ptr.* = true;
2166 const child_qt = ZigClangType_getPointeeType(ty);
2167 ty = ZigClangQualType_getTypePtr(child_qt);
2168 }
2169 if (ZigClangType_getTypeClass(ty) == .FunctionProto) {
2170 return @ptrCast(*const ZigClangFunctionProtoType, ty);
2171 }
2172 return null;
2173}
14482174
1449 const int_node = if (!pure_enum) blk: {
1450 _ = try appendToken(c, .Colon, "=");
1451 break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
2175fn transUnaryExprOrTypeTraitExpr(
2176 rp: RestorePoint,
2177 scope: *Scope,
2178 stmt: *const ZigClangUnaryExprOrTypeTraitExpr,
2179 result_used: ResultUsed,
2180) TransError!*ast.Node {
2181 const type_node = try transQualType(
2182 rp,
2183 ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(stmt),
2184 ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt),
2185 );
2186
2187 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf");
2188 try builtin_node.params.push(type_node);
2189 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2190 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
2191}
2192
2193fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool {
2194 if (cIsSignedInteger(qt) or cIsFloating(qt)) {
2195 // float and signed integer overflow is undefined behavior.
2196 return false;
2197 } else {
2198 // unsigned integer overflow wraps around.
2199 return true;
2200 }
2201}
2202
2203fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {
2204 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2205 switch (ZigClangUnaryOperator_getOpcode(stmt)) {
2206 .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2207 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2208 else
2209 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2210 .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2211 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2212 else
2213 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
2214 .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2215 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2216 else
2217 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2218 .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2219 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2220 else
2221 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
2222 .AddrOf => {
2223 const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2224 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
2225 return &op_node.base;
2226 },
2227 .Deref => {
2228 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);
2229 var is_ptr = false;
2230 const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(op_expr), &is_ptr);
2231 if (fn_ty != null and is_ptr)
2232 return value_node;
2233 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);
2234 return transCreateNodePtrDeref(rp.c, unwrapped);
2235 },
2236 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
2237 .Minus => {
2238 if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) {
2239 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
2240 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2241 return &op_node.base;
2242 } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
2243 // we gotta emit 0 -% x
2244 const zero = try transCreateNodeInt(rp.c, 0);
2245 const token = try appendToken(rp.c, .MinusPercent, "-%");
2246 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2247 return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
14522248 } else
1453 null;
2249 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
2250 },
2251 .Not => {
2252 const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
2253 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2254 return &op_node.base;
2255 },
2256 .LNot => {
2257 const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
2258 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
2259 return &op_node.base;
2260 },
2261 .Extension => {
2262 return transExpr(rp, scope, ZigClangUnaryOperator_getSubExpr(stmt), used, .l_value);
2263 },
2264 else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "unsupported C translation {}", .{ZigClangUnaryOperator_getOpcode(stmt)}),
2265 }
2266}
14542267
1455 const field_node = try c.a().create(ast.Node.ContainerField);
1456 field_node.* = .{
1457 .doc_comments = null,
1458 .comptime_token = null,
1459 .name_token = field_name_tok,
1460 .type_expr = null,
1461 .value_expr = int_node,
1462 .align_expr = null,
1463 };
2268fn transCreatePreCrement(
2269 rp: RestorePoint,
2270 scope: *Scope,
2271 stmt: *const ZigClangUnaryOperator,
2272 op: ast.Node.InfixOp.Op,
2273 op_tok_id: std.zig.Token.Id,
2274 bytes: []const u8,
2275 used: ResultUsed,
2276) TransError!*ast.Node {
2277 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2278
2279 if (used == .unused) {
2280 // common case
2281 // c: ++expr
2282 // zig: expr += 1
2283 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2284 const token = try appendToken(rp.c, op_tok_id, bytes);
2285 const one = try transCreateNodeInt(rp.c, 1);
2286 _ = try appendToken(rp.c, .Semicolon, ";");
2287 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2288 }
2289 // worst case
2290 // c: ++expr
2291 // zig: (blk: {
2292 // zig: const _ref = &expr;
2293 // zig: _ref.* += 1;
2294 // zig: break :blk _ref.*
2295 // zig: })
2296 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2297 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
2298 const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()});
2299
2300 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
2301 node.eq_token = try appendToken(rp.c, .Equal, "=");
2302 const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2303 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2304 node.init_node = &rhs_node.base;
2305 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2306 try block_scope.block_node.statements.push(&node.base);
2307
2308 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
2309 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
2310 _ = try appendToken(rp.c, .Semicolon, ";");
2311 const token = try appendToken(rp.c, op_tok_id, bytes);
2312 const one = try transCreateNodeInt(rp.c, 1);
2313 _ = try appendToken(rp.c, .Semicolon, ";");
2314 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
2315 try block_scope.block_node.statements.push(assign);
2316
2317 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
2318 break_node.rhs = ref_node;
2319 try block_scope.block_node.statements.push(&break_node.base);
2320 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2321 // semicolon must immediately follow rbrace because it is the last token in a block
2322 _ = try appendToken(rp.c, .Semicolon, ";");
2323 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
2324 grouped_expr.* = .{
2325 .lparen = try appendToken(rp.c, .LParen, "("),
2326 .expr = &block_scope.block_node.base,
2327 .rparen = try appendToken(rp.c, .RParen, ")"),
2328 };
2329 return &grouped_expr.base;
2330}
14642331
1465 try container_node.fields_and_decls.push(&field_node.base);
1466 _ = try appendToken(c, .Comma, ",");
1467 // In C each enum value is in the global namespace. So we put them there too.
1468 // At this point we can rely on the enum emitting successfully.
1469 try addEnumTopLevel(c, name, field_name, enum_val_name);
2332fn transCreatePostCrement(
2333 rp: RestorePoint,
2334 scope: *Scope,
2335 stmt: *const ZigClangUnaryOperator,
2336 op: ast.Node.InfixOp.Op,
2337 op_tok_id: std.zig.Token.Id,
2338 bytes: []const u8,
2339 used: ResultUsed,
2340) TransError!*ast.Node {
2341 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2342
2343 if (used == .unused) {
2344 // common case
2345 // c: ++expr
2346 // zig: expr += 1
2347 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2348 const token = try appendToken(rp.c, op_tok_id, bytes);
2349 const one = try transCreateNodeInt(rp.c, 1);
2350 _ = try appendToken(rp.c, .Semicolon, ";");
2351 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2352 }
2353 // worst case
2354 // c: expr++
2355 // zig: (blk: {
2356 // zig: const _ref = &expr;
2357 // zig: const _tmp = _ref.*;
2358 // zig: _ref.* += 1;
2359 // zig: break :blk _tmp
2360 // zig: })
2361 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2362 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
2363 const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()});
2364
2365 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
2366 node.eq_token = try appendToken(rp.c, .Equal, "=");
2367 const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2368 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2369 node.init_node = &rhs_node.base;
2370 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2371 try block_scope.block_node.statements.push(&node.base);
2372
2373 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
2374 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
2375 _ = try appendToken(rp.c, .Semicolon, ";");
2376
2377 const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()});
2378 const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
2379 tmp_node.eq_token = try appendToken(rp.c, .Equal, "=");
2380 tmp_node.init_node = ref_node;
2381 tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2382 try block_scope.block_node.statements.push(&tmp_node.base);
2383
2384 const token = try appendToken(rp.c, op_tok_id, bytes);
2385 const one = try transCreateNodeInt(rp.c, 1);
2386 _ = try appendToken(rp.c, .Semicolon, ";");
2387 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
2388 try block_scope.block_node.statements.push(assign);
2389
2390 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
2391 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
2392 try block_scope.block_node.statements.push(&break_node.base);
2393 _ = try appendToken(rp.c, .Semicolon, ";");
2394 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2395 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
2396 grouped_expr.* = .{
2397 .lparen = try appendToken(rp.c, .LParen, "("),
2398 .expr = &block_scope.block_node.base,
2399 .rparen = try appendToken(rp.c, .RParen, ")"),
2400 };
2401 return &grouped_expr.base;
2402}
2403
2404fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
2405 switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {
2406 .MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2407 return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)
2408 else
2409 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),
2410 .AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2411 return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
2412 else
2413 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
2414 .SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
2415 return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
2416 else
2417 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
2418 .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),
2419 .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),
2420 .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),
2421 .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),
2422 .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),
2423 else => return revertAndWarn(
2424 rp,
2425 error.UnsupportedTranslation,
2426 ZigClangCompoundAssignOperator_getBeginLoc(stmt),
2427 "unsupported C translation {}",
2428 .{ZigClangCompoundAssignOperator_getOpcode(stmt)},
2429 ),
2430 }
2431}
2432
2433fn transCreateCompoundAssign(
2434 rp: RestorePoint,
2435 scope: *Scope,
2436 stmt: *const ZigClangCompoundAssignOperator,
2437 assign_op: ast.Node.InfixOp.Op,
2438 assign_tok_id: std.zig.Token.Id,
2439 assign_bytes: []const u8,
2440 bin_op: ast.Node.InfixOp.Op,
2441 bin_tok_id: std.zig.Token.Id,
2442 bin_bytes: []const u8,
2443 used: ResultUsed,
2444) TransError!*ast.Node {
2445 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
2446 const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
2447 const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
2448 const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
2449 if (used == .unused) {
2450 // common case
2451 // c: lhs += rhs
2452 // zig: lhs += rhs
2453 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
2454 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
2455 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2456
2457 if (is_shift) {
2458 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2459 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
2460 try as_node.params.push(rhs_type);
2461 _ = try appendToken(rp.c, .Comma, ",");
2462 try as_node.params.push(rhs_node);
2463 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2464 rhs_node = &as_node.base;
14702465 }
1471 container_node.rbrace_token = try appendToken(c, .RBrace, "}");
2466 if (scope.id != .Condition)
2467 _ = try appendToken(rp.c, .Semicolon, ";");
2468 return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
2469 }
2470 // worst case
2471 // c: lhs += rhs
2472 // zig: (blk: {
2473 // zig: const _ref = &lhs;
2474 // zig: _ref.* = _ref.* + rhs;
2475 // zig: break :blk _ref.*
2476 // zig: })
2477 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2478 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
2479 const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()});
2480
2481 const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
2482 node.eq_token = try appendToken(rp.c, .Equal, "=");
2483 const addr_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2484 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
2485 node.init_node = &addr_node.base;
2486 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2487 try block_scope.block_node.statements.push(&node.base);
2488
2489 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
2490 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
2491 _ = try appendToken(rp.c, .Semicolon, ";");
2492 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
2493 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2494 if (is_shift) {
2495 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2496 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
2497 try as_node.params.push(rhs_type);
2498 _ = try appendToken(rp.c, .Comma, ",");
2499 try as_node.params.push(rhs_node);
2500 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2501 rhs_node = &as_node.base;
2502 }
2503 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
14722504
1473 break :blk &container_node.base;
1474 } else
1475 try transCreateNodeOpaqueType(c);
2505 _ = try appendToken(rp.c, .Semicolon, ";");
14762506
1477 const semicolon_token = try appendToken(c, .Semicolon, ";");
2507 const eq_token = try appendToken(rp.c, .Equal, "=");
2508 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
2509 try block_scope.block_node.statements.push(assign);
14782510
1479 const node = try c.a().create(ast.Node.VarDecl);
1480 node.* = ast.Node.VarDecl{
1481 .visib_token = visib_tok,
1482 .mut_token = const_tok,
1483 .name_token = name_tok,
1484 .eq_token = eq_tok,
1485 .init_node = init_node,
1486 .semicolon_token = semicolon_token,
1487 .doc_comments = null,
1488 .comptime_token = null,
1489 .extern_export_token = null,
1490 .thread_local_token = null,
1491 .lib_name = null,
1492 .type_node = null,
1493 .align_node = null,
1494 .section_node = null,
2511 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
2512 break_node.rhs = ref_node;
2513 try block_scope.block_node.statements.push(&break_node.base);
2514 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2515 // semicolon must immediately follow rbrace because it is the last token in a block
2516 _ = try appendToken(rp.c, .Semicolon, ";");
2517 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
2518 grouped_expr.* = .{
2519 .lparen = try appendToken(rp.c, .LParen, "("),
2520 .expr = &block_scope.block_node.base,
2521 .rparen = try appendToken(rp.c, .RParen, ")"),
14952522 };
2523 return &grouped_expr.base;
2524}
14962525
1497 try addTopLevelDecl(c, name, &node.base);
1498 if (!is_unnamed)
1499 try c.alias_list.push(.{ .alias = bare_name, .name = name });
1500 return transCreateNodeIdentifier(c, name);
2526fn transCPtrCast(
2527 rp: RestorePoint,
2528 loc: ZigClangSourceLocation,
2529 dst_type: ZigClangQualType,
2530 src_type: ZigClangQualType,
2531 expr: *ast.Node,
2532) !*ast.Node {
2533 const ty = ZigClangQualType_getTypePtr(dst_type);
2534 const child_type = ZigClangType_getPointeeType(ty);
2535
2536 // Implicit downcasting from higher to lower alignment values is forbidden,
2537 // use @alignCast to side-step this problem
2538 const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");
2539 const dst_type_node = try transType(rp, ty, loc);
2540 try ptrcast_node.params.push(dst_type_node);
2541 _ = try appendToken(rp.c, .Comma, ",");
2542
2543 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {
2544 // void has 1-byte alignment, so @alignCast is not needed
2545 try ptrcast_node.params.push(expr);
2546 } else {
2547 const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast");
2548 const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf");
2549 const child_type_node = try transQualType(rp, child_type, loc);
2550 try alignof_node.params.push(child_type_node);
2551 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2552 try aligncast_node.params.push(&alignof_node.base);
2553 _ = try appendToken(rp.c, .Comma, ",");
2554 try aligncast_node.params.push(expr);
2555 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2556 try ptrcast_node.params.push(&aligncast_node.base);
2557 }
2558 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2559
2560 return &ptrcast_node.base;
15012561}
15022562
1503fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {
1504 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1505 const const_tok = try appendToken(c, .Keyword_const, "const");
1506 const name_tok = try appendIdentifier(c, enum_val_name);
1507 const eq_tok = try appendToken(c, .Equal, "=");
2563fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
2564 const break_scope = scope.getBreakableScope();
2565 const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch)
2566 "__switch"
2567 else
2568 null);
2569 _ = try appendToken(rp.c, .Semicolon, ";");
2570 return &br.base;
2571}
15082572
1509 const enum_ident = try transCreateNodeIdentifier(c, enum_name);
1510 const period_tok = try appendToken(c, .Period, ".");
1511 const field_ident = try transCreateNodeIdentifier(c, field_name);
2573fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
2574 // TODO use something more accurate
2575 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);
2576 const node = try rp.c.a().create(ast.Node.FloatLiteral);
2577 node.* = .{
2578 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
2579 };
2580 return maybeSuppressResult(rp, scope, used, &node.base);
2581}
15122582
1513 const field_access_node = try c.a().create(ast.Node.InfixOp);
1514 field_access_node.* = .{
1515 .op_token = period_tok,
1516 .lhs = enum_ident,
1517 .op = .Period,
1518 .rhs = field_ident,
2583fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node {
2584 const grouped = scope.id == .Condition;
2585 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
2586 const if_node = try transCreateNodeIf(rp.c);
2587 var cond_scope = Scope{
2588 .parent = scope,
2589 .id = .Condition,
15192590 };
1520 const semicolon_token = try appendToken(c, .Semicolon, ";");
15212591
1522 const node = try c.a().create(ast.Node.VarDecl);
1523 node.* = ast.Node.VarDecl{
1524 .visib_token = visib_tok,
1525 .mut_token = const_tok,
1526 .name_token = name_tok,
1527 .eq_token = eq_tok,
1528 .init_node = &field_access_node.base,
1529 .semicolon_token = semicolon_token,
1530 .thread_local_token = null,
1531 .doc_comments = null,
1532 .comptime_token = null,
1533 .extern_export_token = null,
1534 .lib_name = null,
1535 .type_node = null,
1536 .align_node = null,
1537 .section_node = null,
2592 const cond_expr = ZigClangConditionalOperator_getCond(stmt);
2593 const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt);
2594 const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt);
2595
2596 if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false);
2597 _ = try appendToken(rp.c, .RParen, ")");
2598
2599 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
2600
2601 if_node.@"else" = try transCreateNodeElse(rp.c);
2602 if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);
2603
2604 if (grouped) {
2605 const rparen = try appendToken(rp.c, .RParen, ")");
2606 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
2607 grouped_expr.* = .{
2608 .lparen = lparen,
2609 .expr = &if_node.base,
2610 .rparen = rparen,
2611 };
2612 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
2613 } else {
2614 return maybeSuppressResult(rp, scope, used, &if_node.base);
2615 }
2616}
2617
2618fn maybeSuppressResult(
2619 rp: RestorePoint,
2620 scope: *Scope,
2621 used: ResultUsed,
2622 result: *ast.Node,
2623) TransError!*ast.Node {
2624 if (used == .used) return result;
2625 if (scope.id != .Condition) {
2626 // NOTE: This is backwards, but the semicolon must immediately follow the node.
2627 _ = try appendToken(rp.c, .Semicolon, ";");
2628 } else { // TODO is there a way to avoid this hack?
2629 // this parenthesis must come immediately following the node
2630 _ = try appendToken(rp.c, .RParen, ")");
2631 // these need to come before _
2632 _ = try appendToken(rp.c, .Colon, ":");
2633 _ = try appendToken(rp.c, .LParen, "(");
2634 }
2635 const lhs = try transCreateNodeIdentifier(rp.c, "_");
2636 const op_token = try appendToken(rp.c, .Equal, "=");
2637 const op_node = try rp.c.a().create(ast.Node.InfixOp);
2638 op_node.* = .{
2639 .op_token = op_token,
2640 .lhs = lhs,
2641 .op = .Assign,
2642 .rhs = result,
15382643 };
2644 return &op_node.base;
2645}
15392646
1540 try addTopLevelDecl(c, field_name, &node.base);
2647fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
2648 try c.tree.root_node.decls.push(decl_node);
2649 _ = try c.global_scope.sym_table.put(name, decl_node);
2650}
2651
2652fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {
2653 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
15412654}
15422655
15432656fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
......@@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
15522665 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
15532666}
15542667
2668fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 {
2669 const ty = ZigClangQualType_getTypePtr(qt);
2670
2671 switch (ZigClangType_getTypeClass(ty)) {
2672 .Builtin => {
2673 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
2674
2675 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2676 .Char_U,
2677 .UChar,
2678 .Char_S,
2679 .SChar,
2680 => return 8,
2681 .UInt128,
2682 .Int128,
2683 => return 128,
2684 else => return 0,
2685 }
2686
2687 unreachable;
2688 },
2689 .Typedef => {
2690 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
2691 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
2692 const type_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
2693
2694 if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) {
2695 return 8;
2696 } else if (mem.eql(u8, type_name, "uint16_t") or mem.eql(u8, type_name, "int16_t")) {
2697 return 16;
2698 } else if (mem.eql(u8, type_name, "uint32_t") or mem.eql(u8, type_name, "int32_t")) {
2699 return 32;
2700 } else if (mem.eql(u8, type_name, "uint64_t") or mem.eql(u8, type_name, "int64_t")) {
2701 return 64;
2702 } else {
2703 return 0;
2704 }
2705 },
2706 else => return 0,
2707 }
2708
2709 unreachable;
2710}
2711
2712fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
2713 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
2714
2715 if (int_bit_width != 0) {
2716 // we can perform the log2 now.
2717 const cast_bit_width = std.math.log2_int(u64, int_bit_width);
2718 const node = try rp.c.a().create(ast.Node.IntegerLiteral);
2719 node.* = ast.Node.IntegerLiteral{
2720 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
2721 };
2722 return &node.base;
2723 }
2724
2725 const zig_type_node = try transQualType(rp, qt, source_loc);
2726
2727 // @import("std").math.Log2Int(c_long);
2728 //
2729 // FnCall
2730 // FieldAccess
2731 // FieldAccess
2732 // FnCall (.builtin = true)
2733 // Symbol "import"
2734 // StringLiteral "std"
2735 // Symbol "math"
2736 // Symbol "Log2Int"
2737 // Symbol <zig_type_node> (var from above)
2738
2739 const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import");
2740 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
2741 const std_node = try rp.c.a().create(ast.Node.StringLiteral);
2742 std_node.* = ast.Node.StringLiteral{
2743 .token = std_token,
2744 };
2745 try import_fn_call.params.push(&std_node.base);
2746 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
2747
2748 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
2749 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
2750 const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access);
2751 try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node);
2752 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
2753
2754 return &log2int_fn_call.base;
2755}
2756
15552757fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
15562758 const ty = ZigClangQualType_getTypePtr(qt);
15572759
......@@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
16012803 return ZigClangExpr_getType(expr);
16022804}
16032805
2806fn getExprQualTypeBeforeImplicitCast(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
2807 if (ZigClangExpr_getStmtClass(expr) == .ImplicitCastExprClass) {
2808 const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr);
2809 return getExprQualType(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr));
2810 }
2811 return ZigClangExpr_getType(expr);
2812}
2813
16042814fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {
16052815 switch (ZigClangType_getTypeClass(ty)) {
16062816 .Builtin => {
......@@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
16572867 };
16582868}
16592869
2870fn cIsSignedInteger(qt: ZigClangQualType) bool {
2871 const c_type = qualTypeCanon(qt);
2872 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
2873 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
2874 return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2875 .SChar,
2876 .Short,
2877 .Int,
2878 .Long,
2879 .LongLong,
2880 .Int128,
2881 .WChar_S,
2882 => true,
2883 else => false,
2884 };
2885}
2886
2887fn cIsFloating(qt: ZigClangQualType) bool {
2888 const c_type = qualTypeCanon(qt);
2889 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
2890 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
2891 return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2892 .Float,
2893 .Double,
2894 .Float128,
2895 .LongDouble,
2896 => true,
2897 else => false,
2898 };
2899}
2900
16602901fn transCreateNodeAssign(
16612902 rp: RestorePoint,
16622903 scope: *Scope,
16632904 result_used: ResultUsed,
16642905 lhs: *const ZigClangExpr,
16652906 rhs: *const ZigClangExpr,
1666) !*ast.Node.InfixOp {
2907) !*ast.Node {
16672908 // common case
16682909 // c: lhs = rhs
16692910 // zig: lhs = rhs
16702911 if (result_used == .unused) {
16712912 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
16722913 const eq_token = try appendToken(rp.c, .Equal, "=");
1673 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
1674 _ = try appendToken(rp.c, .Semicolon, ";");
1675
1676 const node = try rp.c.a().create(ast.Node.InfixOp);
1677 node.* = .{
1678 .op_token = eq_token,
1679 .lhs = lhs_node,
1680 .op = .Assign,
1681 .rhs = rhs_node,
1682 };
1683 return node;
2914 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2915 if (isBoolRes(rhs_node)) {
2916 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
2917 try builtin_node.params.push(rhs_node);
2918 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2919 rhs_node = &builtin_node.base;
2920 }
2921 if (scope.id != .Condition)
2922 _ = try appendToken(rp.c, .Semicolon, ";");
2923 return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false);
16842924 }
16852925
16862926 // worst case
16872927 // c: lhs = rhs
1688 // zig: (x: {
2928 // zig: (blk: {
16892929 // zig: const _tmp = rhs;
16902930 // zig: lhs = _tmp;
1691 // zig: break :x _tmp
2931 // zig: break :blk _tmp
16922932 // zig: })
1693 return revertAndWarn(
1694 rp,
1695 error.UnsupportedTranslation,
1696 ZigClangExpr_getBeginLoc(lhs),
1697 "TODO: worst case assign op expr",
1698 .{},
1699 );
2933 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
2934 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
2935 const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()});
2936
2937 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
2938 node.eq_token = try appendToken(rp.c, .Equal, "=");
2939 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2940 if (isBoolRes(rhs_node)) {
2941 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
2942 try builtin_node.params.push(rhs_node);
2943 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2944 rhs_node = &builtin_node.base;
2945 }
2946 node.init_node = rhs_node;
2947 node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
2948 try block_scope.block_node.statements.push(&node.base);
2949
2950 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
2951 const eq_token = try appendToken(rp.c, .Equal, "=");
2952 const ident = try transCreateNodeIdentifier(rp.c, tmp);
2953 _ = try appendToken(rp.c, .Semicolon, ";");
2954
2955 const assign = try transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, ident, .used, false);
2956 try block_scope.block_node.statements.push(assign);
2957
2958 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
2959 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
2960 _ = try appendToken(rp.c, .Semicolon, ";");
2961 try block_scope.block_node.statements.push(&break_node.base);
2962 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2963 // semicolon must immediately follow rbrace because it is the last token in a block
2964 _ = try appendToken(rp.c, .Semicolon, ";");
2965 return &block_scope.block_node.base;
17002966}
17012967
17022968fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall {
17032969 const builtin_token = try appendToken(c, .Builtin, name);
17042970 _ = try appendToken(c, .LParen, "(");
17052971 const node = try c.a().create(ast.Node.BuiltinCall);
1706 node.* = ast.Node.BuiltinCall{
2972 node.* = .{
17072973 .builtin_token = builtin_token,
17082974 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
17092975 .rparen_token = undefined, // set after appending args
......@@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti
17142980fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
17152981 _ = try appendToken(c, .LParen, "(");
17162982 const node = try c.a().create(ast.Node.SuffixOp);
1717 node.* = ast.Node.SuffixOp{
2983 node.* = .{
17182984 .lhs = .{ .node = fn_expr },
1719 .op = ast.Node.SuffixOp.Op{
1720 .Call = ast.Node.SuffixOp.Op.Call{
2985 .op = .{
2986 .Call = .{
17212987 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
17222988 .async_token = null,
17232989 },
......@@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
17272993 return node;
17282994}
17292995
2996fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
2997 const field_access_node = try c.a().create(ast.Node.InfixOp);
2998 field_access_node.* = .{
2999 .op_token = try appendToken(c, .Period, "."),
3000 .lhs = container,
3001 .op = .Period,
3002 .rhs = try transCreateNodeIdentifier(c, field_name),
3003 };
3004 return &field_access_node.base;
3005}
3006
17303007fn transCreateNodePrefixOp(
17313008 c: *Context,
17323009 op: ast.Node.PrefixOp.Op,
......@@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp(
17453022fn transCreateNodeInfixOp(
17463023 rp: RestorePoint,
17473024 scope: *Scope,
1748 stmt: *const ZigClangBinaryOperator,
3025 lhs_node: *ast.Node,
17493026 op: ast.Node.InfixOp.Op,
1750 op_tok_id: std.zig.Token.Id,
1751 bytes: []const u8,
3027 op_token: ast.TokenIndex,
3028 rhs_node: *ast.Node,
3029 used: ResultUsed,
17523030 grouped: bool,
17533031) !*ast.Node {
1754 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
1755 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
1756 const op_token = try appendToken(rp.c, op_tok_id, bytes);
1757 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
3032 var lparen = if (grouped)
3033 try appendToken(rp.c, .LParen, "(")
3034 else
3035 null;
17583036 const node = try rp.c.a().create(ast.Node.InfixOp);
1759 node.* = ast.Node.InfixOp{
3037 node.* = .{
17603038 .op_token = op_token,
1761 .lhs = lhs,
3039 .lhs = lhs_node,
17623040 .op = op,
1763 .rhs = rhs,
3041 .rhs = rhs_node,
17643042 };
1765 if (!grouped) return &node.base;
3043 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
17663044 const rparen = try appendToken(rp.c, .RParen, ")");
17673045 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
1768 grouped_expr.* = ast.Node.GroupedExpression{
1769 .lparen = lparen,
3046 grouped_expr.* = .{
3047 .lparen = lparen.?,
17703048 .expr = &node.base,
17713049 .rparen = rparen,
17723050 };
1773 return &grouped_expr.base;
3051 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
3052}
3053
3054fn transCreateNodeBoolInfixOp(
3055 rp: RestorePoint,
3056 scope: *Scope,
3057 stmt: *const ZigClangBinaryOperator,
3058 op: ast.Node.InfixOp.Op,
3059 used: ResultUsed,
3060 grouped: bool,
3061) !*ast.Node {
3062 std.debug.assert(op == .BoolAnd or op == .BoolOr);
3063
3064 const lhs_hode = try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value, true);
3065 const op_token = if (op == .BoolAnd)
3066 try appendToken(rp.c, .Keyword_and, "and")
3067 else
3068 try appendToken(rp.c, .Keyword_or, "or");
3069 const rhs = try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value, true);
3070
3071 return transCreateNodeInfixOp(
3072 rp,
3073 scope,
3074 lhs_hode,
3075 op,
3076 op_token,
3077 rhs,
3078 used,
3079 grouped,
3080 );
17743081}
17753082
17763083fn transCreateNodePtrType(
......@@ -1797,9 +3104,9 @@ fn transCreateNodePtrType(
17973104 .Asterisk => try appendToken(c, .Asterisk, "*"),
17983105 else => unreachable,
17993106 };
1800 node.* = ast.Node.PrefixOp{
3107 node.* = .{
18013108 .op_token = op_token,
1802 .op = ast.Node.PrefixOp.Op{
3109 .op = .{
18033110 .PtrType = .{
18043111 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
18053112 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
......@@ -1810,11 +3117,17 @@ fn transCreateNodePtrType(
18103117 return node;
18113118}
18123119
1813fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
1814 const num_limbs = ZigClangAPSInt_getNumWords(int.?);
3120fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
3121 const num_limbs = ZigClangAPSInt_getNumWords(int);
3122 var aps_int = int;
3123 const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
3124 if (is_negative)
3125 aps_int = ZigClangAPSInt_negate(aps_int);
18153126 var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);
3127 if (is_negative)
3128 big.negate();
18163129 defer big.deinit();
1817 const data = ZigClangAPSInt_getRawData(int.?);
3130 const data = ZigClangAPSInt_getRawData(aps_int);
18183131 var i: @TypeOf(num_limbs) = 0;
18193132 while (i < num_limbs) : (i += 1) big.limbs[i] = data[i];
18203133 const str = big.toString(c.a(), 10) catch |err| switch (err) {
......@@ -1823,16 +3136,18 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
18233136 };
18243137 const token = try appendToken(c, .IntegerLiteral, str);
18253138 const node = try c.a().create(ast.Node.IntegerLiteral);
1826 node.* = ast.Node.IntegerLiteral{
3139 node.* = .{
18273140 .token = token,
18283141 };
3142 if (is_negative)
3143 ZigClangAPSInt_free(aps_int);
18293144 return &node.base;
18303145}
18313146
18323147fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
18333148 const ltoken = try appendToken(c, .Keyword_return, "return");
18343149 const node = try c.a().create(ast.Node.ControlFlowExpression);
1835 node.* = ast.Node.ControlFlowExpression{
3150 node.* = .{
18363151 .ltoken = ltoken,
18373152 .kind = .Return,
18383153 .rhs = null,
......@@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
18433158fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
18443159 const token = try appendToken(c, .Keyword_undefined, "undefined");
18453160 const node = try c.a().create(ast.Node.UndefinedLiteral);
1846 node.* = ast.Node.UndefinedLiteral{
3161 node.* = .{
18473162 .token = token,
18483163 };
18493164 return &node.base;
......@@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
18523167fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
18533168 const token = try appendToken(c, .Keyword_null, "null");
18543169 const node = try c.a().create(ast.Node.NullLiteral);
1855 node.* = ast.Node.NullLiteral{
3170 node.* = .{
18563171 .token = token,
18573172 };
18583173 return &node.base;
......@@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
18643179 else
18653180 try appendToken(c, .Keyword_false, "false");
18663181 const node = try c.a().create(ast.Node.BoolLiteral);
1867 node.* = ast.Node.BoolLiteral{
3182 node.* = .{
18683183 .token = token,
18693184 };
18703185 return &node.base;
18713186}
18723187
1873fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp {
3188fn transCreateNodeContainerInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp {
18743189 _ = try appendToken(c, .LBrace, "{");
18753190 const node = try c.a().create(ast.Node.SuffixOp);
18763191 node.* = ast.Node.SuffixOp{
......@@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N
18863201fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
18873202 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
18883203 const node = try c.a().create(ast.Node.IntegerLiteral);
1889 node.* = ast.Node.IntegerLiteral{
3204 node.* = .{
18903205 .token = token,
18913206 };
18923207 return &node.base;
......@@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
19073222 return &call_node.base;
19083223}
19093224
1910fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node {
3225fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
19113226 const scope = &c.global_scope.base;
19123227
19133228 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
......@@ -1916,8 +3231,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
19163231 const name_tok = try appendIdentifier(c, name);
19173232 _ = try appendToken(c, .LParen, "(");
19183233
1919 const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?;
1920
19213234 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
19223235 var it = proto_alias.params.iterator(0);
19233236 while (it.next()) |pn| {
......@@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {
20463359 return block_node;
20473360}
20483361
3362fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {
3363 const ltoken = try appendToken(c, .Keyword_break, "break");
3364 const label_node = if (label) |l| blk: {
3365 _ = try appendToken(c, .Colon, ":");
3366 break :blk try transCreateNodeIdentifier(c, l);
3367 } else null;
3368 const node = try c.a().create(ast.Node.ControlFlowExpression);
3369 node.* = .{
3370 .ltoken = ltoken,
3371 .kind = .{ .Break = label_node },
3372 .rhs = null,
3373 };
3374 return node;
3375}
3376
3377fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []const u8) !*ast.Node.VarDecl {
3378 const visib_tok = if (is_pub) try appendToken(c, .Keyword_pub, "pub") else null;
3379 const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var");
3380 const name_tok = try appendIdentifier(c, name);
3381
3382 const node = try c.a().create(ast.Node.VarDecl);
3383 node.* = .{
3384 .doc_comments = null,
3385 .visib_token = visib_tok,
3386 .thread_local_token = null,
3387 .name_token = name_tok,
3388 .eq_token = undefined,
3389 .mut_token = mut_tok,
3390 .comptime_token = null,
3391 .extern_export_token = null,
3392 .lib_name = null,
3393 .type_node = null,
3394 .align_node = null,
3395 .section_node = null,
3396 .init_node = null,
3397 .semicolon_token = undefined,
3398 };
3399 return node;
3400}
3401
3402fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
3403 const while_tok = try appendToken(c, .Keyword_while, "while");
3404 _ = try appendToken(c, .LParen, "(");
3405
3406 const node = try c.a().create(ast.Node.While);
3407 node.* = .{
3408 .label = null,
3409 .inline_token = null,
3410 .while_token = while_tok,
3411 .condition = undefined,
3412 .payload = null,
3413 .continue_expr = null,
3414 .body = undefined,
3415 .@"else" = null,
3416 };
3417 return node;
3418}
3419
3420fn transCreateNodeContinue(c: *Context) !*ast.Node {
3421 const ltoken = try appendToken(c, .Keyword_continue, "continue");
3422 const node = try c.a().create(ast.Node.ControlFlowExpression);
3423 node.* = .{
3424 .ltoken = ltoken,
3425 .kind = .{ .Continue = null },
3426 .rhs = null,
3427 };
3428 _ = try appendToken(c, .Semicolon, ";");
3429 return &node.base;
3430}
3431
3432fn transCreateNodeSwitch(c: *Context) !*ast.Node.Switch {
3433 const switch_tok = try appendToken(c, .Keyword_switch, "switch");
3434 _ = try appendToken(c, .LParen, "(");
3435
3436 const node = try c.a().create(ast.Node.Switch);
3437 node.* = .{
3438 .switch_token = switch_tok,
3439 .expr = undefined,
3440 .cases = ast.Node.Switch.CaseList.init(c.a()),
3441 .rbrace = undefined,
3442 };
3443 return node;
3444}
3445
3446fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase {
3447 const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>");
3448
3449 const node = try c.a().create(ast.Node.SwitchCase);
3450 node.* = .{
3451 .items = ast.Node.SwitchCase.ItemList.init(c.a()),
3452 .arrow_token = arrow_tok,
3453 .payload = null,
3454 .expr = undefined,
3455 };
3456 try node.items.push(lhs);
3457 return node;
3458}
3459
3460fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {
3461 const node = try c.a().create(ast.Node.SwitchElse);
3462 node.* = .{
3463 .token = try appendToken(c, .Keyword_else, "else"),
3464 };
3465 return &node.base;
3466}
3467
3468fn transCreateNodeShiftOp(
3469 rp: RestorePoint,
3470 scope: *Scope,
3471 stmt: *const ZigClangBinaryOperator,
3472 op: ast.Node.InfixOp.Op,
3473 op_tok_id: std.zig.Token.Id,
3474 bytes: []const u8,
3475) !*ast.Node {
3476 std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight);
3477
3478 const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
3479 const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
3480 const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
3481 // lhs >> @as(u5, rh)
3482
3483 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
3484 const op_token = try appendToken(rp.c, op_tok_id, bytes);
3485
3486 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
3487 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
3488 try as_node.params.push(rhs_type);
3489 _ = try appendToken(rp.c, .Comma, ",");
3490 const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
3491 try as_node.params.push(rhs);
3492 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3493
3494 const node = try rp.c.a().create(ast.Node.InfixOp);
3495 node.* = ast.Node.InfixOp{
3496 .op_token = op_token,
3497 .lhs = lhs,
3498 .op = op,
3499 .rhs = &as_node.base,
3500 };
3501
3502 return &node.base;
3503}
3504
3505fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
3506 const node = try c.a().create(ast.Node.SuffixOp);
3507 node.* = .{
3508 .lhs = .{ .node = lhs },
3509 .op = .Deref,
3510 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
3511 };
3512 return &node.base;
3513}
3514
3515fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {
3516 _ = try appendToken(c, .LBrace, "[");
3517 const node = try c.a().create(ast.Node.SuffixOp);
3518 node.* = .{
3519 .lhs = .{ .node = lhs },
3520 .op = .{
3521 .ArrayAccess = undefined,
3522 },
3523 .rtoken = undefined,
3524 };
3525 return node;
3526}
3527
20493528const RestorePoint = struct {
20503529 c: *Context,
20513530 token_index: ast.TokenIndex,
......@@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
20923571 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
20933572 });
20943573 },
2095 .FunctionProto => {
3574 .FunctionProto, .FunctionNoProto => {
20963575 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
20973576 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);
20983577 return &fn_proto.base;
......@@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
21673646 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
21683647
21693648 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
2170 const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
2171 return transCreateNodeIdentifier(rp.c, typedef_name);
3649 return (try transTypeDef(rp.c, typedef_decl)) orelse
3650 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
21723651 },
21733652 .Record => {
21743653 const record_ty = @ptrCast(*const ZigClangRecordType, ty);
21753654
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 // };
21833655 const record_decl = ZigClangRecordType_getDecl(record_ty);
2184 if (try getContainerName(rp, record_decl)) |name|
2185 return transCreateNodeIdentifier(rp.c, name)
2186 else
2187 return transRecordDecl(rp.c, record_decl);
3656 return (try transRecordDecl(rp.c, record_decl)) orelse
3657 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
21883658 },
21893659 .Enum => {
21903660 const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
......@@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
22053675 const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty);
22063676 return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc);
22073677 },
3678 .MacroQualified => {
3679 const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty);
3680 return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc);
3681 },
22083682 else => {
22093683 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
22103684 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});
......@@ -2212,22 +3686,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
22123686 }
22133687}
22143688
2215fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 {
2216 const bare_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
2217
2218 const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl))
2219 "union"
2220 else if (ZigClangRecordDecl_isStruct(record_decl))
2221 "struct"
2222 else
2223 return revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name});
2224
2225 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)
2226 return null;
2227
2228 return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name });
2229}
2230
22313689fn isCVoid(qt: ZigClangQualType) bool {
22323690 const ty = ZigClangQualType_getTypePtr(qt);
22333691 if (ZigClangType_getTypeClass(ty) == .Builtin) {
......@@ -2241,7 +3699,6 @@ const FnDeclContext = struct {
22413699 fn_name: []const u8,
22423700 has_body: bool,
22433701 storage_class: ZigClangStorageClass,
2244 scope: **Scope,
22453702 is_export: bool,
22463703};
22473704
......@@ -2307,9 +3764,6 @@ fn finishTransFnProto(
23073764 // TODO check for always_inline attribute
23083765 // TODO check for align attribute
23093766
2310 var fndef_scope = Scope.FnDef.init(rp.c);
2311 const scope = &fndef_scope.base;
2312
23133767 // pub extern fn name(...) T
23143768 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
23153769 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
......@@ -2335,15 +3789,11 @@ fn finishTransFnProto(
23353789 const param_name_tok: ?ast.TokenIndex = blk: {
23363790 if (fn_decl != null) {
23373791 const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i));
2338 var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
3792 const param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param)));
23393793 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;
3794 break :blk null;
23453795
2346 const result = try appendIdentifier(rp.c, checked_param_name);
3796 const result = try appendIdentifier(rp.c, param_name);
23473797 _ = try appendToken(rp.c, .Colon, ":");
23483798 break :blk result;
23493799 }
......@@ -2410,14 +3860,13 @@ fn finishTransFnProto(
24103860 };
24113861
24123862 const fn_proto = try rp.c.a().create(ast.Node.FnProto);
2413 fn_proto.* = ast.Node.FnProto{
2414 .base = ast.Node{ .id = ast.Node.Id.FnProto },
3863 fn_proto.* = .{
24153864 .doc_comments = null,
24163865 .visib_token = pub_tok,
24173866 .fn_token = fn_tok,
24183867 .name_token = name_tok,
24193868 .params = fn_params,
2420 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },
3869 .return_type = .{ .Explicit = return_type_node },
24213870 .var_args_token = null, // TODO this field is broken in the AST data model
24223871 .extern_export_inline_token = extern_export_inline_tok,
24233872 .cc_token = cc_tok,
......@@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8,
25233972 return token_index;
25243973}
25253974
3975// TODO hook up with codegen
3976fn isZigPrimitiveType(name: []const u8) bool {
3977 if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
3978 for (name[1..]) |c| {
3979 switch (c) {
3980 '0'...'9' => {},
3981 else => return false,
3982 }
3983 }
3984 return true;
3985 }
3986 // void is invalid in c so it doesn't need to be checked.
3987 return mem.eql(u8, name, "comptime_float") or
3988 mem.eql(u8, name, "comptime_int") or
3989 mem.eql(u8, name, "bool") or
3990 mem.eql(u8, name, "isize") or
3991 mem.eql(u8, name, "usize") or
3992 mem.eql(u8, name, "f16") or
3993 mem.eql(u8, name, "f32") or
3994 mem.eql(u8, name, "f64") or
3995 mem.eql(u8, name, "f128") or
3996 mem.eql(u8, name, "c_longdouble") or
3997 mem.eql(u8, name, "noreturn") or
3998 mem.eql(u8, name, "type") or
3999 mem.eql(u8, name, "anyerror") or
4000 mem.eql(u8, name, "c_short") or
4001 mem.eql(u8, name, "c_ushort") or
4002 mem.eql(u8, name, "c_int") or
4003 mem.eql(u8, name, "c_uint") or
4004 mem.eql(u8, name, "c_long") or
4005 mem.eql(u8, name, "c_ulong") or
4006 mem.eql(u8, name, "c_longlong") or
4007 mem.eql(u8, name, "c_ulonglong");
4008}
4009
25264010fn isValidZigIdentifier(name: []const u8) bool {
25274011 for (name) |c, i| {
25284012 switch (c) {
......@@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
25734057 const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro);
25744058
25754059 const name = try c.str(raw_name);
2576 if (scope.contains(name)) {
4060
4061 // TODO https://github.com/ziglang/zig/issues/3756
4062 // TODO https://github.com/ziglang/zig/issues/1802
4063 const checked_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name;
4064 if (scope.contains(checked_name)) {
25774065 continue;
25784066 }
25794067 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
25804068 ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) {
25814069 error.OutOfMemory => |e| return e,
25824070 else => {
2583 try failDecl(c, begin_loc, name, "unable to tokenize macro definition", .{});
4071 try failDecl(c, begin_loc, checked_name, "unable to tokenize macro definition", .{});
25844072 continue;
25854073 },
25864074 };
25874075
25884076 var tok_it = tok_list.iterator(0);
25894077 const first_tok = tok_it.next().?;
2590 assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name));
4078 assert(first_tok.id == .Identifier and mem.eql(u8, first_tok.bytes, name));
25914079 const next = tok_it.peek().?;
25924080 switch (next.id) {
25934081 .Identifier => {
25944082 // if it equals itself, ignore. for example, from stdio.h:
25954083 // #define stdin stdin
2596 if (std.mem.eql(u8, name, next.bytes)) {
4084 if (mem.eql(u8, checked_name, next.bytes)) {
25974085 continue;
25984086 }
25994087 },
......@@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
26104098 } else false;
26114099
26124100 (if (macro_fn)
2613 transMacroFnDefine(c, &tok_it, name, begin_loc)
4101 transMacroFnDefine(c, &tok_it, checked_name, begin_loc)
26144102 else
2615 transMacroDefine(c, &tok_it, name, begin_loc)) catch |err| switch (err) {
4103 transMacroDefine(c, &tok_it, checked_name, begin_loc)) catch |err| switch (err) {
26164104 error.UnsupportedTranslation,
26174105 error.ParseError,
2618 => try failDecl(c, begin_loc, name, "unable to translate macro", .{}),
4106 => try failDecl(c, begin_loc, checked_name, "unable to translate macro", .{}),
26194107 error.OutOfMemory => |e| return e,
26204108 };
26214109 },
......@@ -2628,37 +4116,28 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8,
26284116 const rp = makeRestorePoint(c);
26294117 const scope = &c.global_scope.base;
26304118
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, "=");
4119 const node = try transCreateNodeVarDecl(c, true, true, name);
4120 node.eq_token = try appendToken(c, .Equal, "=");
26354121
2636 const init_node = try parseCExpr(rp, it, source_loc, scope);
4122 node.init_node = try parseCExpr(rp, it, source_loc, scope);
4123 const last = it.next().?;
4124 if (last.id != .Eof)
4125 return revertAndWarn(
4126 rp,
4127 error.UnsupportedTranslation,
4128 source_loc,
4129 "unable to translate C expr, unexpected token: {}",
4130 .{last.id},
4131 );
26374132
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 };
4133 node.semicolon_token = try appendToken(c, .Semicolon, ";");
26554134 _ = try c.global_scope.macro_table.put(name, &node.base);
26564135}
26574136
26584137fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
26594138 const rp = makeRestorePoint(c);
2660 var fndef_scope = Scope.FnDef.init(c);
2661 const scope = &fndef_scope.base;
4139 const block_scope = try Scope.Block.init(c, &c.global_scope.base, null);
4140 const scope = &block_scope.base;
26624141
26634142 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
26644143 const inline_tok = try appendToken(c, .Keyword_inline, "inline");
......@@ -2676,7 +4155,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
26764155 return error.ParseError;
26774156
26784157 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 });
4158 try block_scope.variables.push(.{ .name = param_tok.bytes, .alias = alias });
26804159 break :blk alias;
26814160 } else param_tok.bytes;
26824161
......@@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
27374216
27384217 const return_expr = try transCreateNodeReturnExpr(c);
27394218 const expr = try parseCExpr(rp, it, source_loc, scope);
4219 const last = it.next().?;
4220 if (last.id != .Eof)
4221 return revertAndWarn(
4222 rp,
4223 error.UnsupportedTranslation,
4224 source_loc,
4225 "unable to translate C expr, unexpected token: {}",
4226 .{last.id},
4227 );
27404228 _ = try appendToken(c, .Semicolon, ";");
27414229 try type_of.params.push(expr);
27424230 return_expr.rhs = expr;
......@@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
28384326
28394327 if (it.peek().?.id == .RParen) {
28404328 _ = it.next();
2841 return inner_node;
4329 if (it.peek().?.id != .LParen) {
4330 return inner_node;
4331 }
4332 _ = it.next();
28424333 }
28434334
28444335 // hack to get zig fmt to render a comma in builtin calls
......@@ -2930,8 +4421,8 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
29304421 rp,
29314422 error.UnsupportedTranslation,
29324423 source_loc,
2933 "unable to translate C expr",
2934 .{},
4424 "unable to translate C expr, unexpected token: {}",
4425 .{tok.id},
29354426 ),
29364427 }
29374428}
......@@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
29444435 .Dot => {
29454436 const name_tok = it.next().?;
29464437 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;
4438 return error.ParseError;
4439
4440 node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes);
4441 },
4442 .Arrow => {
4443 const name_tok = it.next().?;
4444 if (name_tok.id != .Identifier)
4445 return error.ParseError;
4446
4447 const deref = try transCreateNodePtrDeref(rp.c, node);
4448 node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes);
29654449 },
29664450 .Asterisk => {
29674451 if (it.peek().?.id == .RParen) {
......@@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
29774461 // expr * expr
29784462 const op_token = try appendToken(rp.c, .Asterisk, "*");
29794463 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
2980 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
2981 bitshift_node.* = .{
4464 const mul_node = try rp.c.a().create(ast.Node.InfixOp);
4465 mul_node.* = .{
29824466 .op_token = op_token,
29834467 .lhs = node,
29844468 .op = .BitShiftLeft,
29854469 .rhs = rhs,
29864470 };
2987 node = &bitshift_node.base;
4471 node = &mul_node.base;
29884472 }
29894473 },
29904474 .Shl => {
29914475 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");
2992 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
4476 const rhs = try parseCExpr(rp, it, source_loc, scope);
29934477 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
29944478 bitshift_node.* = .{
29954479 .op_token = op_token,
......@@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
29994483 };
30004484 node = &bitshift_node.base;
30014485 },
4486 .Pipe => {
4487 const op_token = try appendToken(rp.c, .Pipe, "|");
4488 const rhs = try parseCExpr(rp, it, source_loc, scope);
4489 const or_node = try rp.c.a().create(ast.Node.InfixOp);
4490 or_node.* = .{
4491 .op_token = op_token,
4492 .lhs = node,
4493 .op = .BitOr,
4494 .rhs = rhs,
4495 };
4496 node = &or_node.base;
4497 },
4498 .LBrace => {
4499 const arr_node = try transCreateNodeArrayAccess(rp.c, node);
4500 arr_node.op.ArrayAccess = try parseCExpr(rp, it, source_loc, scope);
4501 arr_node.rtoken = try appendToken(rp.c, .RBrace, "]");
4502 node = &arr_node.base;
4503 if (it.next().?.id != .RBrace)
4504 return error.ParseError;
4505 },
4506 .LParen => {
4507 const call_node = try transCreateNodeFnCall(rp.c, node);
4508 while (true) {
4509 const arg = try parseCExpr(rp, it, source_loc, scope);
4510 try call_node.op.Call.params.push(arg);
4511 const next = it.next().?;
4512 if (next.id == .Comma)
4513 _ = try appendToken(rp.c, .Comma, ",")
4514 else if (next.id == .RParen)
4515 break
4516 else
4517 return error.ParseError;
4518 }
4519 call_node.rtoken = try appendToken(rp.c, .RParen, ")");
4520 node = &call_node.base;
4521 },
30024522 else => {
30034523 _ = it.prev();
30044524 return node;
......@@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
30284548 },
30294549 .Asterisk => {
30304550 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;
4551 return try transCreateNodePtrDeref(rp.c, prefix_op_expr);
30384552 },
30394553 else => {
30404554 _ = it.prev();
......@@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
30434557 }
30444558}
30454559
3046fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 {
4560fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
30474561 const tok = c.tree.tokens.at(token);
3048 return c.source_buffer.toSliceConst()[tok.start..tok.end];
4562 return c.source_buffer.toSlice()[tok.start..tok.end];
30494563}
30504564
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;
4565fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
4566 if (node.id == .ContainerDecl) {
4567 return node;
4568 } else if (node.id == .PrefixOp) {
4569 return node;
4570 } else if (node.cast(ast.Node.Identifier)) |ident| {
4571 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {
4572 if (kv.value.cast(ast.Node.VarDecl)) |var_decl|
4573 return getContainer(c, var_decl.init_node.?);
4574 }
4575 } else if (node.cast(ast.Node.InfixOp)) |infix| {
4576 if (infix.op != .Period)
4577 return null;
4578 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
4579 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
4580 var it = container.fields_and_decls.iterator(0);
4581 while (it.next()) |field_ref| {
4582 const field = field_ref.*.cast(ast.Node.ContainerField).?;
4583 const ident = infix.rhs.cast(ast.Node.Identifier).?;
4584 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
4585 return getContainer(c, field.type_expr.?);
4586 }
4587 }
4588 }
4589 }
4590 }
4591 return null;
4592}
4593
4594fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
4595 if (ref.cast(ast.Node.Identifier)) |ident| {
4596 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {
4597 if (kv.value.cast(ast.Node.VarDecl)) |var_decl| {
4598 if (var_decl.type_node) |ty|
4599 return getContainer(c, ty);
4600 }
4601 }
4602 } else if (ref.cast(ast.Node.InfixOp)) |infix| {
4603 if (infix.op != .Period)
4604 return null;
4605 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
4606 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
4607 var it = container.fields_and_decls.iterator(0);
4608 while (it.next()) |field_ref| {
4609 const field = field_ref.*.cast(ast.Node.ContainerField).?;
4610 const ident = infix.rhs.cast(ast.Node.Identifier).?;
4611 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
4612 return getContainer(c, field.type_expr.?);
30644613 }
30654614 }
4615 } else
4616 return ty_node;
4617 }
4618 }
4619 return null;
4620}
4621
4622fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
4623 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;
4624 if (getContainerTypeOf(c, init)) |ty_node| {
4625 if (ty_node.cast(ast.Node.PrefixOp)) |prefix| {
4626 if (prefix.op == .OptionalType) {
4627 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
4628 return fn_proto;
4629 }
30664630 }
30674631 }
30684632 }
......@@ -3072,7 +4636,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {
30724636fn addMacros(c: *Context) !void {
30734637 var macro_it = c.global_scope.macro_table.iterator();
30744638 while (macro_it.next()) |kv| {
3075 if (getFnDecl(c, kv.value)) |proto_node| {
4639 if (getFnProto(c, kv.value)) |proto_node| {
30764640 // If a macro aliases a global variable which is a function pointer, we conclude that
30774641 // the macro is intended to represent a function that assumes the function pointer
30784642 // variable is non-null and calls it.
src/zig_clang.cpp+15
......@@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi
15711571 return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl);
15721572}
15731573
1574const ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self) {
1575 const clang::FunctionDecl *decl = reinterpret_cast<const clang::FunctionDecl*>(self)->getCanonicalDecl();
1576 return reinterpret_cast<const ZigClangFunctionDecl *>(decl);
1577}
1578
1579const ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self) {
1580 const clang::VarDecl *decl = reinterpret_cast<const clang::VarDecl*>(self)->getCanonicalDecl();
1581 return reinterpret_cast<const ZigClangVarDecl *>(decl);
1582}
1583
15741584const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) {
15751585 const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl);
15761586 const clang::RecordDecl *definition = record_decl->getDefinition();
......@@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D
21612171 return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM);
21622172}
21632173
2174double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self) {
2175 auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
2176 return casted->getValueAsApproximateDouble();
2177}
2178
21642179enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) {
21652180 auto casted = reinterpret_cast<const clang::StringLiteral *>(self);
21662181 return (ZigClangStringLiteral_StringKind)casted->getKind();
src/zig_clang.h+3
......@@ -856,6 +856,8 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc
856856ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl);
857857ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *);
858858ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *);
859ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self);
860ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self);
859861
860862ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *);
861863ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *);
......@@ -985,6 +987,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st
985987
986988ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,
987989 unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);
990ZIG_EXTERN_C double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self);
988991
989992ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self);
990993ZIG_EXTERN_C const char *ZigClangStringLiteral_getString_bytes_begin_size(const struct ZigClangStringLiteral *self,
test/translate_c.zig+2403-1321
......@@ -127,16 +127,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
127127 });
128128
129129 cases.addC_both("add, sub, mul, div, rem",
130 \\int s(int a, int b) {
131 \\ int c;
130 \\int s() {
131 \\ int a, b, c;
132132 \\ c = a + b;
133133 \\ c = a - b;
134134 \\ c = a * b;
135135 \\ c = a / b;
136136 \\ c = a % b;
137137 \\}
138 \\unsigned u(unsigned a, unsigned b) {
139 \\ unsigned c;
138 \\unsigned u() {
139 \\ unsigned a, b, c;
140140 \\ c = a + b;
141141 \\ c = a - b;
142142 \\ c = a * b;
......@@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
144144 \\ c = a % b;
145145 \\}
146146 , &[_][]const u8{
147 \\pub export fn s(a: c_int, b: c_int) c_int {
147 \\pub export fn s() c_int {
148 \\ var a: c_int = undefined;
149 \\ var b: c_int = undefined;
148150 \\ var c: c_int = undefined;
149151 \\ c = (a + b);
150152 \\ c = (a - b);
......@@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
152154 \\ c = @divTrunc(a, b);
153155 \\ c = @rem(a, b);
154156 \\}
155 \\pub export fn u(a: c_uint, b: c_uint) c_uint {
157 \\pub export fn u() c_uint {
158 \\ var a: c_uint = undefined;
159 \\ var b: c_uint = undefined;
156160 \\ var c: c_uint = undefined;
157161 \\ c = (a +% b);
158162 \\ c = (a -% b);
......@@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
162166 \\}
163167 });
164168
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
209169 cases.add_both("typedef of function in struct field",
210170 \\typedef void lws_callback_function(void);
211171 \\struct Foo {
......@@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
228188 \\ struct Foo *foo;
229189 \\};
230190 , &[_][]const u8{
231 \\pub const struct_Foo = @OpaqueType()
191 \\pub const struct_Foo = @OpaqueType();
232192 ,
233193 \\pub const struct_Bar = extern struct {
234194 \\ foo: ?*struct_Foo,
......@@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
426386 },
427387 );
428388
429 /////////////// Cases that pass for only stage2 ////////////////
430
431 cases.add_2("Parameterless function prototypes",
432 \\void a() {}
433 \\void b(void) {}
434 \\void c();
435 \\void d(void);
389 cases.addC_both("null statements",
390 \\void foo(void) {
391 \\ ;;;;;
392 \\}
436393 , &[_][]const u8{
437 \\pub export fn a() void {}
438 \\pub export fn b() void {}
439 \\pub extern fn c(...) void;
440 \\pub extern fn d() void;
394 \\pub export fn foo() void {
395 \\ {}
396 \\ {}
397 \\ {}
398 \\ {}
399 \\ {}
400 \\}
441401 });
442402
443 cases.add_2("variable declarations",
444 \\extern char arr0[] = "hello";
445 \\static char arr1[] = "hello";
446 \\char arr2[] = "hello";
447 , &[_][]const u8{
448 \\pub extern var arr0: [*c]u8 = "hello";
449 \\pub var arr1: [*c]u8 = "hello";
450 \\pub export var arr2: [*c]u8 = "hello";
451 });
403 if (builtin.os != builtin.Os.windows) {
404 // Windows treats this as an enum with type c_int
405 cases.add_both("big negative enum init values when C ABI supports long long enums",
406 \\enum EnumWithInits {
407 \\ VAL01 = 0,
408 \\ VAL02 = 1,
409 \\ VAL03 = 2,
410 \\ VAL04 = 3,
411 \\ VAL05 = -1,
412 \\ VAL06 = -2,
413 \\ VAL07 = -3,
414 \\ VAL08 = -4,
415 \\ VAL09 = VAL02 + VAL08,
416 \\ VAL10 = -1000012000,
417 \\ VAL11 = -1000161000,
418 \\ VAL12 = -1000174001,
419 \\ VAL13 = VAL09,
420 \\ VAL14 = VAL10,
421 \\ VAL15 = VAL11,
422 \\ VAL16 = VAL13,
423 \\ VAL17 = (VAL16 - VAL10 + 1),
424 \\ VAL18 = 0x1000000000000000L,
425 \\ VAL19 = VAL18 + VAL18 + VAL18 - 1,
426 \\ VAL20 = VAL19 + VAL19,
427 \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF,
428 \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1,
429 \\ VAL23 = 0xFFFFFFFFFFFFFFFF,
430 \\};
431 , &[_][]const u8{
432 \\pub const enum_EnumWithInits = extern enum(c_longlong) {
433 \\ VAL01 = 0,
434 \\ VAL02 = 1,
435 \\ VAL03 = 2,
436 \\ VAL04 = 3,
437 \\ VAL05 = -1,
438 \\ VAL06 = -2,
439 \\ VAL07 = -3,
440 \\ VAL08 = -4,
441 \\ VAL09 = -3,
442 \\ VAL10 = -1000012000,
443 \\ VAL11 = -1000161000,
444 \\ VAL12 = -1000174001,
445 \\ VAL13 = -3,
446 \\ VAL14 = -1000012000,
447 \\ VAL15 = -1000161000,
448 \\ VAL16 = -3,
449 \\ VAL17 = 1000011998,
450 \\ VAL18 = 1152921504606846976,
451 \\ VAL19 = 3458764513820540927,
452 \\ VAL20 = 6917529027641081854,
453 \\ VAL21 = 6917529027641081853,
454 \\ VAL22 = 0,
455 \\ VAL23 = -1,
456 \\};
457 });
458 }
452459
453 cases.add_2("array initializer expr",
454 \\static void foo(void){
455 \\ char arr[10] ={1};
456 \\ char *arr1[10] ={0};
460 cases.addC_both("predefined expressions",
461 \\void foo(void) {
462 \\ __func__;
463 \\ __FUNCTION__;
464 \\ __PRETTY_FUNCTION__;
457465 \\}
458466 , &[_][]const u8{
459 \\pub fn foo() void {
460 \\ var arr: [10]u8 = .{
461 \\ @as(u8, 1),
462 \\ } ++ .{0} ** 9;
463 \\ var arr1: [10][*c]u8 = .{
464 \\ null,
465 \\ } ++ .{null} ** 9;
467 \\pub export fn foo() void {
468 \\ _ = "foo";
469 \\ _ = "foo";
470 \\ _ = "void foo(void)";
466471 \\}
467472 });
468473
469 cases.add_2("enums",
470 \\typedef enum {
471 \\ a,
472 \\ b,
473 \\ c,
474 \\} d;
475 \\enum {
476 \\ e,
477 \\ f = 4,
478 \\ g,
479 \\} h = e;
480 \\struct Baz {
481 \\ enum {
482 \\ i,
483 \\ j,
484 \\ k,
485 \\ } l;
486 \\ d m;
487 \\};
488 \\enum i {
489 \\ n,
490 \\ o,
491 \\ p,
492 \\};
474 cases.addC_both("ignore result, no function arguments",
475 \\void foo() {
476 \\ int a;
477 \\ 1;
478 \\ "hey";
479 \\ 1 + 1;
480 \\ 1 - 1;
481 \\ a = 1;
482 \\}
493483 , &[_][]const u8{
494 \\pub const a = enum_unnamed_1.a;
495 \\pub const b = enum_unnamed_1.b;
496 \\pub const c = enum_unnamed_1.c;
497 \\pub const enum_unnamed_1 = extern enum {
498 \\ a,
499 \\ b,
500 \\ c,
501 \\};
502 \\pub const d = enum_unnamed_1;
503 \\pub const e = enum_unnamed_2.e;
504 \\pub const f = enum_unnamed_2.f;
505 \\pub const g = enum_unnamed_2.g;
506 \\pub const enum_unnamed_2 = extern enum {
507 \\ e = 0,
508 \\ f = 4,
509 \\ g = 5,
510 \\};
511 \\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e);
512 \\pub const i = enum_unnamed_3.i;
513 \\pub const j = enum_unnamed_3.j;
514 \\pub const k = enum_unnamed_3.k;
515 \\pub const enum_unnamed_3 = extern enum {
516 \\ i,
517 \\ j,
518 \\ k,
519 \\};
520 \\pub const struct_Baz = extern struct {
521 \\ l: enum_unnamed_3,
522 \\ m: d,
523 \\};
524 \\pub const n = enum_i.n;
525 \\pub const o = enum_i.o;
526 \\pub const p = enum_i.p;
527 \\pub const enum_i = extern enum {
528 \\ n,
529 \\ o,
530 \\ p,
531 \\};
532 ,
533 \\pub const Baz = struct_Baz;
484 \\pub export fn foo() void {
485 \\ var a: c_int = undefined;
486 \\ _ = 1;
487 \\ _ = "hey";
488 \\ _ = (1 + 1);
489 \\ _ = (1 - 1);
490 \\ a = 1;
491 \\}
534492 });
535493
536 cases.add_2("#define a char literal",
537 \\#define A_CHAR 'a'
494 cases.add_both("constant size array",
495 \\void func(int array[20]);
538496 , &[_][]const u8{
539 \\pub const A_CHAR = 'a';
497 \\pub extern fn func(array: [*c]c_int) void;
540498 });
541499
542 cases.add_2("comment after integer literal",
543 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
500 cases.add_both("__cdecl doesn't mess up function pointers",
501 \\void foo(void (__cdecl *fn_ptr)(void));
544502 , &[_][]const u8{
545 \\pub const SDL_INIT_VIDEO = 0x00000020;
503 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
546504 });
547505
548 cases.add_2("u integer suffix after hex literal",
549 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
506 cases.addC_both("void cast",
507 \\void foo() {
508 \\ int a;
509 \\ (void) a;
510 \\}
550511 , &[_][]const u8{
551 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
512 \\pub export fn foo() void {
513 \\ var a: c_int = undefined;
514 \\ _ = a;
515 \\}
552516 });
553517
554 cases.add_2("l integer suffix after hex literal",
555 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
518 cases.addC_both("implicit cast to void *",
519 \\void *foo() {
520 \\ unsigned short *x;
521 \\ return x;
522 \\}
556523 , &[_][]const u8{
557 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
524 \\pub export fn foo() ?*c_void {
525 \\ var x: [*c]c_ushort = undefined;
526 \\ return @ptrCast(?*c_void, x);
527 \\}
558528 });
559529
560 cases.add_2("ul integer suffix after hex literal",
561 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
530 cases.addC_both("null pointer implicit cast",
531 \\int* foo(void) {
532 \\ return 0;
533 \\}
562534 , &[_][]const u8{
563 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
535 \\pub export fn foo() [*c]c_int {
536 \\ return null;
537 \\}
564538 });
565539
566 cases.add_2("lu integer suffix after hex literal",
567 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
540 cases.add_both("simple union",
541 \\union Foo {
542 \\ int x;
543 \\ double y;
544 \\};
568545 , &[_][]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;
619 \\};
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 \\ },
546 \\pub const union_Foo = extern union {
547 \\ x: c_int,
548 \\ y: f64,
635549 \\};
636550 ,
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)
650 , &[_][]const u8{
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";
670 ,
671 \\pub const FOO2 = "aoeu\x07 derp";
551 \\pub const Foo = union_Foo;
672552 });
673553
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;
554 cases.addC_both("string literal",
555 \\const char *foo(void) {
556 \\ return "bar";
686557 \\}
687558 , &[_][]const u8{
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);
559 \\pub export fn foo() [*c]const u8 {
560 \\ return "bar";
699561 \\}
700562 });
701563
702 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
703
704 if (builtin.os != builtin.Os.windows) {
705 // Windows treats this as an enum with type c_int
706 cases.add("big negative enum init values when C ABI supports long long enums",
707 \\enum EnumWithInits {
708 \\ VAL01 = 0,
709 \\ VAL02 = 1,
710 \\ VAL03 = 2,
711 \\ VAL04 = 3,
712 \\ VAL05 = -1,
713 \\ VAL06 = -2,
714 \\ VAL07 = -3,
715 \\ VAL08 = -4,
716 \\ VAL09 = VAL02 + VAL08,
717 \\ VAL10 = -1000012000,
718 \\ VAL11 = -1000161000,
719 \\ VAL12 = -1000174001,
720 \\ VAL13 = VAL09,
721 \\ VAL14 = VAL10,
722 \\ VAL15 = VAL11,
723 \\ VAL16 = VAL13,
724 \\ VAL17 = (VAL16 - VAL10 + 1),
725 \\ VAL18 = 0x1000000000000000L,
726 \\ VAL19 = VAL18 + VAL18 + VAL18 - 1,
727 \\ VAL20 = VAL19 + VAL19,
728 \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF,
729 \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1,
730 \\ VAL23 = 0xFFFFFFFFFFFFFFFF,
731 \\};
732 , &[_][]const u8{
733 \\pub const enum_EnumWithInits = extern enum(c_longlong) {
734 \\ VAL01 = 0,
735 \\ VAL02 = 1,
736 \\ VAL03 = 2,
737 \\ VAL04 = 3,
738 \\ VAL05 = -1,
739 \\ VAL06 = -2,
740 \\ VAL07 = -3,
741 \\ VAL08 = -4,
742 \\ VAL09 = -3,
743 \\ VAL10 = -1000012000,
744 \\ VAL11 = -1000161000,
745 \\ VAL12 = -1000174001,
746 \\ VAL13 = -3,
747 \\ VAL14 = -1000012000,
748 \\ VAL15 = -1000161000,
749 \\ VAL16 = -3,
750 \\ VAL17 = 1000011998,
751 \\ VAL18 = 1152921504606846976,
752 \\ VAL19 = 3458764513820540927,
753 \\ VAL20 = 6917529027641081854,
754 \\ VAL21 = 6917529027641081853,
755 \\ VAL22 = 0,
756 \\ VAL23 = -1,
757 \\};
758 });
759 }
760
761 cases.add("predefined expressions",
564 cases.addC_both("return void",
762565 \\void foo(void) {
763 \\ __func__;
764 \\ __FUNCTION__;
765 \\ __PRETTY_FUNCTION__;
566 \\ return;
766567 \\}
767568 , &[_][]const u8{
768 \\pub fn foo() void {
769 \\ _ = "foo";
770 \\ _ = "foo";
771 \\ _ = "void foo(void)";
569 \\pub export fn foo() void {
570 \\ return;
772571 \\}
773572 });
774573
775 cases.add("ignore result, no function arguments",
776 \\void foo() {
777 \\ int a;
778 \\ 1;
779 \\ "hey";
780 \\ 1 + 1;
781 \\ 1 - 1;
782 \\ a = 1;
574 cases.addC_both("for loop",
575 \\void foo(void) {
576 \\ for (int i = 0; i; i = i + 1) { }
783577 \\}
784578 , &[_][]const u8{
785 \\pub fn foo() void {
786 \\ var a: c_int = undefined;
787 \\ _ = 1;
788 \\ _ = "hey";
789 \\ _ = (1 + 1);
790 \\ _ = (1 - 1);
791 \\ a = 1;
579 \\pub export fn foo() void {
580 \\ {
581 \\ var i: c_int = 0;
582 \\ while (i != 0) : (i = (i + 1)) {}
583 \\ }
792584 \\}
793585 });
794586
795 cases.add("for loop with var init but empty body",
587 cases.addC_both("empty for loop",
796588 \\void foo(void) {
797 \\ for (int x = 0; x < 10; x++);
589 \\ for (;;) { }
798590 \\}
799591 , &[_][]const u8{
800 \\pub fn foo() void {
801 \\ {
802 \\ var x: c_int = 0;
803 \\ while (x < 10) : (x += 1) {}
804 \\ }
592 \\pub export fn foo() void {
593 \\ while (true) {}
805594 \\}
806595 });
807596
808 cases.add("do while with empty body",
597 cases.addC_both("break statement",
809598 \\void foo(void) {
810 \\ do ; while (1);
599 \\ for (;;) {
600 \\ break;
601 \\ }
811602 \\}
812 , &[_][]const u8{ // TODO this should be if (1 != 0) break
813 \\pub fn foo() void {
603 , &[_][]const u8{
604 \\pub export fn foo() void {
814605 \\ while (true) {
815 \\ {}
816 \\ if (!1) break;
606 \\ break;
817607 \\ }
818608 \\}
819609 });
820610
821 cases.add("for with empty body",
611 cases.addC_both("continue statement",
822612 \\void foo(void) {
823 \\ for (;;);
613 \\ for (;;) {
614 \\ continue;
615 \\ }
824616 \\}
825617 , &[_][]const u8{
826 \\pub fn foo() void {
827 \\ while (true) {}
618 \\pub export fn foo() void {
619 \\ while (true) {
620 \\ continue;
621 \\ }
828622 \\}
829623 });
830624
831 cases.add("while with empty body",
832 \\void foo(void) {
833 \\ while (1);
625 cases.addC_both("pointer casting",
626 \\float *ptrcast() {
627 \\ int *a;
628 \\ return (float *)a;
834629 \\}
835630 , &[_][]const u8{
836 \\pub fn foo() void {
837 \\ while (1 != 0) {}
631 \\pub export fn ptrcast() [*c]f32 {
632 \\ var a: [*c]c_int = undefined;
633 \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
838634 \\}
839635 });
840636
841 cases.addAllowWarnings("simple data types",
842 \\#include <stdint.h>
843 \\int foo(char a, unsigned char b, signed char c);
844 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
845 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
846 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
847 , &[_][]const u8{
848 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
849 ,
850 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
851 ,
852 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
853 });
854
855 cases.addC("simple function",
856 \\int abs(int a) {
857 \\ return a < 0 ? -a : a;
637 cases.addC_both("pointer conversion with different alignment",
638 \\void test_ptr_cast() {
639 \\ void *p;
640 \\ {
641 \\ char *to_char = (char *)p;
642 \\ short *to_short = (short *)p;
643 \\ int *to_int = (int *)p;
644 \\ long long *to_longlong = (long long *)p;
645 \\ }
646 \\ {
647 \\ char *to_char = p;
648 \\ short *to_short = p;
649 \\ int *to_int = p;
650 \\ long long *to_longlong = p;
651 \\ }
858652 \\}
859653 , &[_][]const u8{
860 \\export fn abs(a: c_int) c_int {
861 \\ return if (a < 0) -a else a;
654 \\pub export fn test_ptr_cast() void {
655 \\ var p: ?*c_void = undefined;
656 \\ {
657 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
658 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
659 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
660 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
661 \\ }
662 \\ {
663 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
664 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
665 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
666 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
667 \\ }
862668 \\}
863669 });
864670
865 cases.add("restrict -> noalias",
866 \\void foo(void *restrict bar, void *restrict);
867 , &[_][]const u8{
868 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
869 });
870
871 cases.add("qualified struct and enum",
872 \\struct Foo {
873 \\ int x;
874 \\ int y;
875 \\};
876 \\enum Bar {
877 \\ BarA,
878 \\ BarB,
879 \\};
880 \\void func(struct Foo *a, enum Bar **b);
881 , &[_][]const u8{
882 \\pub const struct_Foo = extern struct {
883 \\ x: c_int,
884 \\ y: c_int,
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;
901 });
902
903 cases.add("constant size array",
904 \\void func(int array[20]);
905 , &[_][]const u8{
906 \\pub extern fn func(array: [*c]c_int) void;
907 });
908
909 cases.add("__cdecl doesn't mess up function pointers",
910 \\void foo(void (__cdecl *fn_ptr)(void));
911 , &[_][]const u8{
912 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
913 });
914
915 cases.add("macro defines string literal with hex",
916 \\#define FOO "aoeu\xab derp"
917 \\#define FOO2 "aoeu\x0007a derp"
918 \\#define FOO_CHAR '\xfF'
919 , &[_][]const u8{
920 \\pub const FOO = "aoeu\xab derp";
921 ,
922 \\pub const FOO2 = "aoeuz derp";
923 ,
924 \\pub const FOO_CHAR = 255;
925 });
926
927 cases.add("macro defines string literal with octal",
928 \\#define FOO "aoeu\023 derp"
929 \\#define FOO2 "aoeu\0234 derp"
930 \\#define FOO_CHAR '\077'
671 cases.addC_both("while on non-bool",
672 \\int while_none_bool() {
673 \\ int a;
674 \\ float b;
675 \\ void *c;
676 \\ while (a) return 0;
677 \\ while (b) return 1;
678 \\ while (c) return 2;
679 \\ return 3;
680 \\}
931681 , &[_][]const u8{
932 \\pub const FOO = "aoeu\x13 derp";
933 ,
934 \\pub const FOO2 = "aoeu\x134 derp";
935 ,
936 \\pub const FOO_CHAR = 63;
682 \\pub export fn while_none_bool() c_int {
683 \\ var a: c_int = undefined;
684 \\ var b: f32 = undefined;
685 \\ var c: ?*c_void = undefined;
686 \\ while (a != 0) return 0;
687 \\ while (b != 0) return 1;
688 \\ while (c != null) return 2;
689 \\ return 3;
690 \\}
937691 });
938692
939 cases.addC("post increment",
940 \\unsigned foo1(unsigned a) {
941 \\ a++;
942 \\ return a;
943 \\}
944 \\int foo2(int a) {
945 \\ a++;
946 \\ return a;
693 cases.addC_both("for on non-bool",
694 \\int for_none_bool() {
695 \\ int a;
696 \\ float b;
697 \\ void *c;
698 \\ for (;a;) return 0;
699 \\ for (;b;) return 1;
700 \\ for (;c;) return 2;
701 \\ return 3;
947702 \\}
948703 , &[_][]const u8{
949 \\pub export fn foo1(_arg_a: c_uint) c_uint {
950 \\ var a = _arg_a;
951 \\ a +%= 1;
952 \\ return a;
953 \\}
954 \\pub export fn foo2(_arg_a: c_int) c_int {
955 \\ var a = _arg_a;
956 \\ a += 1;
957 \\ return a;
704 \\pub export fn for_none_bool() c_int {
705 \\ var a: c_int = undefined;
706 \\ var b: f32 = undefined;
707 \\ var c: ?*c_void = undefined;
708 \\ while (a != 0) return 0;
709 \\ while (b != 0) return 1;
710 \\ while (c != null) return 2;
711 \\ return 3;
958712 \\}
959713 });
960714
961 cases.addC("shift right assign",
962 \\int log2(unsigned a) {
963 \\ int i = 0;
964 \\ while (a > 0) {
965 \\ a >>= 1;
966 \\ }
967 \\ return i;
715 cases.addC_both("bitshift",
716 \\int foo(void) {
717 \\ return (1 << 2) >> 1;
968718 \\}
969719 , &[_][]const u8{
970 \\pub export fn log2(_arg_a: c_uint) c_int {
971 \\ var a = _arg_a;
972 \\ var i: c_int = 0;
973 \\ while (a > @as(c_uint, 0)) {
974 \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1);
975 \\ }
976 \\ return i;
720 \\pub export fn foo() c_int {
721 \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
977722 \\}
978723 });
979724
980 cases.addC("if statement",
981 \\int max(int a, int b) {
982 \\ if (a < b)
983 \\ return b;
984 \\
985 \\ if (a < b)
986 \\ return b;
987 \\ else
988 \\ return a;
989 \\
990 \\ if (a < b) ; else ;
725 cases.addC_both("sizeof",
726 \\#include <stddef.h>
727 \\size_t size_of(void) {
728 \\ return sizeof(int);
991729 \\}
992730 , &[_][]const u8{
993 \\pub export fn max(a: c_int, b: c_int) c_int {
994 \\ if (a < b) return b;
995 \\ if (a < b) return b else return a;
996 \\ if (a < b) {} else {}
731 \\pub export fn size_of() usize {
732 \\ return @sizeOf(c_int);
997733 \\}
998734 });
999735
1000 cases.addC("==, !=",
1001 \\int max(int a, int b) {
1002 \\ if (a == b)
1003 \\ return a;
1004 \\ if (a != b)
1005 \\ return b;
1006 \\ return a;
736 cases.addC_both("normal deref",
737 \\void foo() {
738 \\ int *x;
739 \\ *x = 1;
1007740 \\}
1008741 , &[_][]const u8{
1009 \\pub export fn max(a: c_int, b: c_int) c_int {
1010 \\ if (a == b) return a;
1011 \\ if (a != b) return b;
1012 \\ return a;
742 \\pub export fn foo() void {
743 \\ var x: [*c]c_int = undefined;
744 \\ x.?.* = 1;
1013745 \\}
1014746 });
1015747
1016 cases.addC("bitwise binary operators",
1017 \\int max(int a, int b) {
1018 \\ return (a & b) ^ (a | b);
748 cases.addC_both("address of operator",
749 \\int foo(void) {
750 \\ int x = 1234;
751 \\ int *ptr = &x;
752 \\ return *ptr;
1019753 \\}
1020754 , &[_][]const u8{
1021 \\pub export fn max(a: c_int, b: c_int) c_int {
1022 \\ return (a & b) ^ (a | b);
755 \\pub export fn foo() c_int {
756 \\ var x: c_int = 1234;
757 \\ var ptr: [*c]c_int = &x;
758 \\ return ptr.?.*;
1023759 \\}
1024760 });
1025761
1026 cases.addC("logical and, logical or",
1027 \\int max(int a, int b) {
1028 \\ if (a < b || a == b)
1029 \\ return b;
1030 \\ if (a >= b && a == b)
1031 \\ return a;
1032 \\ return a;
762 cases.addC_both("bin not",
763 \\int foo() {
764 \\ int x;
765 \\ return ~x;
1033766 \\}
1034767 , &[_][]const u8{
1035 \\pub export fn max(a: c_int, b: c_int) c_int {
1036 \\ if ((a < b) or (a == b)) return b;
1037 \\ if ((a >= b) and (a == b)) return a;
1038 \\ return a;
768 \\pub export fn foo() c_int {
769 \\ var x: c_int = undefined;
770 \\ return ~x;
1039771 \\}
1040772 });
1041773
1042 cases.addC("logical and, logical or on none bool values",
1043 \\int and_or_none_bool(int a, float b, void *c) {
1044 \\ if (a && b) return 0;
1045 \\ if (b && c) return 1;
1046 \\ if (a && c) return 2;
1047 \\ if (a || b) return 3;
1048 \\ if (b || c) return 4;
1049 \\ if (a || c) return 5;
1050 \\ return 6;
774 cases.addC_both("bool not",
775 \\int foo() {
776 \\ int a;
777 \\ float b;
778 \\ void *c;
779 \\ return !(a == 0);
780 \\ return !a;
781 \\ return !b;
782 \\ return !c;
1051783 \\}
1052784 , &[_][]const u8{
1053 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1054 \\ if ((a != 0) and (b != 0)) return 0;
1055 \\ if ((b != 0) and (c != null)) return 1;
1056 \\ if ((a != 0) and (c != null)) return 2;
1057 \\ if ((a != 0) or (b != 0)) return 3;
1058 \\ if ((b != 0) or (c != null)) return 4;
1059 \\ if ((a != 0) or (c != null)) return 5;
1060 \\ return 6;
785 \\pub export fn foo() c_int {
786 \\ var a: c_int = undefined;
787 \\ var b: f32 = undefined;
788 \\ var c: ?*c_void = undefined;
789 \\ return !(a == 0);
790 \\ return !(a != 0);
791 \\ return !(b != 0);
792 \\ return !(c != null);
1061793 \\}
1062794 });
1063795
1064 cases.addC("assign",
1065 \\int max(int a) {
1066 \\ int tmp;
1067 \\ tmp = a;
1068 \\ a = tmp;
796 cases.addC("__extension__ cast",
797 \\int foo(void) {
798 \\ return __extension__ 1;
1069799 \\}
1070800 , &[_][]const u8{
1071 \\pub export fn max(_arg_a: c_int) c_int {
1072 \\ var a = _arg_a;
1073 \\ var tmp: c_int = undefined;
1074 \\ tmp = a;
1075 \\ a = tmp;
801 \\pub export fn foo() c_int {
802 \\ return 1;
1076803 \\}
1077804 });
1078805
1079 cases.addC("chaining assign",
1080 \\void max(int a) {
1081 \\ int b, c;
1082 \\ c = b = a;
1083 \\}
1084 , &[_][]const u8{
1085 \\pub export fn max(a: c_int) void {
1086 \\ var b: c_int = undefined;
1087 \\ var c: c_int = undefined;
1088 \\ c = (x: {
1089 \\ const _tmp = a;
1090 \\ b = _tmp;
1091 \\ break :x _tmp;
1092 \\ });
1093 \\}
1094 });
806 if (builtin.os != builtin.Os.windows) {
807 // sysv_abi not currently supported on windows
808 cases.add_both("Macro qualified functions",
809 \\void __attribute__((sysv_abi)) foo(void);
810 , &[_][]const u8{
811 \\pub extern fn foo() void;
812 });
813 }
1095814
1096 cases.addC("shift right assign with a fixed size type",
1097 \\#include <stdint.h>
1098 \\int log2(uint32_t a) {
1099 \\ int i = 0;
1100 \\ while (a > 0) {
1101 \\ a >>= 1;
1102 \\ }
1103 \\ return i;
1104 \\}
815 /////////////// Cases that pass for only stage2 ////////////////
816
817 cases.add_2("Parameterless function prototypes",
818 \\void a() {}
819 \\void b(void) {}
820 \\void c();
821 \\void d(void);
1105822 , &[_][]const u8{
1106 \\pub export fn log2(_arg_a: u32) c_int {
1107 \\ var a = _arg_a;
1108 \\ var i: c_int = 0;
1109 \\ while (a > @as(c_uint, 0)) {
1110 \\ a >>= @as(u5, 1);
1111 \\ }
1112 \\ return i;
1113 \\}
823 \\pub export fn a() void {}
824 \\pub export fn b() void {}
825 \\pub extern fn c(...) void;
826 \\pub extern fn d() void;
1114827 });
1115828
1116 cases.add("anonymous enum",
1117 \\enum {
1118 \\ One,
1119 \\ Two,
1120 \\};
829 cases.add_2("variable declarations",
830 \\extern char arr0[] = "hello";
831 \\static char arr1[] = "hello";
832 \\char arr2[] = "hello";
1121833 , &[_][]const u8{
1122 \\pub const One = 0;
1123 \\pub const Two = 1;
834 \\pub extern var arr0: [*c]u8 = "hello";
835 \\pub var arr1: [*c]u8 = "hello";
836 \\pub export var arr2: [*c]u8 = "hello";
1124837 });
1125838
1126 cases.addC("function call",
1127 \\static void bar(void) { }
1128 \\static int baz(void) { return 0; }
1129 \\void foo(void) {
1130 \\ bar();
1131 \\ baz();
839 cases.add_2("array initializer expr",
840 \\static void foo(void){
841 \\ char arr[10] ={1};
842 \\ char *arr1[10] ={0};
1132843 \\}
1133844 , &[_][]const u8{
1134 \\pub fn bar() void {}
1135 \\pub fn baz() c_int {
1136 \\ return 0;
1137 \\}
1138 \\pub export fn foo() void {
1139 \\ bar();
1140 \\ _ = baz();
845 \\pub fn foo() void {
846 \\ var arr: [10]u8 = .{
847 \\ @as(u8, 1),
848 \\ } ++ .{0} ** 9;
849 \\ var arr1: [10][*c]u8 = .{
850 \\ null,
851 \\ } ++ .{null} ** 9;
1141852 \\}
1142853 });
1143854
1144 cases.addC("field access expression",
1145 \\struct Foo {
1146 \\ int field;
855 cases.add_2("enums",
856 \\typedef enum {
857 \\ a,
858 \\ b,
859 \\ c,
860 \\} d;
861 \\enum {
862 \\ e,
863 \\ f = 4,
864 \\ g,
865 \\} h = e;
866 \\struct Baz {
867 \\ enum {
868 \\ i,
869 \\ j,
870 \\ k,
871 \\ } l;
872 \\ d m;
873 \\};
874 \\enum i {
875 \\ n,
876 \\ o,
877 \\ p,
1147878 \\};
1148 \\int read_field(struct Foo *foo) {
1149 \\ return foo->field;
1150 \\}
1151879 , &[_][]const u8{
1152 \\pub const struct_Foo = extern struct {
1153 \\ field: c_int,
880 \\pub const a = 0;
881 \\pub const b = 1;
882 \\pub const c = 2;
883 \\const enum_unnamed_1 = extern enum {
884 \\ a,
885 \\ b,
886 \\ c,
1154887 \\};
1155 \\pub export fn read_field(foo: [*c]struct_Foo) c_int {
1156 \\ return foo.*.field;
1157 \\}
888 \\pub const d = enum_unnamed_1;
889 \\pub const e = 0;
890 \\pub const f = 4;
891 \\pub const g = 5;
892 \\const enum_unnamed_2 = extern enum {
893 \\ e = 0,
894 \\ f = 4,
895 \\ g = 5,
896 \\};
897 \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
898 \\pub const i = 0;
899 \\pub const j = 1;
900 \\pub const k = 2;
901 \\const enum_unnamed_3 = extern enum {
902 \\ i,
903 \\ j,
904 \\ k,
905 \\};
906 \\pub const struct_Baz = extern struct {
907 \\ l: enum_unnamed_3,
908 \\ m: d,
909 \\};
910 \\pub const n = 0;
911 \\pub const o = 1;
912 \\pub const p = 2;
913 \\pub const enum_i = extern enum {
914 \\ n,
915 \\ o,
916 \\ p,
917 \\};
918 ,
919 \\pub const Baz = struct_Baz;
1158920 });
1159921
1160 cases.addC("null statements",
1161 \\void foo(void) {
1162 \\ ;;;;;
1163 \\}
922 cases.add_2("#define a char literal",
923 \\#define A_CHAR 'a'
1164924 , &[_][]const u8{
1165 \\pub export fn foo() void {
1166 \\ {}
1167 \\ {}
1168 \\ {}
1169 \\ {}
1170 \\ {}
1171 \\}
925 \\pub const A_CHAR = 'a';
1172926 });
1173927
1174 cases.add("undefined array global",
1175 \\int array[100];
928 cases.add_2("comment after integer literal",
929 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1176930 , &[_][]const u8{
1177 \\pub var array: [100]c_int = undefined;
931 \\pub const SDL_INIT_VIDEO = 0x00000020;
1178932 });
1179933
1180 cases.addC("array access",
1181 \\int array[100];
1182 \\int foo(int index) {
1183 \\ return array[index];
1184 \\}
934 cases.add_2("u integer suffix after hex literal",
935 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1185936 , &[_][]const u8{
1186 \\pub var array: [100]c_int = undefined;
1187 \\pub export fn foo(index: c_int) c_int {
1188 \\ return array[index];
1189 \\}
937 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
1190938 });
1191939
1192 cases.addC("c style cast",
1193 \\int float_to_int(float a) {
1194 \\ return (int)a;
1195 \\}
940 cases.add_2("l integer suffix after hex literal",
941 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1196942 , &[_][]const u8{
1197 \\pub export fn float_to_int(a: f32) c_int {
1198 \\ return @as(c_int, a);
1199 \\}
943 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
1200944 });
1201945
1202 cases.addC("void cast",
1203 \\void foo(int a) {
1204 \\ (void) a;
1205 \\}
946 cases.add_2("ul integer suffix after hex literal",
947 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1206948 , &[_][]const u8{
1207 \\pub export fn foo(a: c_int) void {
1208 \\ _ = a;
1209 \\}
949 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1210950 });
1211951
1212 cases.addC("implicit cast to void *",
1213 \\void *foo(unsigned short *x) {
1214 \\ return x;
1215 \\}
952 cases.add_2("lu integer suffix after hex literal",
953 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1216954 , &[_][]const u8{
1217 \\pub export fn foo(x: [*c]c_ushort) ?*c_void {
1218 \\ return @ptrCast(?*c_void, x);
1219 \\}
955 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1220956 });
1221957
1222 cases.addC("sizeof",
1223 \\#include <stddef.h>
1224 \\size_t size_of(void) {
1225 \\ return sizeof(int);
1226 \\}
958 cases.add_2("ll integer suffix after hex literal",
959 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1227960 , &[_][]const u8{
1228 \\pub export fn size_of() usize {
1229 \\ return @sizeOf(c_int);
1230 \\}
961 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020);
1231962 });
1232963
1233 cases.addC("null pointer implicit cast",
1234 \\int* foo(void) {
1235 \\ return 0;
1236 \\}
964 cases.add_2("ull integer suffix after hex literal",
965 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1237966 , &[_][]const u8{
1238 \\pub export fn foo() [*c]c_int {
1239 \\ return null;
1240 \\}
967 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1241968 });
1242969
1243 cases.addC("comma operator",
1244 \\int foo(void) {
1245 \\ return 1, 2;
1246 \\}
970 cases.add_2("llu integer suffix after hex literal",
971 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1247972 , &[_][]const u8{
1248 \\pub export fn foo() c_int {
1249 \\ return x: {
1250 \\ _ = 1;
1251 \\ break :x 2;
1252 \\ };
1253 \\}
973 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1254974 });
1255975
1256 cases.addC("statement expression",
1257 \\int foo(void) {
1258 \\ return ({
1259 \\ int a = 1;
1260 \\ a;
1261 \\ });
1262 \\}
976 cases.add_2("generate inline func for #define global extern fn",
977 \\extern void (*fn_ptr)(void);
978 \\#define foo fn_ptr
979 \\
980 \\extern char (*fn_ptr2)(int, float);
981 \\#define bar fn_ptr2
1263982 , &[_][]const u8{
1264 \\pub export fn foo() c_int {
1265 \\ return x: {
1266 \\ var a: c_int = 1;
1267 \\ break :x a;
1268 \\ };
983 \\pub extern var fn_ptr: ?extern fn () void;
984 ,
985 \\pub inline fn foo() void {
986 \\ return fn_ptr.?();
1269987 \\}
1270 });
1271
1272 cases.addC("__extension__ cast",
1273 \\int foo(void) {
1274 \\ return __extension__ 1;
988 ,
989 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
990 ,
991 \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 {
992 \\ return fn_ptr2.?(arg_1, arg_2);
993 \\}
994 });
995
996 cases.add_2("macros with field targets",
997 \\typedef unsigned int GLbitfield;
998 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
999 \\typedef void(*OpenGLProc)(void);
1000 \\union OpenGLProcs {
1001 \\ OpenGLProc ptr[1];
1002 \\ struct {
1003 \\ PFNGLCLEARPROC Clear;
1004 \\ } gl;
1005 \\};
1006 \\extern union OpenGLProcs glProcs;
1007 \\#define glClearUnion glProcs.gl.Clear
1008 \\#define glClearPFN PFNGLCLEARPROC
1009 , &[_][]const u8{
1010 \\pub const GLbitfield = c_uint;
1011 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
1012 \\pub const OpenGLProc = ?extern fn () void;
1013 \\const struct_unnamed_1 = extern struct {
1014 \\ Clear: PFNGLCLEARPROC,
1015 \\};
1016 \\pub const union_OpenGLProcs = extern union {
1017 \\ ptr: [1]OpenGLProc,
1018 \\ gl: struct_unnamed_1,
1019 \\};
1020 \\pub extern var glProcs: union_OpenGLProcs;
1021 ,
1022 \\pub const glClearPFN = PFNGLCLEARPROC;
1023 ,
1024 \\pub inline fn glClearUnion(arg_2: GLbitfield) void {
1025 \\ return glProcs.gl.Clear.?(arg_2);
1026 \\}
1027 ,
1028 \\pub const OpenGLProcs = union_OpenGLProcs;
1029 });
1030
1031 cases.add_2("macro pointer cast",
1032 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1033 , &[_][]const u8{
1034 \\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);
1035 });
1036
1037 cases.add_2("basic macro function",
1038 \\extern int c;
1039 \\#define BASIC(c) (c*2)
1040 , &[_][]const u8{
1041 \\pub extern var c: c_int;
1042 ,
1043 \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) {
1044 \\ return c_1 * 2;
1045 \\}
1046 });
1047
1048 cases.add_2("macro defines string literal with hex",
1049 \\#define FOO "aoeu\xab derp"
1050 \\#define FOO2 "aoeu\x0007a derp"
1051 \\#define FOO_CHAR '\xfF'
1052 , &[_][]const u8{
1053 \\pub const FOO = "aoeu\xab derp";
1054 ,
1055 \\pub const FOO2 = "aoeu\x7a derp";
1056 ,
1057 \\pub const FOO_CHAR = '\xff';
1058 });
1059
1060 cases.add_2("variable aliasing",
1061 \\static long a = 2;
1062 \\static long b = 2;
1063 \\static int c = 4;
1064 \\void foo(char c) {
1065 \\ int a;
1066 \\ char b = 123;
1067 \\ b = (char) a;
1068 \\ {
1069 \\ int d = 5;
1070 \\ }
1071 \\ unsigned d = 440;
1072 \\}
1073 , &[_][]const u8{
1074 \\pub var a: c_long = @as(c_long, 2);
1075 \\pub var b: c_long = @as(c_long, 2);
1076 \\pub var c: c_int = 4;
1077 \\pub export fn foo(_arg_c_1: u8) void {
1078 \\ var c_1 = _arg_c_1;
1079 \\ var a_2: c_int = undefined;
1080 \\ var b_3: u8 = @as(u8, 123);
1081 \\ b_3 = @as(u8, a_2);
1082 \\ {
1083 \\ var d: c_int = 5;
1084 \\ }
1085 \\ var d: c_uint = @as(c_uint, 440);
1086 \\}
1087 });
1088
1089 cases.add_2("comma operator",
1090 \\int foo(char c) {
1091 \\ 2, 4;
1092 \\ return 2, 4, 6;
1093 \\}
1094 , &[_][]const u8{
1095 \\pub export fn foo(_arg_c: u8) c_int {
1096 \\ var c = _arg_c;
1097 \\ _ = 2;
1098 \\ _ = 4;
1099 \\ _ = 2;
1100 \\ _ = 4;
1101 \\ return 6;
1102 \\}
1103 });
1104
1105 cases.add_2("wors-case assign",
1106 \\int foo(char c) {
1107 \\ int a;
1108 \\ int b;
1109 \\ a = b = 2;
1110 \\}
1111 , &[_][]const u8{
1112 \\pub export fn foo(_arg_c: u8) c_int {
1113 \\ var c = _arg_c;
1114 \\ var a: c_int = undefined;
1115 \\ var b: c_int = undefined;
1116 \\ a = blk: {
1117 \\ const _tmp_1 = 2;
1118 \\ b = _tmp_1;
1119 \\ break :blk _tmp_1;
1120 \\ };
1121 \\}
1122 });
1123
1124 cases.add_2("if statements",
1125 \\int foo(char c) {
1126 \\ if (2) {
1127 \\ int a = 2;
1128 \\ }
1129 \\ if (2, 5) {
1130 \\ int a = 2;
1131 \\ }
1132 \\}
1133 , &[_][]const u8{
1134 \\pub export fn foo(_arg_c: u8) c_int {
1135 \\ var c = _arg_c;
1136 \\ if (2 != 0) {
1137 \\ var a: c_int = 2;
1138 \\ }
1139 \\ if ((blk: {
1140 \\ _ = 2;
1141 \\ break :blk 5;
1142 \\ }) != 0) {
1143 \\ var a: c_int = 2;
1144 \\ }
1145 \\}
1146 });
1147
1148 cases.add_2("while loops",
1149 \\int foo() {
1150 \\ int a = 5;
1151 \\ while (2)
1152 \\ a = 2;
1153 \\ while (4) {
1154 \\ int a = 4;
1155 \\ a = 9;
1156 \\ return 6, a;
1157 \\ }
1158 \\ do {
1159 \\ int a = 2;
1160 \\ a = 12;
1161 \\ } while (4);
1162 \\ do
1163 \\ a = 7;
1164 \\ while (4);
12751165 \\}
12761166 , &[_][]const u8{
12771167 \\pub export fn foo() c_int {
1278 \\ return 1;
1168 \\ var a: c_int = 5;
1169 \\ while (2 != 0) a = 2;
1170 \\ while (4 != 0) {
1171 \\ var a: c_int = 4;
1172 \\ a = 9;
1173 \\ _ = 6;
1174 \\ return a;
1175 \\ }
1176 \\ while (true) {
1177 \\ var a: c_int = 2;
1178 \\ a = 12;
1179 \\ if (!(4 != 0)) break;
1180 \\ }
1181 \\ while (true) {
1182 \\ a = 7;
1183 \\ if (!(4 != 0)) break;
1184 \\ }
12791185 \\}
12801186 });
12811187
1282 cases.addC("bitshift",
1283 \\int foo(void) {
1284 \\ return (1 << 2) >> 1;
1188 cases.add_2("for loops",
1189 \\int foo() {
1190 \\ for (int i = 2, b = 4; i + 2; i = 2) {
1191 \\ int a = 2;
1192 \\ a = 6, 5, 7;
1193 \\ }
1194 \\ char i = 2;
12851195 \\}
12861196 , &[_][]const u8{
12871197 \\pub export fn foo() c_int {
1288 \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
1198 \\ {
1199 \\ var i: c_int = 2;
1200 \\ var b: c_int = 4;
1201 \\ while ((i + 2) != 0) : (i = 2) {
1202 \\ var a: c_int = 2;
1203 \\ a = 6;
1204 \\ _ = 5;
1205 \\ _ = 7;
1206 \\ }
1207 \\ }
1208 \\ var i: u8 = @as(u8, 2);
12891209 \\}
12901210 });
12911211
1292 cases.addC("compound assignment operators",
1293 \\void foo(void) {
1294 \\ int a = 0;
1295 \\ a += (a += 1);
1296 \\ a -= (a -= 1);
1297 \\ a *= (a *= 1);
1298 \\ a &= (a &= 1);
1299 \\ a |= (a |= 1);
1300 \\ a ^= (a ^= 1);
1301 \\ a >>= (a >>= 1);
1302 \\ a <<= (a <<= 1);
1212 cases.add_2("shadowing primitive types",
1213 \\unsigned anyerror = 2;
1214 , &[_][]const u8{
1215 \\pub export var _anyerror: c_uint = @as(c_uint, 2);
1216 });
1217
1218 cases.add_2("floats",
1219 \\float a = 3.1415;
1220 \\double b = 3.1415;
1221 \\int c = 3.1415;
1222 \\double d = 3;
1223 , &[_][]const u8{
1224 \\pub export var a: f32 = @floatCast(f32, 3.1415);
1225 \\pub export var b: f64 = 3.1415;
1226 \\pub export var c: c_int = @floatToInt(c_int, 3.1415);
1227 \\pub export var d: f64 = @intToFloat(f64, 3);
1228 });
1229
1230 cases.add_2("conditional operator",
1231 \\int bar(void) {
1232 \\ if (2 ? 5 : 5 ? 4 : 6) 2;
1233 \\ return 2 ? 5 : 5 ? 4 : 6;
13031234 \\}
13041235 , &[_][]const u8{
1305 \\pub export fn foo() void {
1306 \\ var a: c_int = 0;
1307 \\ a += (x: {
1308 \\ const _ref = &a;
1309 \\ _ref.* = (_ref.* + 1);
1310 \\ break :x _ref.*;
1311 \\ });
1312 \\ a -= (x: {
1313 \\ const _ref = &a;
1314 \\ _ref.* = (_ref.* - 1);
1315 \\ break :x _ref.*;
1316 \\ });
1317 \\ a *= (x: {
1318 \\ const _ref = &a;
1319 \\ _ref.* = (_ref.* * 1);
1320 \\ break :x _ref.*;
1321 \\ });
1322 \\ a &= (x: {
1323 \\ const _ref = &a;
1324 \\ _ref.* = (_ref.* & 1);
1325 \\ break :x _ref.*;
1326 \\ });
1327 \\ a |= (x: {
1328 \\ const _ref = &a;
1329 \\ _ref.* = (_ref.* | 1);
1330 \\ break :x _ref.*;
1331 \\ });
1332 \\ a ^= (x: {
1333 \\ const _ref = &a;
1334 \\ _ref.* = (_ref.* ^ 1);
1335 \\ break :x _ref.*;
1336 \\ });
1337 \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: {
1338 \\ const _ref = &a;
1339 \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
1340 \\ break :x _ref.*;
1341 \\ }));
1342 \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: {
1343 \\ const _ref = &a;
1344 \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
1345 \\ break :x _ref.*;
1346 \\ }));
1236 \\pub export fn bar() c_int {
1237 \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2;
1238 \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6;
1239 \\}
1240 });
1241
1242 cases.add_2("switch on int",
1243 \\int switch_fn(int i) {
1244 \\ int res = 0;
1245 \\ switch (i) {
1246 \\ case 0:
1247 \\ res = 1;
1248 \\ case 1 ... 3:
1249 \\ res = 2;
1250 \\ default:
1251 \\ res = 3 * i;
1252 \\ break;
1253 \\ case 4:
1254 \\ res = 5;
1255 \\ }
1256 \\}
1257 , &[_][]const u8{
1258 \\pub export fn switch_fn(_arg_i: c_int) c_int {
1259 \\ var i = _arg_i;
1260 \\ var res: c_int = 0;
1261 \\ __switch: {
1262 \\ __case_2: {
1263 \\ __default: {
1264 \\ __case_1: {
1265 \\ __case_0: {
1266 \\ switch (i) {
1267 \\ 0 => break :__case_0,
1268 \\ 1...3 => break :__case_1,
1269 \\ else => break :__default,
1270 \\ 4 => break :__case_2,
1271 \\ }
1272 \\ }
1273 \\ res = 1;
1274 \\ }
1275 \\ res = 2;
1276 \\ }
1277 \\ res = (3 * i);
1278 \\ break :__switch;
1279 \\ }
1280 \\ res = 5;
1281 \\ }
1282 \\}
1283 });
1284
1285 cases.add_2("type referenced struct",
1286 \\struct Foo {
1287 \\ struct Bar{
1288 \\ int b;
1289 \\ };
1290 \\ struct Bar c;
1291 \\};
1292 , &[_][]const u8{
1293 \\pub const struct_Bar = extern struct {
1294 \\ b: c_int,
1295 \\};
1296 \\pub const struct_Foo = extern struct {
1297 \\ c: struct_Bar,
1298 \\};
1299 });
1300
1301 cases.add_2("undefined array global",
1302 \\int array[100] = {};
1303 , &[_][]const u8{
1304 \\pub export var array: [100]c_int = .{0} ** 100;
1305 });
1306
1307 cases.add_2("restrict -> noalias",
1308 \\void foo(void *restrict bar, void *restrict);
1309 , &[_][]const u8{
1310 \\pub extern fn foo(noalias bar: ?*c_void, noalias ?*c_void) void;
1311 });
1312
1313 cases.add_2("assign",
1314 \\int max(int a) {
1315 \\ int tmp;
1316 \\ tmp = a;
1317 \\ a = tmp;
13471318 \\}
1319 , &[_][]const u8{
1320 \\pub export fn max(_arg_a: c_int) c_int {
1321 \\ var a = _arg_a;
1322 \\ var tmp: c_int = undefined;
1323 \\ tmp = a;
1324 \\ a = tmp;
1325 \\}
1326 });
1327
1328 cases.add_2("chaining assign",
1329 \\void max(int a) {
1330 \\ int b, c;
1331 \\ c = b = a;
1332 \\}
1333 , &[_][]const u8{
1334 \\pub export fn max(_arg_a: c_int) void {
1335 \\ var a = _arg_a;
1336 \\ var b: c_int = undefined;
1337 \\ var c: c_int = undefined;
1338 \\ c = blk: {
1339 \\ const _tmp_1 = a;
1340 \\ b = _tmp_1;
1341 \\ break :blk _tmp_1;
1342 \\ };
1343 \\}
1344 });
1345
1346 cases.add_2("anonymous enum",
1347 \\enum {
1348 \\ One,
1349 \\ Two,
1350 \\};
1351 , &[_][]const u8{
1352 \\pub const One = 0;
1353 \\pub const Two = 1;
1354 \\const enum_unnamed_1 = extern enum {
1355 \\ One,
1356 \\ Two,
1357 \\};
1358 });
1359
1360 cases.add_2("c style cast",
1361 \\int float_to_int(float a) {
1362 \\ return (int)a;
1363 \\}
1364 , &[_][]const u8{
1365 \\pub export fn float_to_int(_arg_a: f32) c_int {
1366 \\ var a = _arg_a;
1367 \\ return @floatToInt(c_int, a);
1368 \\}
1369 });
1370
1371 cases.add_2("escape sequences",
1372 \\const char *escapes() {
1373 \\char a = '\'',
1374 \\ b = '\\',
1375 \\ c = '\a',
1376 \\ d = '\b',
1377 \\ e = '\f',
1378 \\ f = '\n',
1379 \\ g = '\r',
1380 \\ h = '\t',
1381 \\ i = '\v',
1382 \\ j = '\0',
1383 \\ k = '\"';
1384 \\ return "\'\\\a\b\f\n\r\t\v\0\"";
1385 \\}
1386 \\
1387 , &[_][]const u8{
1388 \\pub export fn escapes() [*c]const u8 {
1389 \\ var a: u8 = @as(u8, '\'');
1390 \\ var b: u8 = @as(u8, '\\');
1391 \\ var c: u8 = @as(u8, '\x07');
1392 \\ var d: u8 = @as(u8, '\x08');
1393 \\ var e: u8 = @as(u8, '\x0c');
1394 \\ var f: u8 = @as(u8, '\n');
1395 \\ var g: u8 = @as(u8, '\r');
1396 \\ var h: u8 = @as(u8, '\t');
1397 \\ var i: u8 = @as(u8, '\x0b');
1398 \\ var j: u8 = @as(u8, '\x00');
1399 \\ var k: u8 = @as(u8, '\"');
1400 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
1401 \\}
1402 });
1403
1404 cases.add_2("do loop",
1405 \\void foo(void) {
1406 \\ int a = 2;
1407 \\ do {
1408 \\ a = a - 1;
1409 \\ } while (a);
1410 \\
1411 \\ int b = 2;
1412 \\ do
1413 \\ b = b -1;
1414 \\ while (b);
1415 \\}
1416 , &[_][]const u8{
1417 \\pub export fn foo() void {
1418 \\ var a: c_int = 2;
1419 \\ while (true) {
1420 \\ a = (a - 1);
1421 \\ if (!(a != 0)) break;
1422 \\ }
1423 \\ var b: c_int = 2;
1424 \\ while (true) {
1425 \\ b = (b - 1);
1426 \\ if (!(b != 0)) break;
1427 \\ }
1428 \\}
1429 });
1430
1431 cases.add_2("logical and, logical or, on non-bool values, extra parens",
1432 \\enum Foo {
1433 \\ FooA,
1434 \\ FooB,
1435 \\ FooC,
1436 \\};
1437 \\typedef int SomeTypedef;
1438 \\int and_or_non_bool(int a, float b, void *c) {
1439 \\ enum Foo d = FooA;
1440 \\ int e = (a && b);
1441 \\ int f = (b && c);
1442 \\ int g = (a && c);
1443 \\ int h = (a || b);
1444 \\ int i = (b || c);
1445 \\ int j = (a || c);
1446 \\ int k = (a || d);
1447 \\ int l = (d && b);
1448 \\ int m = (c || d);
1449 \\ SomeTypedef td = 44;
1450 \\ int o = (td || b);
1451 \\ int p = (c && td);
1452 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1453 \\}
1454 , &[_][]const u8{
1455 \\pub const enum_Foo = extern enum {
1456 \\ A,
1457 \\ B,
1458 \\ C,
1459 \\};
1460 \\pub const SomeTypedef = c_int;
1461 \\pub export fn and_or_non_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void) c_int {
1462 \\ var a = _arg_a;
1463 \\ var b = _arg_b;
1464 \\ var c = _arg_c;
1465 \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
1466 \\ var e: c_int = @boolToInt(((a != 0) and (b != 0)));
1467 \\ var f: c_int = @boolToInt(((b != 0) and (c != null)));
1468 \\ var g: c_int = @boolToInt(((a != 0) and (c != null)));
1469 \\ var h: c_int = @boolToInt(((a != 0) or (b != 0)));
1470 \\ var i: c_int = @boolToInt(((b != 0) or (c != null)));
1471 \\ var j: c_int = @boolToInt(((a != 0) or (c != null)));
1472 \\ var k: c_int = @boolToInt(((a != 0) or (@enumToInt(d) != 0)));
1473 \\ var l: c_int = @boolToInt(((@enumToInt(d) != 0) and (b != 0)));
1474 \\ var m: c_int = @boolToInt(((c != null) or (@enumToInt(d) != 0)));
1475 \\ var td: SomeTypedef = 44;
1476 \\ var o: c_int = @boolToInt(((td != 0) or (b != 0)));
1477 \\ var p: c_int = @boolToInt(((c != null) and (td != 0)));
1478 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1479 \\}
1480 ,
1481 \\pub const Foo = enum_Foo;
1482 });
1483
1484 cases.add_2("qualified struct and enum",
1485 \\struct Foo {
1486 \\ int x;
1487 \\ int y;
1488 \\};
1489 \\enum Bar {
1490 \\ BarA,
1491 \\ BarB,
1492 \\};
1493 \\void func(struct Foo *a, enum Bar **b);
1494 , &[_][]const u8{
1495 \\pub const struct_Foo = extern struct {
1496 \\ x: c_int,
1497 \\ y: c_int,
1498 \\};
1499 ,
1500 \\pub const enum_Bar = extern enum {
1501 \\ A,
1502 \\ B,
1503 \\};
1504 \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
1505 ,
1506 \\pub const Foo = struct_Foo;
1507 \\pub const Bar = enum_Bar;
1508 });
1509
1510 cases.add_2("bitwise binary operators, simpler parens",
1511 \\int max(int a, int b) {
1512 \\ return (a & b) ^ (a | b);
1513 \\}
1514 , &[_][]const u8{
1515 \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int {
1516 \\ var a = _arg_a;
1517 \\ var b = _arg_b;
1518 \\ return ((a & b) ^ (a | b));
1519 \\}
1520 });
1521
1522 cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons.
1523 \\int test_comparisons(int a, int b) {
1524 \\ int c = (a < b);
1525 \\ int d = (a > b);
1526 \\ int e = (a <= b);
1527 \\ int f = (a >= b);
1528 \\ int g = (c < d);
1529 \\ int h = (e < f);
1530 \\ int i = (g < h);
1531 \\ return i;
1532 \\}
1533 , &[_][]const u8{
1534 \\pub export fn test_comparisons(_arg_a: c_int, _arg_b: c_int) c_int {
1535 \\ var a = _arg_a;
1536 \\ var b = _arg_b;
1537 \\ var c: c_int = @boolToInt((a < b));
1538 \\ var d: c_int = @boolToInt((a > b));
1539 \\ var e: c_int = @boolToInt((a <= b));
1540 \\ var f: c_int = @boolToInt((a >= b));
1541 \\ var g: c_int = @boolToInt((c < d));
1542 \\ var h: c_int = @boolToInt((e < f));
1543 \\ var i: c_int = @boolToInt((g < h));
1544 \\ return i;
1545 \\}
1546 });
1547
1548 cases.add_2("==, !=",
1549 \\int max(int a, int b) {
1550 \\ if (a == b)
1551 \\ return a;
1552 \\ if (a != b)
1553 \\ return b;
1554 \\ return a;
1555 \\}
1556 , &[_][]const u8{
1557 \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int {
1558 \\ var a = _arg_a;
1559 \\ var b = _arg_b;
1560 \\ if (a == b) return a;
1561 \\ if (a != b) return b;
1562 \\ return a;
1563 \\}
1564 });
1565
1566 cases.add_2("typedeffed bool expression",
1567 \\typedef char* yes;
1568 \\void foo(void) {
1569 \\ yes a;
1570 \\ if (a) 2;
1571 \\}
1572 , &[_][]const u8{
1573 \\pub const yes = [*c]u8;
1574 \\pub export fn foo() void {
1575 \\ var a: yes = undefined;
1576 \\ if (a != null) _ = 2;
1577 \\}
1578 });
1579
1580 cases.add_2("statement expression",
1581 \\int foo(void) {
1582 \\ return ({
1583 \\ int a = 1;
1584 \\ a;
1585 \\ a;
1586 \\ });
1587 \\}
1588 , &[_][]const u8{
1589 \\pub export fn foo() c_int {
1590 \\ return (blk: {
1591 \\ var a: c_int = 1;
1592 \\ _ = a;
1593 \\ break :blk a;
1594 \\ });
1595 \\}
1596 });
1597
1598 cases.add_2("field access expression",
1599 \\#define ARROW a->b
1600 \\#define DOT a.b
1601 \\extern struct Foo {
1602 \\ int b;
1603 \\}a;
1604 \\float b = 2.0f;
1605 \\int foo(void) {
1606 \\ struct Foo *c;
1607 \\ a.b;
1608 \\ c->b;
1609 \\}
1610 , &[_][]const u8{
1611 \\pub const struct_Foo = extern struct {
1612 \\ b: c_int,
1613 \\};
1614 \\pub extern var a: struct_Foo;
1615 \\pub export var b: f32 = 2;
1616 \\pub export fn foo() c_int {
1617 \\ var c: [*c]struct_Foo = undefined;
1618 \\ _ = a.b;
1619 \\ _ = c.*.b;
1620 \\}
1621 ,
1622 \\pub const DOT = a.b;
1623 ,
1624 \\pub const ARROW = a.*.b;
1625 });
1626
1627 cases.add_2("array access",
1628 \\#define ACCESS array[2]
1629 \\int array[100] = {};
1630 \\int foo(int index) {
1631 \\ return array[index];
1632 \\}
1633 , &[_][]const u8{
1634 \\pub export var array: [100]c_int = .{0} ** 100;
1635 \\pub export fn foo(_arg_index: c_int) c_int {
1636 \\ var index = _arg_index;
1637 \\ return array[index];
1638 \\}
1639 ,
1640 \\pub const ACCESS = array[2];
1641 });
1642
1643 cases.add_2("macro call",
1644 \\#define CALL(arg) bar(arg)
1645 , &[_][]const u8{
1646 \\pub inline fn CALL(arg: var) @TypeOf(bar(arg)) {
1647 \\ return bar(arg);
1648 \\}
1649 });
1650
1651 cases.add_2("logical and, logical or",
1652 \\int max(int a, int b) {
1653 \\ if (a < b || a == b)
1654 \\ return b;
1655 \\ if (a >= b && a == b)
1656 \\ return a;
1657 \\ return a;
1658 \\}
1659 , &[_][]const u8{
1660 \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int {
1661 \\ var a = _arg_a;
1662 \\ var b = _arg_b;
1663 \\ if ((a < b) or (a == b)) return b;
1664 \\ if ((a >= b) and (a == b)) return a;
1665 \\ return a;
1666 \\}
1667 });
1668
1669 cases.add_2("if statement",
1670 \\int max(int a, int b) {
1671 \\ if (a < b)
1672 \\ return b;
1673 \\
1674 \\ if (a < b)
1675 \\ return b;
1676 \\ else
1677 \\ return a;
1678 \\
1679 \\ if (a < b) ; else ;
1680 \\}
1681 , &[_][]const u8{
1682 \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int {
1683 \\ var a = _arg_a;
1684 \\ var b = _arg_b;
1685 \\ if (a < b) return b;
1686 \\ if (a < b) return b else return a;
1687 \\ if (a < b) {} else {}
1688 \\}
1689 });
1690
1691 cases.add_2("if on non-bool",
1692 \\enum SomeEnum { A, B, C };
1693 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
1694 \\ if (a) return 0;
1695 \\ if (b) return 1;
1696 \\ if (c) return 2;
1697 \\ if (d) return 3;
1698 \\ return 4;
1699 \\}
1700 , &[_][]const u8{
1701 \\pub const enum_SomeEnum = extern enum {
1702 \\ A,
1703 \\ B,
1704 \\ C,
1705 \\};
1706 \\pub export fn if_none_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void, _arg_d: enum_SomeEnum) c_int {
1707 \\ var a = _arg_a;
1708 \\ var b = _arg_b;
1709 \\ var c = _arg_c;
1710 \\ var d = _arg_d;
1711 \\ if (a != 0) return 0;
1712 \\ if (b != 0) return 1;
1713 \\ if (c != null) return 2;
1714 \\ if (d != 0) return 3;
1715 \\ return 4;
1716 \\}
1717 });
1718
1719 cases.add_2("simple data types",
1720 \\#include <stdint.h>
1721 \\int foo(char a, unsigned char b, signed char c);
1722 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
1723 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
1724 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
1725 , &[_][]const u8{
1726 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
1727 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
1728 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
1729 });
1730
1731 cases.add_2("simple function",
1732 \\int abs(int a) {
1733 \\ return a < 0 ? -a : a;
1734 \\}
1735 , &[_][]const u8{
1736 \\pub export fn abs(_arg_a: c_int) c_int {
1737 \\ var a = _arg_a;
1738 \\ return if (a < 0) -a else a;
1739 \\}
1740 });
1741
1742 cases.add_2("post increment",
1743 \\unsigned foo1(unsigned a) {
1744 \\ a++;
1745 \\ return a;
1746 \\}
1747 \\int foo2(int a) {
1748 \\ a++;
1749 \\ return a;
1750 \\}
1751 , &[_][]const u8{
1752 \\pub export fn foo1(_arg_a: c_uint) c_uint {
1753 \\ var a = _arg_a;
1754 \\ a +%= 1;
1755 \\ return a;
1756 \\}
1757 \\pub export fn foo2(_arg_a: c_int) c_int {
1758 \\ var a = _arg_a;
1759 \\ a += 1;
1760 \\ return a;
1761 \\}
1762 });
1763
1764 cases.add_2("deref function pointer",
1765 \\void foo(void) {}
1766 \\int baz(void) { return 0; }
1767 \\void bar(void) {
1768 \\ void(*f)(void) = foo;
1769 \\ int(*b)(void) = baz;
1770 \\ f();
1771 \\ (*(f))();
1772 \\ foo();
1773 \\ b();
1774 \\ (*(b))();
1775 \\ baz();
1776 \\}
1777 , &[_][]const u8{
1778 \\pub export fn foo() void {}
1779 \\pub export fn baz() c_int {
1780 \\ return 0;
1781 \\}
1782 \\pub export fn bar() void {
1783 \\ var f: ?extern fn () void = foo;
1784 \\ var b: ?extern fn () c_int = baz;
1785 \\ f.?();
1786 \\ (f).?();
1787 \\ foo();
1788 \\ _ = b.?();
1789 \\ _ = (b).?();
1790 \\ _ = baz();
1791 \\}
1792 });
1793
1794 cases.add_2("pre increment/decrement",
1795 \\void foo(void) {
1796 \\ int i = 0;
1797 \\ unsigned u = 0;
1798 \\ ++i;
1799 \\ --i;
1800 \\ ++u;
1801 \\ --u;
1802 \\ i = ++i;
1803 \\ i = --i;
1804 \\ u = ++u;
1805 \\ u = --u;
1806 \\}
1807 , &[_][]const u8{
1808 \\pub export fn foo() void {
1809 \\ var i: c_int = 0;
1810 \\ var u: c_uint = @as(c_uint, 0);
1811 \\ i += 1;
1812 \\ i -= 1;
1813 \\ u +%= 1;
1814 \\ u -%= 1;
1815 \\ i = (blk: {
1816 \\ const _ref_1 = &i;
1817 \\ _ref_1.* += 1;
1818 \\ break :blk _ref_1.*;
1819 \\ });
1820 \\ i = (blk: {
1821 \\ const _ref_2 = &i;
1822 \\ _ref_2.* -= 1;
1823 \\ break :blk _ref_2.*;
1824 \\ });
1825 \\ u = (blk: {
1826 \\ const _ref_3 = &u;
1827 \\ _ref_3.* +%= 1;
1828 \\ break :blk _ref_3.*;
1829 \\ });
1830 \\ u = (blk: {
1831 \\ const _ref_4 = &u;
1832 \\ _ref_4.* -%= 1;
1833 \\ break :blk _ref_4.*;
1834 \\ });
1835 \\}
1836 });
1837
1838 cases.add_2("shift right assign",
1839 \\int log2(unsigned a) {
1840 \\ int i = 0;
1841 \\ while (a > 0) {
1842 \\ a >>= 1;
1843 \\ }
1844 \\ return i;
1845 \\}
1846 , &[_][]const u8{
1847 \\pub export fn log2(_arg_a: c_uint) c_int {
1848 \\ var a = _arg_a;
1849 \\ var i: c_int = 0;
1850 \\ while (a > @as(c_uint, 0)) {
1851 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
1852 \\ }
1853 \\ return i;
1854 \\}
1855 });
1856
1857 cases.add_2("shift right assign with a fixed size type",
1858 \\#include <stdint.h>
1859 \\int log2(uint32_t a) {
1860 \\ int i = 0;
1861 \\ while (a > 0) {
1862 \\ a >>= 1;
1863 \\ }
1864 \\ return i;
1865 \\}
1866 , &[_][]const u8{
1867 \\pub export fn log2(_arg_a: u32) c_int {
1868 \\ var a = _arg_a;
1869 \\ var i: c_int = 0;
1870 \\ while (a > @as(c_uint, 0)) {
1871 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
1872 \\ }
1873 \\ return i;
1874 \\}
1875 });
1876
1877 cases.add_2("compound assignment operators",
1878 \\void foo(void) {
1879 \\ int a = 0;
1880 \\ a += (a += 1);
1881 \\ a -= (a -= 1);
1882 \\ a *= (a *= 1);
1883 \\ a &= (a &= 1);
1884 \\ a |= (a |= 1);
1885 \\ a ^= (a ^= 1);
1886 \\ a >>= (a >>= 1);
1887 \\ a <<= (a <<= 1);
1888 \\}
1889 , &[_][]const u8{
1890 \\pub export fn foo() void {
1891 \\ var a: c_int = 0;
1892 \\ a += (blk: {
1893 \\ const _ref_1 = &a;
1894 \\ _ref_1.* = _ref_1.* + 1;
1895 \\ break :blk _ref_1.*;
1896 \\ });
1897 \\ a -= (blk: {
1898 \\ const _ref_2 = &a;
1899 \\ _ref_2.* = _ref_2.* - 1;
1900 \\ break :blk _ref_2.*;
1901 \\ });
1902 \\ a *= (blk: {
1903 \\ const _ref_3 = &a;
1904 \\ _ref_3.* = _ref_3.* * 1;
1905 \\ break :blk _ref_3.*;
1906 \\ });
1907 \\ a &= (blk: {
1908 \\ const _ref_4 = &a;
1909 \\ _ref_4.* = _ref_4.* & 1;
1910 \\ break :blk _ref_4.*;
1911 \\ });
1912 \\ a |= (blk: {
1913 \\ const _ref_5 = &a;
1914 \\ _ref_5.* = _ref_5.* | 1;
1915 \\ break :blk _ref_5.*;
1916 \\ });
1917 \\ a ^= (blk: {
1918 \\ const _ref_6 = &a;
1919 \\ _ref_6.* = _ref_6.* ^ 1;
1920 \\ break :blk _ref_6.*;
1921 \\ });
1922 \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
1923 \\ const _ref_7 = &a;
1924 \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
1925 \\ break :blk _ref_7.*;
1926 \\ }));
1927 \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
1928 \\ const _ref_8 = &a;
1929 \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
1930 \\ break :blk _ref_8.*;
1931 \\ }));
1932 \\}
1933 });
1934
1935 cases.add_2("compound assignment operators unsigned",
1936 \\void foo(void) {
1937 \\ unsigned a = 0;
1938 \\ a += (a += 1);
1939 \\ a -= (a -= 1);
1940 \\ a *= (a *= 1);
1941 \\ a &= (a &= 1);
1942 \\ a |= (a |= 1);
1943 \\ a ^= (a ^= 1);
1944 \\ a >>= (a >>= 1);
1945 \\ a <<= (a <<= 1);
1946 \\}
1947 , &[_][]const u8{
1948 \\pub export fn foo() void {
1949 \\ var a: c_uint = @as(c_uint, 0);
1950 \\ a +%= (blk: {
1951 \\ const _ref_1 = &a;
1952 \\ _ref_1.* = _ref_1.* +% @as(c_uint, 1);
1953 \\ break :blk _ref_1.*;
1954 \\ });
1955 \\ a -%= (blk: {
1956 \\ const _ref_2 = &a;
1957 \\ _ref_2.* = _ref_2.* -% @as(c_uint, 1);
1958 \\ break :blk _ref_2.*;
1959 \\ });
1960 \\ a *%= (blk: {
1961 \\ const _ref_3 = &a;
1962 \\ _ref_3.* = _ref_3.* *% @as(c_uint, 1);
1963 \\ break :blk _ref_3.*;
1964 \\ });
1965 \\ a &= (blk: {
1966 \\ const _ref_4 = &a;
1967 \\ _ref_4.* = _ref_4.* & @as(c_uint, 1);
1968 \\ break :blk _ref_4.*;
1969 \\ });
1970 \\ a |= (blk: {
1971 \\ const _ref_5 = &a;
1972 \\ _ref_5.* = _ref_5.* | @as(c_uint, 1);
1973 \\ break :blk _ref_5.*;
1974 \\ });
1975 \\ a ^= (blk: {
1976 \\ const _ref_6 = &a;
1977 \\ _ref_6.* = _ref_6.* ^ @as(c_uint, 1);
1978 \\ break :blk _ref_6.*;
1979 \\ });
1980 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
1981 \\ const _ref_7 = &a;
1982 \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
1983 \\ break :blk _ref_7.*;
1984 \\ }));
1985 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
1986 \\ const _ref_8 = &a;
1987 \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
1988 \\ break :blk _ref_8.*;
1989 \\ }));
1990 \\}
1991 });
1992
1993 cases.add_2("post increment/decrement",
1994 \\void foo(void) {
1995 \\ int i = 0;
1996 \\ unsigned u = 0;
1997 \\ i++;
1998 \\ i--;
1999 \\ u++;
2000 \\ u--;
2001 \\ i = i++;
2002 \\ i = i--;
2003 \\ u = u++;
2004 \\ u = u--;
2005 \\}
2006 , &[_][]const u8{
2007 \\pub export fn foo() void {
2008 \\ var i: c_int = 0;
2009 \\ var u: c_uint = @as(c_uint, 0);
2010 \\ i += 1;
2011 \\ i -= 1;
2012 \\ u +%= 1;
2013 \\ u -%= 1;
2014 \\ i = (blk: {
2015 \\ const _ref_1 = &i;
2016 \\ const _tmp_2 = _ref_1.*;
2017 \\ _ref_1.* += 1;
2018 \\ break :blk _tmp_2;
2019 \\ });
2020 \\ i = (blk: {
2021 \\ const _ref_3 = &i;
2022 \\ const _tmp_4 = _ref_3.*;
2023 \\ _ref_3.* -= 1;
2024 \\ break :blk _tmp_4;
2025 \\ });
2026 \\ u = (blk: {
2027 \\ const _ref_5 = &u;
2028 \\ const _tmp_6 = _ref_5.*;
2029 \\ _ref_5.* +%= 1;
2030 \\ break :blk _tmp_6;
2031 \\ });
2032 \\ u = (blk: {
2033 \\ const _ref_7 = &u;
2034 \\ const _tmp_8 = _ref_7.*;
2035 \\ _ref_7.* -%= 1;
2036 \\ break :blk _tmp_8;
2037 \\ });
2038 \\}
2039 });
2040
2041 cases.add_2("implicit casts",
2042 \\#include <stdbool.h>
2043 \\
2044 \\void fn_int(int x);
2045 \\void fn_f32(float x);
2046 \\void fn_f64(double x);
2047 \\void fn_char(char x);
2048 \\void fn_bool(bool x);
2049 \\void fn_ptr(void *x);
2050 \\
2051 \\void call(int q) {
2052 \\ fn_int(3.0f);
2053 \\ fn_int(3.0);
2054 \\ fn_int(3.0L);
2055 \\ fn_int('ABCD');
2056 \\ fn_f32(3);
2057 \\ fn_f64(3);
2058 \\ fn_char('3');
2059 \\ fn_char('\x1');
2060 \\ fn_char(0);
2061 \\ fn_f32(3.0f);
2062 \\ fn_f64(3.0);
2063 \\ fn_bool(123);
2064 \\ fn_bool(0);
2065 \\ fn_bool(&fn_int);
2066 \\ fn_int(&fn_int);
2067 \\ fn_ptr(42);
2068 \\}
2069 , &[_][]const u8{
2070 \\pub extern fn fn_int(x: c_int) void;
2071 \\pub extern fn fn_f32(x: f32) void;
2072 \\pub extern fn fn_f64(x: f64) void;
2073 \\pub extern fn fn_char(x: u8) void;
2074 \\pub extern fn fn_bool(x: bool) void;
2075 \\pub extern fn fn_ptr(x: ?*c_void) void;
2076 \\pub export fn call(_arg_q: c_int) void {
2077 \\ var q = _arg_q;
2078 \\ fn_int(@floatToInt(c_int, 3));
2079 \\ fn_int(@floatToInt(c_int, 3));
2080 \\ fn_int(@floatToInt(c_int, 3));
2081 \\ fn_int(1094861636);
2082 \\ fn_f32(@intToFloat(f32, 3));
2083 \\ fn_f64(@intToFloat(f64, 3));
2084 \\ fn_char(@as(u8, '3'));
2085 \\ fn_char(@as(u8, '\x01'));
2086 \\ fn_char(@as(u8, 0));
2087 \\ fn_f32(3);
2088 \\ fn_f64(3);
2089 \\ fn_bool(123 != 0);
2090 \\ fn_bool(0 != 0);
2091 \\ fn_bool(@ptrToInt(&fn_int) != 0);
2092 \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int)));
2093 \\ fn_ptr(@intToPtr(?*c_void, 42));
2094 \\}
2095 });
2096
2097 cases.add_2("function call",
2098 \\static void bar(void) { }
2099 \\void foo(int *(baz)(void)) {
2100 \\ bar();
2101 \\ baz();
2102 \\}
2103 , &[_][]const u8{
2104 \\pub fn bar() void {}
2105 \\pub export fn foo(_arg_baz: ?extern fn () [*c]c_int) void {
2106 \\ var baz = _arg_baz;
2107 \\ bar();
2108 \\ _ = baz.?();
2109 \\}
2110 });
2111
2112 cases.add_2("macro defines string literal with octal",
2113 \\#define FOO "aoeu\023 derp"
2114 \\#define FOO2 "aoeu\0234 derp"
2115 \\#define FOO_CHAR '\077'
2116 , &[_][]const u8{
2117 \\pub const FOO = "aoeu\x13 derp";
2118 ,
2119 \\pub const FOO2 = "aoeu\x134 derp";
2120 ,
2121 \\pub const FOO_CHAR = '\x3f';
2122 });
2123
2124 cases.add_2("enums",
2125 \\enum Foo {
2126 \\ FooA,
2127 \\ FooB,
2128 \\ Foo1,
2129 \\};
2130 , &[_][]const u8{
2131 \\pub const enum_Foo = extern enum {
2132 \\ A,
2133 \\ B,
2134 \\ @"1",
2135 \\};
2136 ,
2137 \\pub const FooA = 0;
2138 ,
2139 \\pub const FooB = 1;
2140 ,
2141 \\pub const Foo1 = 2;
2142 ,
2143 \\pub const Foo = enum_Foo;
2144 });
2145
2146 cases.add_2("enums",
2147 \\enum Foo {
2148 \\ FooA = 2,
2149 \\ FooB = 5,
2150 \\ Foo1,
2151 \\};
2152 , &[_][]const u8{
2153 \\pub const enum_Foo = extern enum {
2154 \\ A = 2,
2155 \\ B = 5,
2156 \\ @"1" = 6,
2157 \\};
2158 ,
2159 \\pub const FooA = 2;
2160 ,
2161 \\pub const FooB = 5;
2162 ,
2163 \\pub const Foo1 = 6;
2164 ,
2165 \\pub const Foo = enum_Foo;
2166 });
2167
2168 cases.add_2("macro cast",
2169 \\#define FOO(bar) baz((void *)(baz))
2170 , &[_][]const u8{
2171 \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz))) {
2172 \\ return baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz));
2173 \\}
2174 });
2175
2176 /////////////// Cases for only stage1 because stage2 behavior is better ////////////////
2177 cases.addC("Parameterless function prototypes",
2178 \\void foo() {}
2179 \\void bar(void) {}
2180 , &[_][]const u8{
2181 \\pub export fn foo() void {}
2182 \\pub export fn bar() void {}
2183 });
2184
2185 cases.add("#define a char literal",
2186 \\#define A_CHAR 'a'
2187 , &[_][]const u8{
2188 \\pub const A_CHAR = 97;
2189 });
2190
2191 cases.add("generate inline func for #define global extern fn",
2192 \\extern void (*fn_ptr)(void);
2193 \\#define foo fn_ptr
2194 \\
2195 \\extern char (*fn_ptr2)(int, float);
2196 \\#define bar fn_ptr2
2197 , &[_][]const u8{
2198 \\pub extern var fn_ptr: ?extern fn () void;
2199 ,
2200 \\pub inline fn foo() void {
2201 \\ return fn_ptr.?();
2202 \\}
2203 ,
2204 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
2205 ,
2206 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {
2207 \\ return fn_ptr2.?(arg0, arg1);
2208 \\}
2209 });
2210 cases.add("comment after integer literal",
2211 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2212 , &[_][]const u8{
2213 \\pub const SDL_INIT_VIDEO = 32;
2214 });
2215
2216 cases.add("u integer suffix after hex literal",
2217 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2218 , &[_][]const u8{
2219 \\pub const SDL_INIT_VIDEO = @as(c_uint, 32);
2220 });
2221
2222 cases.add("l integer suffix after hex literal",
2223 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2224 , &[_][]const u8{
2225 \\pub const SDL_INIT_VIDEO = @as(c_long, 32);
2226 });
2227
2228 cases.add("ul integer suffix after hex literal",
2229 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2230 , &[_][]const u8{
2231 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2232 });
2233
2234 cases.add("lu integer suffix after hex literal",
2235 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2236 , &[_][]const u8{
2237 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2238 });
2239
2240 cases.add("ll integer suffix after hex literal",
2241 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2242 , &[_][]const u8{
2243 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32);
2244 });
2245
2246 cases.add("ull integer suffix after hex literal",
2247 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2248 , &[_][]const u8{
2249 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2250 });
2251
2252 cases.add("llu integer suffix after hex literal",
2253 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2254 , &[_][]const u8{
2255 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2256 });
2257
2258 cases.add("macros with field targets",
2259 \\typedef unsigned int GLbitfield;
2260 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
2261 \\typedef void(*OpenGLProc)(void);
2262 \\union OpenGLProcs {
2263 \\ OpenGLProc ptr[1];
2264 \\ struct {
2265 \\ PFNGLCLEARPROC Clear;
2266 \\ } gl;
2267 \\};
2268 \\extern union OpenGLProcs glProcs;
2269 \\#define glClearUnion glProcs.gl.Clear
2270 \\#define glClearPFN PFNGLCLEARPROC
2271 , &[_][]const u8{
2272 \\pub const GLbitfield = c_uint;
2273 ,
2274 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;
2275 ,
2276 \\pub const OpenGLProc = ?extern fn () void;
2277 ,
2278 \\pub const union_OpenGLProcs = extern union {
2279 \\ ptr: [1]OpenGLProc,
2280 \\ gl: extern struct {
2281 \\ Clear: PFNGLCLEARPROC,
2282 \\ },
2283 \\};
2284 ,
2285 \\pub extern var glProcs: union_OpenGLProcs;
2286 ,
2287 \\pub const glClearPFN = PFNGLCLEARPROC;
2288 ,
2289 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
2290 \\ return glProcs.gl.Clear.?(arg0);
2291 \\}
2292 ,
2293 \\pub const OpenGLProcs = union_OpenGLProcs;
2294 });
2295
2296 cases.add("macro pointer cast",
2297 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
2298 , &[_][]const u8{
2299 \\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);
2300 });
2301
2302 cases.add("switch on int",
2303 \\int switch_fn(int i) {
2304 \\ int res = 0;
2305 \\ switch (i) {
2306 \\ case 0:
2307 \\ res = 1;
2308 \\ case 1:
2309 \\ res = 2;
2310 \\ default:
2311 \\ res = 3 * i;
2312 \\ break;
2313 \\ case 2:
2314 \\ res = 5;
2315 \\ }
2316 \\}
2317 , &[_][]const u8{
2318 \\pub fn switch_fn(i: c_int) c_int {
2319 \\ var res: c_int = 0;
2320 \\ __switch: {
2321 \\ __case_2: {
2322 \\ __default: {
2323 \\ __case_1: {
2324 \\ __case_0: {
2325 \\ switch (i) {
2326 \\ 0 => break :__case_0,
2327 \\ 1 => break :__case_1,
2328 \\ else => break :__default,
2329 \\ 2 => break :__case_2,
2330 \\ }
2331 \\ }
2332 \\ res = 1;
2333 \\ }
2334 \\ res = 2;
2335 \\ }
2336 \\ res = (3 * i);
2337 \\ break :__switch;
2338 \\ }
2339 \\ res = 5;
2340 \\ }
2341 \\}
2342 });
2343
2344 cases.add("for loop with var init but empty body",
2345 \\void foo(void) {
2346 \\ for (int x = 0; x < 10; x++);
2347 \\}
2348 , &[_][]const u8{
2349 \\pub fn foo() void {
2350 \\ {
2351 \\ var x: c_int = 0;
2352 \\ while (x < 10) : (x += 1) {}
2353 \\ }
2354 \\}
2355 });
2356
2357 cases.add("do while with empty body",
2358 \\void foo(void) {
2359 \\ do ; while (1);
2360 \\}
2361 , &[_][]const u8{ // TODO this should be if (1 != 0) break
2362 \\pub fn foo() void {
2363 \\ while (true) {
2364 \\ {}
2365 \\ if (!1) break;
2366 \\ }
2367 \\}
2368 });
2369
2370 cases.add("for with empty body",
2371 \\void foo(void) {
2372 \\ for (;;);
2373 \\}
2374 , &[_][]const u8{
2375 \\pub fn foo() void {
2376 \\ while (true) {}
2377 \\}
2378 });
2379
2380 cases.add("while with empty body",
2381 \\void foo(void) {
2382 \\ while (1);
2383 \\}
2384 , &[_][]const u8{
2385 \\pub fn foo() void {
2386 \\ while (1 != 0) {}
2387 \\}
2388 });
2389
2390 cases.add("undefined array global",
2391 \\int array[100];
2392 , &[_][]const u8{
2393 \\pub var array: [100]c_int = undefined;
2394 });
2395
2396 cases.add("qualified struct and enum",
2397 \\struct Foo {
2398 \\ int x;
2399 \\ int y;
2400 \\};
2401 \\enum Bar {
2402 \\ BarA,
2403 \\ BarB,
2404 \\};
2405 \\void func(struct Foo *a, enum Bar **b);
2406 , &[_][]const u8{
2407 \\pub const struct_Foo = extern struct {
2408 \\ x: c_int,
2409 \\ y: c_int,
2410 \\};
2411 ,
2412 \\pub const enum_Bar = extern enum {
2413 \\ A,
2414 \\ B,
2415 \\};
2416 ,
2417 \\pub const BarA = enum_Bar.A;
2418 ,
2419 \\pub const BarB = enum_Bar.B;
2420 ,
2421 \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
2422 ,
2423 \\pub const Foo = struct_Foo;
2424 ,
2425 \\pub const Bar = enum_Bar;
2426 });
2427
2428 cases.add("restrict -> noalias",
2429 \\void foo(void *restrict bar, void *restrict);
2430 , &[_][]const u8{
2431 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;
13482432 });
13492433
1350 cases.addC("compound assignment operators unsigned",
1351 \\void foo(void) {
1352 \\ unsigned a = 0;
1353 \\ a += (a += 1);
1354 \\ a -= (a -= 1);
1355 \\ a *= (a *= 1);
1356 \\ a &= (a &= 1);
1357 \\ a |= (a |= 1);
1358 \\ a ^= (a ^= 1);
1359 \\ a >>= (a >>= 1);
1360 \\ a <<= (a <<= 1);
2434 cases.addC("assign",
2435 \\int max(int a) {
2436 \\ int tmp;
2437 \\ tmp = a;
2438 \\ a = tmp;
13612439 \\}
13622440 , &[_][]const u8{
1363 \\pub export fn foo() void {
1364 \\ var a: c_uint = @as(c_uint, 0);
1365 \\ a +%= (x: {
1366 \\ const _ref = &a;
1367 \\ _ref.* = (_ref.* +% @as(c_uint, 1));
1368 \\ break :x _ref.*;
1369 \\ });
1370 \\ a -%= (x: {
1371 \\ const _ref = &a;
1372 \\ _ref.* = (_ref.* -% @as(c_uint, 1));
1373 \\ break :x _ref.*;
1374 \\ });
1375 \\ a *%= (x: {
1376 \\ const _ref = &a;
1377 \\ _ref.* = (_ref.* *% @as(c_uint, 1));
1378 \\ break :x _ref.*;
1379 \\ });
1380 \\ a &= (x: {
1381 \\ const _ref = &a;
1382 \\ _ref.* = (_ref.* & @as(c_uint, 1));
1383 \\ break :x _ref.*;
1384 \\ });
1385 \\ a |= (x: {
1386 \\ const _ref = &a;
1387 \\ _ref.* = (_ref.* | @as(c_uint, 1));
1388 \\ break :x _ref.*;
1389 \\ });
1390 \\ a ^= (x: {
1391 \\ const _ref = &a;
1392 \\ _ref.* = (_ref.* ^ @as(c_uint, 1));
1393 \\ break :x _ref.*;
1394 \\ });
1395 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
1396 \\ const _ref = &a;
1397 \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
1398 \\ break :x _ref.*;
1399 \\ }));
1400 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
1401 \\ const _ref = &a;
1402 \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
1403 \\ break :x _ref.*;
1404 \\ }));
2441 \\pub export fn max(_arg_a: c_int) c_int {
2442 \\ var a = _arg_a;
2443 \\ var tmp: c_int = undefined;
2444 \\ tmp = a;
2445 \\ a = tmp;
14052446 \\}
14062447 });
14072448
1408 cases.addC("post increment/decrement",
1409 \\void foo(void) {
1410 \\ int i = 0;
1411 \\ unsigned u = 0;
1412 \\ i++;
1413 \\ i--;
1414 \\ u++;
1415 \\ u--;
1416 \\ i = i++;
1417 \\ i = i--;
1418 \\ u = u++;
1419 \\ u = u--;
2449 cases.addC("chaining assign",
2450 \\void max(int a) {
2451 \\ int b, c;
2452 \\ c = b = a;
14202453 \\}
14212454 , &[_][]const u8{
1422 \\pub export fn foo() void {
1423 \\ var i: c_int = 0;
1424 \\ var u: c_uint = @as(c_uint, 0);
1425 \\ i += 1;
1426 \\ i -= 1;
1427 \\ u +%= 1;
1428 \\ u -%= 1;
1429 \\ i = (x: {
1430 \\ const _ref = &i;
1431 \\ const _tmp = _ref.*;
1432 \\ _ref.* += 1;
1433 \\ break :x _tmp;
1434 \\ });
1435 \\ i = (x: {
1436 \\ const _ref = &i;
1437 \\ const _tmp = _ref.*;
1438 \\ _ref.* -= 1;
1439 \\ break :x _tmp;
1440 \\ });
1441 \\ u = (x: {
1442 \\ const _ref = &u;
1443 \\ const _tmp = _ref.*;
1444 \\ _ref.* +%= 1;
1445 \\ break :x _tmp;
1446 \\ });
1447 \\ u = (x: {
1448 \\ const _ref = &u;
1449 \\ const _tmp = _ref.*;
1450 \\ _ref.* -%= 1;
2455 \\pub export fn max(a: c_int) void {
2456 \\ var b: c_int = undefined;
2457 \\ var c: c_int = undefined;
2458 \\ c = (x: {
2459 \\ const _tmp = a;
2460 \\ b = _tmp;
14512461 \\ break :x _tmp;
14522462 \\ });
14532463 \\}
14542464 });
14552465
1456 cases.addC("pre increment/decrement",
1457 \\void foo(void) {
1458 \\ int i = 0;
1459 \\ unsigned u = 0;
1460 \\ ++i;
1461 \\ --i;
1462 \\ ++u;
1463 \\ --u;
1464 \\ i = ++i;
1465 \\ i = --i;
1466 \\ u = ++u;
1467 \\ u = --u;
1468 \\}
2466 cases.add("anonymous enum",
2467 \\enum {
2468 \\ One,
2469 \\ Two,
2470 \\};
14692471 , &[_][]const u8{
1470 \\pub export fn foo() void {
1471 \\ var i: c_int = 0;
1472 \\ var u: c_uint = @as(c_uint, 0);
1473 \\ i += 1;
1474 \\ i -= 1;
1475 \\ u +%= 1;
1476 \\ u -%= 1;
1477 \\ i = (x: {
1478 \\ const _ref = &i;
1479 \\ _ref.* += 1;
1480 \\ break :x _ref.*;
1481 \\ });
1482 \\ i = (x: {
1483 \\ const _ref = &i;
1484 \\ _ref.* -= 1;
1485 \\ break :x _ref.*;
1486 \\ });
1487 \\ u = (x: {
1488 \\ const _ref = &u;
1489 \\ _ref.* +%= 1;
1490 \\ break :x _ref.*;
1491 \\ });
1492 \\ u = (x: {
1493 \\ const _ref = &u;
1494 \\ _ref.* -%= 1;
1495 \\ break :x _ref.*;
1496 \\ });
1497 \\}
2472 \\pub const One = 0;
2473 \\pub const Two = 1;
14982474 });
14992475
1500 cases.addC("do loop",
1501 \\void foo(void) {
1502 \\ int a = 2;
1503 \\ do {
1504 \\ a--;
1505 \\ } while (a != 0);
1506 \\
1507 \\ int b = 2;
1508 \\ do
1509 \\ b--;
1510 \\ while (b != 0);
2476 cases.addC("c style cast",
2477 \\int float_to_int(float a) {
2478 \\ return (int)a;
15112479 \\}
15122480 , &[_][]const u8{
1513 \\pub export fn foo() void {
1514 \\ var a: c_int = 2;
1515 \\ while (true) {
1516 \\ a -= 1;
1517 \\ if (!(a != 0)) break;
1518 \\ }
1519 \\ var b: c_int = 2;
1520 \\ while (true) {
1521 \\ b -= 1;
1522 \\ if (!(b != 0)) break;
1523 \\ }
2481 \\pub export fn float_to_int(a: f32) c_int {
2482 \\ return @as(c_int, a);
15242483 \\}
15252484 });
15262485
1527 cases.addC("deref function pointer",
1528 \\void foo(void) {}
1529 \\int baz(void) { return 0; }
1530 \\void bar(void) {
1531 \\ void(*f)(void) = foo;
1532 \\ int(*b)(void) = baz;
1533 \\ f();
1534 \\ (*(f))();
1535 \\ foo();
1536 \\ b();
1537 \\ (*(b))();
1538 \\ baz();
2486 cases.addC("comma operator",
2487 \\int foo(void) {
2488 \\ return 1, 2;
15392489 \\}
15402490 , &[_][]const u8{
1541 \\pub export fn foo() void {}
1542 \\pub export fn baz() c_int {
1543 \\ return 0;
1544 \\}
1545 \\pub export fn bar() void {
1546 \\ var f: ?extern fn () void = foo;
1547 \\ var b: ?extern fn () c_int = baz;
1548 \\ f.?();
1549 \\ f.?();
1550 \\ foo();
1551 \\ _ = b.?();
1552 \\ _ = b.?();
1553 \\ _ = baz();
2491 \\pub export fn foo() c_int {
2492 \\ return x: {
2493 \\ _ = 1;
2494 \\ break :x 2;
2495 \\ };
15542496 \\}
15552497 });
15562498
1557 cases.addC("normal deref",
1558 \\void foo(int *x) {
1559 \\ *x = 1;
2499 cases.addC("escape sequences",
2500 \\const char *escapes() {
2501 \\char a = '\'',
2502 \\ b = '\\',
2503 \\ c = '\a',
2504 \\ d = '\b',
2505 \\ e = '\f',
2506 \\ f = '\n',
2507 \\ g = '\r',
2508 \\ h = '\t',
2509 \\ i = '\v',
2510 \\ j = '\0',
2511 \\ k = '\"';
2512 \\ return "\'\\\a\b\f\n\r\t\v\0\"";
15602513 \\}
2514 \\
15612515 , &[_][]const u8{
1562 \\pub export fn foo(x: [*c]c_int) void {
1563 \\ x.?.* = 1;
2516 \\pub export fn escapes() [*c]const u8 {
2517 \\ var a: u8 = @as(u8, '\'');
2518 \\ var b: u8 = @as(u8, '\\');
2519 \\ var c: u8 = @as(u8, '\x07');
2520 \\ var d: u8 = @as(u8, '\x08');
2521 \\ var e: u8 = @as(u8, '\x0c');
2522 \\ var f: u8 = @as(u8, '\n');
2523 \\ var g: u8 = @as(u8, '\r');
2524 \\ var h: u8 = @as(u8, '\t');
2525 \\ var i: u8 = @as(u8, '\x0b');
2526 \\ var j: u8 = @as(u8, '\x00');
2527 \\ var k: u8 = @as(u8, '\"');
2528 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
15642529 \\}
2530 \\
15652531 });
15662532
1567 cases.add("simple union",
1568 \\union Foo {
1569 \\ int x;
1570 \\ double y;
1571 \\};
2533 cases.addC("do loop",
2534 \\void foo(void) {
2535 \\ int a = 2;
2536 \\ do {
2537 \\ a--;
2538 \\ } while (a != 0);
2539 \\
2540 \\ int b = 2;
2541 \\ do
2542 \\ b--;
2543 \\ while (b != 0);
2544 \\}
15722545 , &[_][]const u8{
1573 \\pub const union_Foo = extern union {
1574 \\ x: c_int,
1575 \\ y: f64,
1576 \\};
1577 ,
1578 \\pub const Foo = union_Foo;
2546 \\pub export fn foo() void {
2547 \\ var a: c_int = 2;
2548 \\ while (true) {
2549 \\ a -= 1;
2550 \\ if (!(a != 0)) break;
2551 \\ }
2552 \\ var b: c_int = 2;
2553 \\ while (true) {
2554 \\ b -= 1;
2555 \\ if (!(b != 0)) break;
2556 \\ }
2557 \\}
15792558 });
15802559
1581 cases.add("address of operator",
1582 \\int foo(void) {
1583 \\ int x = 1234;
1584 \\ int *ptr = &x;
1585 \\ return *ptr;
2560 cases.addC("==, !=",
2561 \\int max(int a, int b) {
2562 \\ if (a == b)
2563 \\ return a;
2564 \\ if (a != b)
2565 \\ return b;
2566 \\ return a;
15862567 \\}
15872568 , &[_][]const u8{
1588 \\pub fn foo() c_int {
1589 \\ var x: c_int = 1234;
1590 \\ var ptr: [*c]c_int = &x;
1591 \\ return ptr.?.*;
2569 \\pub export fn max(a: c_int, b: c_int) c_int {
2570 \\ if (a == b) return a;
2571 \\ if (a != b) return b;
2572 \\ return a;
15922573 \\}
15932574 });
15942575
1595 cases.add("string literal",
1596 \\const char *foo(void) {
1597 \\ return "bar";
2576 cases.addC("bitwise binary operators",
2577 \\int max(int a, int b) {
2578 \\ return (a & b) ^ (a | b);
15982579 \\}
15992580 , &[_][]const u8{
1600 \\pub fn foo() [*c]const u8 {
1601 \\ return "bar";
2581 \\pub export fn max(a: c_int, b: c_int) c_int {
2582 \\ return (a & b) ^ (a | b);
16022583 \\}
16032584 });
16042585
1605 cases.add("return void",
1606 \\void foo(void) {
1607 \\ return;
2586 cases.addC("statement expression",
2587 \\int foo(void) {
2588 \\ return ({
2589 \\ int a = 1;
2590 \\ a;
2591 \\ });
16082592 \\}
16092593 , &[_][]const u8{
1610 \\pub fn foo() void {
1611 \\ return;
2594 \\pub export fn foo() c_int {
2595 \\ return x: {
2596 \\ var a: c_int = 1;
2597 \\ break :x a;
2598 \\ };
16122599 \\}
16132600 });
16142601
1615 cases.add("for loop",
1616 \\void foo(void) {
1617 \\ for (int i = 0; i < 10; i += 1) { }
2602 cases.addC("field access expression",
2603 \\struct Foo {
2604 \\ int field;
2605 \\};
2606 \\int read_field(struct Foo *foo) {
2607 \\ return foo->field;
16182608 \\}
16192609 , &[_][]const u8{
1620 \\pub fn foo() void {
1621 \\ {
1622 \\ var i: c_int = 0;
1623 \\ while (i < 10) : (i += 1) {}
1624 \\ }
2610 \\pub const struct_Foo = extern struct {
2611 \\ field: c_int,
2612 \\};
2613 \\pub export fn read_field(foo: [*c]struct_Foo) c_int {
2614 \\ return foo.*.field;
16252615 \\}
16262616 });
16272617
1628 cases.add("empty for loop",
1629 \\void foo(void) {
1630 \\ for (;;) { }
2618 cases.addC("array access",
2619 \\int array[100];
2620 \\int foo(int index) {
2621 \\ return array[index];
16312622 \\}
16322623 , &[_][]const u8{
1633 \\pub fn foo() void {
1634 \\ while (true) {}
2624 \\pub var array: [100]c_int = undefined;
2625 \\pub export fn foo(index: c_int) c_int {
2626 \\ return array[index];
16352627 \\}
16362628 });
16372629
1638 cases.add("break statement",
1639 \\void foo(void) {
1640 \\ for (;;) {
1641 \\ break;
1642 \\ }
2630 cases.addC("logical and, logical or",
2631 \\int max(int a, int b) {
2632 \\ if (a < b || a == b)
2633 \\ return b;
2634 \\ if (a >= b && a == b)
2635 \\ return a;
2636 \\ return a;
16432637 \\}
16442638 , &[_][]const u8{
1645 \\pub fn foo() void {
1646 \\ while (true) {
1647 \\ break;
1648 \\ }
2639 \\pub export fn max(a: c_int, b: c_int) c_int {
2640 \\ if ((a < b) or (a == b)) return b;
2641 \\ if ((a >= b) and (a == b)) return a;
2642 \\ return a;
16492643 \\}
16502644 });
16512645
1652 cases.add("continue statement",
1653 \\void foo(void) {
1654 \\ for (;;) {
1655 \\ continue;
1656 \\ }
2646 cases.addC("if statement",
2647 \\int max(int a, int b) {
2648 \\ if (a < b)
2649 \\ return b;
2650 \\
2651 \\ if (a < b)
2652 \\ return b;
2653 \\ else
2654 \\ return a;
2655 \\
2656 \\ if (a < b) ; else ;
16572657 \\}
16582658 , &[_][]const u8{
1659 \\pub fn foo() void {
1660 \\ while (true) {
1661 \\ continue;
1662 \\ }
2659 \\pub export fn max(a: c_int, b: c_int) c_int {
2660 \\ if (a < b) return b;
2661 \\ if (a < b) return b else return a;
2662 \\ if (a < b) {} else {}
16632663 \\}
16642664 });
16652665
......@@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16832683 \\}
16842684 });
16852685
1686 cases.add("pointer casting",
1687 \\float *ptrcast(int *a) {
1688 \\ return (float *)a;
2686 cases.add("if on non-bool",
2687 \\enum SomeEnum { A, B, C };
2688 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
2689 \\ if (a) return 0;
2690 \\ if (b) return 1;
2691 \\ if (c) return 2;
2692 \\ if (d) return 3;
2693 \\ return 4;
16892694 \\}
16902695 , &[_][]const u8{
1691 \\fn ptrcast(a: [*c]c_int) [*c]f32 {
1692 \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
2696 \\pub const A = enum_SomeEnum.A;
2697 \\pub const B = enum_SomeEnum.B;
2698 \\pub const C = enum_SomeEnum.C;
2699 \\pub const enum_SomeEnum = extern enum {
2700 \\ A,
2701 \\ B,
2702 \\ C,
2703 \\};
2704 \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
2705 \\ if (a != 0) return 0;
2706 \\ if (b != 0) return 1;
2707 \\ if (c != null) return 2;
2708 \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3;
2709 \\ return 4;
16932710 \\}
16942711 });
16952712
1696 cases.add("bin not",
1697 \\int foo(int x) {
1698 \\ return ~x;
2713 cases.addAllowWarnings("simple data types",
2714 \\#include <stdint.h>
2715 \\int foo(char a, unsigned char b, signed char c);
2716 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
2717 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
2718 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
2719 , &[_][]const u8{
2720 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
2721 ,
2722 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
2723 ,
2724 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
2725 });
2726
2727 cases.addC("simple function",
2728 \\int abs(int a) {
2729 \\ return a < 0 ? -a : a;
16992730 \\}
17002731 , &[_][]const u8{
1701 \\pub fn foo(x: c_int) c_int {
1702 \\ return ~x;
2732 \\pub export fn abs(a: c_int) c_int {
2733 \\ return if (a < 0) -a else a;
17032734 \\}
17042735 });
17052736
1706 cases.add("bool not",
1707 \\int foo(int a, float b, void *c) {
1708 \\ return !(a == 0);
1709 \\ return !a;
1710 \\ return !b;
1711 \\ return !c;
2737 cases.addC("post increment",
2738 \\unsigned foo1(unsigned a) {
2739 \\ a++;
2740 \\ return a;
2741 \\}
2742 \\int foo2(int a) {
2743 \\ a++;
2744 \\ return a;
2745 \\}
2746 , &[_][]const u8{
2747 \\pub export fn foo1(_arg_a: c_uint) c_uint {
2748 \\ var a = _arg_a;
2749 \\ a +%= 1;
2750 \\ return a;
2751 \\}
2752 \\pub export fn foo2(_arg_a: c_int) c_int {
2753 \\ var a = _arg_a;
2754 \\ a += 1;
2755 \\ return a;
2756 \\}
2757 });
2758
2759 cases.addC("deref function pointer",
2760 \\void foo(void) {}
2761 \\int baz(void) { return 0; }
2762 \\void bar(void) {
2763 \\ void(*f)(void) = foo;
2764 \\ int(*b)(void) = baz;
2765 \\ f();
2766 \\ (*(f))();
2767 \\ foo();
2768 \\ b();
2769 \\ (*(b))();
2770 \\ baz();
2771 \\}
2772 , &[_][]const u8{
2773 \\pub export fn foo() void {}
2774 \\pub export fn baz() c_int {
2775 \\ return 0;
2776 \\}
2777 \\pub export fn bar() void {
2778 \\ var f: ?extern fn () void = foo;
2779 \\ var b: ?extern fn () c_int = baz;
2780 \\ f.?();
2781 \\ f.?();
2782 \\ foo();
2783 \\ _ = b.?();
2784 \\ _ = b.?();
2785 \\ _ = baz();
2786 \\}
2787 });
2788
2789 cases.addC("pre increment/decrement",
2790 \\void foo(void) {
2791 \\ int i = 0;
2792 \\ unsigned u = 0;
2793 \\ ++i;
2794 \\ --i;
2795 \\ ++u;
2796 \\ --u;
2797 \\ i = ++i;
2798 \\ i = --i;
2799 \\ u = ++u;
2800 \\ u = --u;
17122801 \\}
17132802 , &[_][]const u8{
1714 \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
1715 \\ return !(a == 0);
1716 \\ return !(a != 0);
1717 \\ return !(b != 0);
1718 \\ return !(c != null);
2803 \\pub export fn foo() void {
2804 \\ var i: c_int = 0;
2805 \\ var u: c_uint = @as(c_uint, 0);
2806 \\ i += 1;
2807 \\ i -= 1;
2808 \\ u +%= 1;
2809 \\ u -%= 1;
2810 \\ i = (x: {
2811 \\ const _ref = &i;
2812 \\ _ref.* += 1;
2813 \\ break :x _ref.*;
2814 \\ });
2815 \\ i = (x: {
2816 \\ const _ref = &i;
2817 \\ _ref.* -= 1;
2818 \\ break :x _ref.*;
2819 \\ });
2820 \\ u = (x: {
2821 \\ const _ref = &u;
2822 \\ _ref.* +%= 1;
2823 \\ break :x _ref.*;
2824 \\ });
2825 \\ u = (x: {
2826 \\ const _ref = &u;
2827 \\ _ref.* -%= 1;
2828 \\ break :x _ref.*;
2829 \\ });
17192830 \\}
17202831 });
17212832
1722 cases.add("primitive types included in defined symbols",
1723 \\int foo(int u32) {
1724 \\ return u32;
2833 cases.addC("shift right assign",
2834 \\int log2(unsigned a) {
2835 \\ int i = 0;
2836 \\ while (a > 0) {
2837 \\ a >>= 1;
2838 \\ }
2839 \\ return i;
17252840 \\}
17262841 , &[_][]const u8{
1727 \\pub fn foo(u32_0: c_int) c_int {
1728 \\ return u32_0;
2842 \\pub export fn log2(_arg_a: c_uint) c_int {
2843 \\ var a = _arg_a;
2844 \\ var i: c_int = 0;
2845 \\ while (a > @as(c_uint, 0)) {
2846 \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1);
2847 \\ }
2848 \\ return i;
17292849 \\}
17302850 });
17312851
1732 cases.add("if on non-bool",
1733 \\enum SomeEnum { A, B, C };
1734 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
1735 \\ if (a) return 0;
1736 \\ if (b) return 1;
1737 \\ if (c) return 2;
1738 \\ if (d) return 3;
1739 \\ return 4;
2852 cases.addC("shift right assign with a fixed size type",
2853 \\#include <stdint.h>
2854 \\int log2(uint32_t a) {
2855 \\ int i = 0;
2856 \\ while (a > 0) {
2857 \\ a >>= 1;
2858 \\ }
2859 \\ return i;
17402860 \\}
17412861 , &[_][]const u8{
1742 \\pub const A = enum_SomeEnum.A;
1743 \\pub const B = enum_SomeEnum.B;
1744 \\pub const C = enum_SomeEnum.C;
1745 \\pub const enum_SomeEnum = extern enum {
1746 \\ A,
1747 \\ B,
1748 \\ C,
1749 \\};
1750 \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
1751 \\ if (a != 0) return 0;
1752 \\ if (b != 0) return 1;
1753 \\ if (c != null) return 2;
1754 \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3;
1755 \\ return 4;
2862 \\pub export fn log2(_arg_a: u32) c_int {
2863 \\ var a = _arg_a;
2864 \\ var i: c_int = 0;
2865 \\ while (a > @as(c_uint, 0)) {
2866 \\ a >>= @as(u5, 1);
2867 \\ }
2868 \\ return i;
17562869 \\}
17572870 });
17582871
1759 cases.add("while on non-bool",
1760 \\int while_none_bool(int a, float b, void *c) {
1761 \\ while (a) return 0;
1762 \\ while (b) return 1;
1763 \\ while (c) return 2;
1764 \\ return 3;
2872 cases.addC("compound assignment operators",
2873 \\void foo(void) {
2874 \\ int a = 0;
2875 \\ a += (a += 1);
2876 \\ a -= (a -= 1);
2877 \\ a *= (a *= 1);
2878 \\ a &= (a &= 1);
2879 \\ a |= (a |= 1);
2880 \\ a ^= (a ^= 1);
2881 \\ a >>= (a >>= 1);
2882 \\ a <<= (a <<= 1);
17652883 \\}
17662884 , &[_][]const u8{
1767 \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1768 \\ while (a != 0) return 0;
1769 \\ while (b != 0) return 1;
1770 \\ while (c != null) return 2;
1771 \\ return 3;
2885 \\pub export fn foo() void {
2886 \\ var a: c_int = 0;
2887 \\ a += (x: {
2888 \\ const _ref = &a;
2889 \\ _ref.* = (_ref.* + 1);
2890 \\ break :x _ref.*;
2891 \\ });
2892 \\ a -= (x: {
2893 \\ const _ref = &a;
2894 \\ _ref.* = (_ref.* - 1);
2895 \\ break :x _ref.*;
2896 \\ });
2897 \\ a *= (x: {
2898 \\ const _ref = &a;
2899 \\ _ref.* = (_ref.* * 1);
2900 \\ break :x _ref.*;
2901 \\ });
2902 \\ a &= (x: {
2903 \\ const _ref = &a;
2904 \\ _ref.* = (_ref.* & 1);
2905 \\ break :x _ref.*;
2906 \\ });
2907 \\ a |= (x: {
2908 \\ const _ref = &a;
2909 \\ _ref.* = (_ref.* | 1);
2910 \\ break :x _ref.*;
2911 \\ });
2912 \\ a ^= (x: {
2913 \\ const _ref = &a;
2914 \\ _ref.* = (_ref.* ^ 1);
2915 \\ break :x _ref.*;
2916 \\ });
2917 \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: {
2918 \\ const _ref = &a;
2919 \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
2920 \\ break :x _ref.*;
2921 \\ }));
2922 \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: {
2923 \\ const _ref = &a;
2924 \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
2925 \\ break :x _ref.*;
2926 \\ }));
17722927 \\}
17732928 });
17742929
1775 cases.add("for on non-bool",
1776 \\int for_none_bool(int a, float b, void *c) {
1777 \\ for (;a;) return 0;
1778 \\ for (;b;) return 1;
1779 \\ for (;c;) return 2;
1780 \\ return 3;
2930 cases.addC("compound assignment operators unsigned",
2931 \\void foo(void) {
2932 \\ unsigned a = 0;
2933 \\ a += (a += 1);
2934 \\ a -= (a -= 1);
2935 \\ a *= (a *= 1);
2936 \\ a &= (a &= 1);
2937 \\ a |= (a |= 1);
2938 \\ a ^= (a ^= 1);
2939 \\ a >>= (a >>= 1);
2940 \\ a <<= (a <<= 1);
17812941 \\}
17822942 , &[_][]const u8{
1783 \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1784 \\ while (a != 0) return 0;
1785 \\ while (b != 0) return 1;
1786 \\ while (c != null) return 2;
1787 \\ return 3;
2943 \\pub export fn foo() void {
2944 \\ var a: c_uint = @as(c_uint, 0);
2945 \\ a +%= (x: {
2946 \\ const _ref = &a;
2947 \\ _ref.* = (_ref.* +% @as(c_uint, 1));
2948 \\ break :x _ref.*;
2949 \\ });
2950 \\ a -%= (x: {
2951 \\ const _ref = &a;
2952 \\ _ref.* = (_ref.* -% @as(c_uint, 1));
2953 \\ break :x _ref.*;
2954 \\ });
2955 \\ a *%= (x: {
2956 \\ const _ref = &a;
2957 \\ _ref.* = (_ref.* *% @as(c_uint, 1));
2958 \\ break :x _ref.*;
2959 \\ });
2960 \\ a &= (x: {
2961 \\ const _ref = &a;
2962 \\ _ref.* = (_ref.* & @as(c_uint, 1));
2963 \\ break :x _ref.*;
2964 \\ });
2965 \\ a |= (x: {
2966 \\ const _ref = &a;
2967 \\ _ref.* = (_ref.* | @as(c_uint, 1));
2968 \\ break :x _ref.*;
2969 \\ });
2970 \\ a ^= (x: {
2971 \\ const _ref = &a;
2972 \\ _ref.* = (_ref.* ^ @as(c_uint, 1));
2973 \\ break :x _ref.*;
2974 \\ });
2975 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
2976 \\ const _ref = &a;
2977 \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
2978 \\ break :x _ref.*;
2979 \\ }));
2980 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
2981 \\ const _ref = &a;
2982 \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
2983 \\ break :x _ref.*;
2984 \\ }));
17882985 \\}
17892986 });
17902987
1791 cases.add("switch on int",
1792 \\int switch_fn(int i) {
1793 \\ int res = 0;
1794 \\ switch (i) {
1795 \\ case 0:
1796 \\ res = 1;
1797 \\ case 1:
1798 \\ res = 2;
1799 \\ default:
1800 \\ res = 3 * i;
1801 \\ break;
1802 \\ case 2:
1803 \\ res = 5;
1804 \\ }
2988 cases.addC("post increment/decrement",
2989 \\void foo(void) {
2990 \\ int i = 0;
2991 \\ unsigned u = 0;
2992 \\ i++;
2993 \\ i--;
2994 \\ u++;
2995 \\ u--;
2996 \\ i = i++;
2997 \\ i = i--;
2998 \\ u = u++;
2999 \\ u = u--;
18053000 \\}
18063001 , &[_][]const u8{
1807 \\pub fn switch_fn(i: c_int) c_int {
1808 \\ var res: c_int = 0;
1809 \\ __switch: {
1810 \\ __case_2: {
1811 \\ __default: {
1812 \\ __case_1: {
1813 \\ __case_0: {
1814 \\ switch (i) {
1815 \\ 0 => break :__case_0,
1816 \\ 1 => break :__case_1,
1817 \\ else => break :__default,
1818 \\ 2 => break :__case_2,
1819 \\ }
1820 \\ }
1821 \\ res = 1;
1822 \\ }
1823 \\ res = 2;
1824 \\ }
1825 \\ res = (3 * i);
1826 \\ break :__switch;
1827 \\ }
1828 \\ res = 5;
1829 \\ }
3002 \\pub export fn foo() void {
3003 \\ var i: c_int = 0;
3004 \\ var u: c_uint = @as(c_uint, 0);
3005 \\ i += 1;
3006 \\ i -= 1;
3007 \\ u +%= 1;
3008 \\ u -%= 1;
3009 \\ i = (x: {
3010 \\ const _ref = &i;
3011 \\ const _tmp = _ref.*;
3012 \\ _ref.* += 1;
3013 \\ break :x _tmp;
3014 \\ });
3015 \\ i = (x: {
3016 \\ const _ref = &i;
3017 \\ const _tmp = _ref.*;
3018 \\ _ref.* -= 1;
3019 \\ break :x _tmp;
3020 \\ });
3021 \\ u = (x: {
3022 \\ const _ref = &u;
3023 \\ const _tmp = _ref.*;
3024 \\ _ref.* +%= 1;
3025 \\ break :x _tmp;
3026 \\ });
3027 \\ u = (x: {
3028 \\ const _ref = &u;
3029 \\ const _tmp = _ref.*;
3030 \\ _ref.* -%= 1;
3031 \\ break :x _tmp;
3032 \\ });
18303033 \\}
18313034 });
18323035
......@@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18853088 \\}
18863089 });
18873090
1888 cases.addC("pointer conversion with different alignment",
1889 \\void test_ptr_cast() {
1890 \\ void *p;
1891 \\ {
1892 \\ char *to_char = (char *)p;
1893 \\ short *to_short = (short *)p;
1894 \\ int *to_int = (int *)p;
1895 \\ long long *to_longlong = (long long *)p;
1896 \\ }
1897 \\ {
1898 \\ char *to_char = p;
1899 \\ short *to_short = p;
1900 \\ int *to_int = p;
1901 \\ long long *to_longlong = p;
1902 \\ }
1903 \\}
1904 , &[_][]const u8{
1905 \\pub export fn test_ptr_cast() void {
1906 \\ var p: ?*c_void = undefined;
1907 \\ {
1908 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
1909 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
1910 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
1911 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
1912 \\ }
1913 \\ {
1914 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
1915 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
1916 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
1917 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
1918 \\ }
1919 \\}
1920 });
1921
1922 cases.addC("escape sequences",
1923 \\const char *escapes() {
1924 \\char a = '\'',
1925 \\ b = '\\',
1926 \\ c = '\a',
1927 \\ d = '\b',
1928 \\ e = '\f',
1929 \\ f = '\n',
1930 \\ g = '\r',
1931 \\ h = '\t',
1932 \\ i = '\v',
1933 \\ j = '\0',
1934 \\ k = '\"';
1935 \\ return "\'\\\a\b\f\n\r\t\v\0\"";
3091 cases.addC("function call",
3092 \\static void bar(void) { }
3093 \\void foo(int *(baz)(void)) {
3094 \\ bar();
3095 \\ baz();
19363096 \\}
1937 \\
19383097 , &[_][]const u8{
1939 \\pub export fn escapes() [*c]const u8 {
1940 \\ var a: u8 = @as(u8, '\'');
1941 \\ var b: u8 = @as(u8, '\\');
1942 \\ var c: u8 = @as(u8, '\x07');
1943 \\ var d: u8 = @as(u8, '\x08');
1944 \\ var e: u8 = @as(u8, '\x0c');
1945 \\ var f: u8 = @as(u8, '\n');
1946 \\ var g: u8 = @as(u8, '\r');
1947 \\ var h: u8 = @as(u8, '\t');
1948 \\ var i: u8 = @as(u8, '\x0b');
1949 \\ var j: u8 = @as(u8, '\x00');
1950 \\ var k: u8 = @as(u8, '\"');
1951 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
3098 \\pub fn bar() void {}
3099 \\pub export fn foo(baz: ?extern fn () [*c]c_int) void {
3100 \\ bar();
3101 \\ _ = baz.?();
19523102 \\}
1953 \\
19543103 });
19553104
1956 if (builtin.os != builtin.Os.windows) {
1957 // sysv_abi not currently supported on windows
1958 cases.add("Macro qualified functions",
1959 \\void __attribute__((sysv_abi)) foo(void);
1960 , &[_][]const u8{
1961 \\pub extern fn foo() void;
1962 });
1963 }
1964
1965 /////////////// Cases for only stage1 because stage2 behavior is better ////////////////
1966 cases.addC("Parameterless function prototypes",
1967 \\void foo() {}
1968 \\void bar(void) {}
3105 cases.add("macro defines string literal with hex",
3106 \\#define FOO "aoeu\xab derp"
3107 \\#define FOO2 "aoeu\x0007a derp"
3108 \\#define FOO_CHAR '\xfF'
19693109 , &[_][]const u8{
1970 \\pub export fn foo() void {}
1971 \\pub export fn bar() void {}
3110 \\pub const FOO = "aoeu\xab derp";
3111 ,
3112 \\pub const FOO2 = "aoeuz derp";
3113 ,
3114 \\pub const FOO_CHAR = 255;
19723115 });
19733116
1974 cases.add("#define a char literal",
1975 \\#define A_CHAR 'a'
3117 cases.add("macro defines string literal with octal",
3118 \\#define FOO "aoeu\023 derp"
3119 \\#define FOO2 "aoeu\0234 derp"
3120 \\#define FOO_CHAR '\077'
19763121 , &[_][]const u8{
1977 \\pub const A_CHAR = 97;
3122 \\pub const FOO = "aoeu\x13 derp";
3123 ,
3124 \\pub const FOO2 = "aoeu\x134 derp";
3125 ,
3126 \\pub const FOO_CHAR = 63;
19783127 });
19793128
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
3129 cases.add("enums",
3130 \\enum Foo {
3131 \\ FooA,
3132 \\ FooB,
3133 \\ Foo1,
3134 \\};
19863135 , &[_][]const u8{
1987 \\pub extern var fn_ptr: ?extern fn () void;
3136 \\pub const enum_Foo = extern enum {
3137 \\ A,
3138 \\ B,
3139 \\ @"1",
3140 \\};
19883141 ,
1989 \\pub inline fn foo() void {
1990 \\ return fn_ptr.?();
1991 \\}
3142 \\pub const FooA = enum_Foo.A;
19923143 ,
1993 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
3144 \\pub const FooB = enum_Foo.B;
19943145 ,
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);
3146 \\pub const Foo1 = enum_Foo.@"1";
3147 ,
3148 \\pub const Foo = enum_Foo;
20453149 });
20463150
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;
3151 cases.add("enums",
3152 \\enum Foo {
3153 \\ FooA = 2,
3154 \\ FooB = 5,
3155 \\ Foo1,
20563156 \\};
2057 \\extern union OpenGLProcs glProcs;
2058 \\#define glClearUnion glProcs.gl.Clear
2059 \\#define glClearPFN PFNGLCLEARPROC
20603157 , &[_][]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 \\ },
3158 \\pub const enum_Foo = extern enum {
3159 \\ A = 2,
3160 \\ B = 5,
3161 \\ @"1" = 6,
20723162 \\};
20733163 ,
2074 \\pub extern var glProcs: union_OpenGLProcs;
3164 \\pub const FooA = enum_Foo.A;
20753165 ,
2076 \\pub const glClearPFN = PFNGLCLEARPROC;
3166 \\pub const FooB = enum_Foo.B;
20773167 ,
2078 \\pub inline fn glClearUnion(arg0: GLbitfield) void {
2079 \\ return glProcs.gl.Clear.?(arg0);
2080 \\}
3168 \\pub const Foo1 = enum_Foo.@"1";
20813169 ,
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);
3170 \\pub const Foo = enum_Foo;
20893171 });
20903172}