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(...@@ -582,7 +582,9 @@ pub fn formatAsciiChar(
582 comptime Errors: type,582 comptime Errors: type,
583 output: fn (@TypeOf(context), []const u8) Errors!void,583 output: fn (@TypeOf(context), []const u8) Errors!void,
584) Errors!void {584) 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});
586}588}
587589
588pub fn formatBuf(590pub fn formatBuf(
lib/std/zig/ast.zig+16-16
...@@ -1431,13 +1431,13 @@ pub const Node = struct {...@@ -1431,13 +1431,13 @@ pub const Node = struct {
1431 AssignBitShiftRight,1431 AssignBitShiftRight,
1432 AssignBitXor,1432 AssignBitXor,
1433 AssignDiv,1433 AssignDiv,
1434 AssignMinus,1434 AssignSub,
1435 AssignMinusWrap,1435 AssignSubWrap,
1436 AssignMod,1436 AssignMod,
1437 AssignPlus,1437 AssignAdd,
1438 AssignPlusWrap,1438 AssignAddWrap,
1439 AssignTimes,1439 AssignMul,
1440 AssignTimesWarp,1440 AssignMulWrap,
1441 BangEqual,1441 BangEqual,
1442 BitAnd,1442 BitAnd,
1443 BitOr,1443 BitOr,
...@@ -1456,8 +1456,8 @@ pub const Node = struct {...@@ -1456,8 +1456,8 @@ pub const Node = struct {
1456 LessThan,1456 LessThan,
1457 MergeErrorSets,1457 MergeErrorSets,
1458 Mod,1458 Mod,
1459 Mult,1459 Mul,
1460 MultWrap,1460 MulWrap,
1461 Period,1461 Period,
1462 Range,1462 Range,
1463 Sub,1463 Sub,
...@@ -1490,13 +1490,13 @@ pub const Node = struct {...@@ -1490,13 +1490,13 @@ pub const Node = struct {
1490 Op.AssignBitShiftRight,1490 Op.AssignBitShiftRight,
1491 Op.AssignBitXor,1491 Op.AssignBitXor,
1492 Op.AssignDiv,1492 Op.AssignDiv,
1493 Op.AssignMinus,1493 Op.AssignSub,
1494 Op.AssignMinusWrap,1494 Op.AssignSubWrap,
1495 Op.AssignMod,1495 Op.AssignMod,
1496 Op.AssignPlus,1496 Op.AssignAdd,
1497 Op.AssignPlusWrap,1497 Op.AssignAddWrap,
1498 Op.AssignTimes,1498 Op.AssignMul,
1499 Op.AssignTimesWarp,1499 Op.AssignMulWrap,
1500 Op.BangEqual,1500 Op.BangEqual,
1501 Op.BitAnd,1501 Op.BitAnd,
1502 Op.BitOr,1502 Op.BitOr,
...@@ -1514,8 +1514,8 @@ pub const Node = struct {...@@ -1514,8 +1514,8 @@ pub const Node = struct {
1514 Op.LessThan,1514 Op.LessThan,
1515 Op.MergeErrorSets,1515 Op.MergeErrorSets,
1516 Op.Mod,1516 Op.Mod,
1517 Op.Mult,1517 Op.Mul,
1518 Op.MultWrap,1518 Op.MulWrap,
1519 Op.Period,1519 Op.Period,
1520 Op.Range,1520 Op.Range,
1521 Op.Sub,1521 Op.Sub,
lib/std/zig/parse.zig+8-8
...@@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
19811981
1982 const token = nextToken(it);1982 const token = nextToken(it);
1983 const op = switch (token.ptr.id) {1983 const op = switch (token.ptr.id) {
1984 .AsteriskEqual => Op{ .AssignTimes = {} },1984 .AsteriskEqual => Op{ .AssignMul = {} },
1985 .SlashEqual => Op{ .AssignDiv = {} },1985 .SlashEqual => Op{ .AssignDiv = {} },
1986 .PercentEqual => Op{ .AssignMod = {} },1986 .PercentEqual => Op{ .AssignMod = {} },
1987 .PlusEqual => Op{ .AssignPlus = {} },1987 .PlusEqual => Op{ .AssignAdd = {} },
1988 .MinusEqual => Op{ .AssignMinus = {} },1988 .MinusEqual => Op{ .AssignSub = {} },
1989 .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },1989 .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },
1990 .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },1990 .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },
1991 .AmpersandEqual => Op{ .AssignBitAnd = {} },1991 .AmpersandEqual => Op{ .AssignBitAnd = {} },
1992 .CaretEqual => Op{ .AssignBitXor = {} },1992 .CaretEqual => Op{ .AssignBitXor = {} },
1993 .PipeEqual => Op{ .AssignBitOr = {} },1993 .PipeEqual => Op{ .AssignBitOr = {} },
1994 .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} },1994 .AsteriskPercentEqual => Op{ .AssignMulWrap = {} },
1995 .PlusPercentEqual => Op{ .AssignPlusWrap = {} },1995 .PlusPercentEqual => Op{ .AssignAddWrap = {} },
1996 .MinusPercentEqual => Op{ .AssignMinusWrap = {} },1996 .MinusPercentEqual => Op{ .AssignSubWrap = {} },
1997 .Equal => Op{ .Assign = {} },1997 .Equal => Op{ .Assign = {} },
1998 else => {1998 else => {
1999 putBackToken(it, token.index);1999 putBackToken(it, token.index);
...@@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2120 const token = nextToken(it);2120 const token = nextToken(it);
2121 const op = switch (token.ptr.id) {2121 const op = switch (token.ptr.id) {
2122 .PipePipe => ops{ .BoolOr = {} },2122 .PipePipe => ops{ .BoolOr = {} },
2123 .Asterisk => ops{ .Mult = {} },2123 .Asterisk => ops{ .Mul = {} },
2124 .Slash => ops{ .Div = {} },2124 .Slash => ops{ .Div = {} },
2125 .Percent => ops{ .Mod = {} },2125 .Percent => ops{ .Mod = {} },
2126 .AsteriskAsterisk => ops{ .ArrayMult = {} },2126 .AsteriskAsterisk => ops{ .ArrayMult = {} },
2127 .AsteriskPercent => ops{ .MultWrap = {} },2127 .AsteriskPercent => ops{ .MulWrap = {} },
2128 else => {2128 else => {
2129 putBackToken(it, token.index);2129 putBackToken(it, token.index);
2130 return null;2130 return null;
lib/std/zig/render.zig+1-1
...@@ -1635,7 +1635,7 @@ fn renderExpression(...@@ -1635,7 +1635,7 @@ fn renderExpression(
1635 .If => {1635 .If => {
1636 const if_node = @fieldParentPtr(ast.Node.If, "base", base);1636 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);
1639 const rparen = tree.nextToken(if_node.condition.lastToken());1639 const rparen = tree.nextToken(if_node.condition.lastToken());
16401640
1641 try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if1641 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 {...@@ -27,6 +27,10 @@ pub const CToken = struct {
27 Lt,27 Lt,
28 Comma,28 Comma,
29 Fn,29 Fn,
30 Arrow,
31 LBrace,
32 RBrace,
33 Pipe,
30 };34 };
3135
32 pub const NumLitSuffix = enum {36 pub const NumLitSuffix = enum {
...@@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken {...@@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken {
71 }75 }
72 } else return tok;76 } else return tok;
73 var bytes = try allocator.alloc(u8, tok.bytes.len * 2);77 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;
75 var i: usize = 0;84 var i: usize = 0;
85 var count: u8 = 0;
86 var num: u8 = 0;
76 for (tok.bytes) |c| {87 for (tok.bytes) |c| {
77 if (escape) {88 switch (state) {
78 switch (c) {89 .Escape => {
79 'n', 'r', 't', '\\', '\'', '\"', 'x' => {90 switch (c) {
80 bytes[i] = c;91 'n', 'r', 't', '\\', '\'', '\"' => {
81 },92 bytes[i] = c;
82 'a' => {93 },
83 bytes[i] = 'x';94 '0'...'7' => {
84 i += 1;95 count += 1;
85 bytes[i] = '0';96 num += c - '0';
86 i += 1;97 state = .Octal;
87 bytes[i] = '7';98 bytes[i] = 'x';
88 },99 },
89 'b' => {100 'x' => {
90 bytes[i] = 'x';101 state = .Hex;
91 i += 1;102 bytes[i] = 'x';
92 bytes[i] = '0';103 },
93 i += 1;104 'a' => {
94 bytes[i] = '8';105 bytes[i] = 'x';
95 },106 i += 1;
96 'f' => {107 bytes[i] = '0';
97 bytes[i] = 'x';108 i += 1;
98 i += 1;109 bytes[i] = '7';
99 bytes[i] = '0';110 },
100 i += 1;111 'b' => {
101 bytes[i] = 'C';112 bytes[i] = 'x';
102 },113 i += 1;
103 'v' => {114 bytes[i] = '0';
104 bytes[i] = 'x';115 i += 1;
105 i += 1;116 bytes[i] = '8';
106 bytes[i] = '0';117 },
107 i += 1;118 'f' => {
108 bytes[i] = 'B';119 bytes[i] = 'x';
109 },120 i += 1;
110 '?' => {121 bytes[i] = '0';
111 i -= 1;122 i += 1;
112 bytes[i] = '?';123 bytes[i] = 'C';
113 },124 },
114 'u', 'U' => {125 'v' => {
115 // TODO unicode escape sequences126 bytes[i] = 'x';
116 return error.TokenizingFailed;127 i += 1;
117 },128 bytes[i] = '0';
118 '0'...'7' => {129 i += 1;
119 // TODO octal escape sequences130 bytes[i] = 'B';
120 return error.TokenizingFailed;131 },
121 },132 '?' => {
122 else => {133 i -= 1;
123 // unknown escape sequence134 bytes[i] = '?';
124 return error.TokenizingFailed;135 },
125 },136 'u', 'U' => {
126 }137 // TODO unicode escape sequences
127 i += 1;138 return error.TokenizingFailed;
128 escape = false;139 },
129 } else {140 else => {
130 if (c == '\\') {141 // unknown escape sequence
131 escape = true;142 return error.TokenizingFailed;
132 }143 },
133 bytes[i] = c;144 }
134 i += 1;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 },
135 }198 }
136 }199 }
200 if (state == .Hex or state == .Octal)
201 i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2});
137 return CToken{202 return CToken{
138 .id = tok.id,203 .id = tok.id,
139 .bytes = bytes[0..i],204 .bytes = bytes[0..i],
...@@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
164 NumLitIntSuffixL,229 NumLitIntSuffixL,
165 NumLitIntSuffixLL,230 NumLitIntSuffixLL,
166 NumLitIntSuffixUL,231 NumLitIntSuffixUL,
232 Minus,
233 Done,
167 } = .Start;234 } = .Start;
168235
169 var result = CToken{236 var result = CToken{
...@@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
178 const c = chars[i.*];245 const c = chars[i.*];
179 if (c == 0) {246 if (c == 0) {
180 switch (state) {247 switch (state) {
181 .Start => {
182 return result;
183 },
184 .Identifier,248 .Identifier,
185 .Decimal,249 .Decimal,
186 .Hex,250 .Hex,
...@@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
193 result.bytes = chars[begin_index..i.*];257 result.bytes = chars[begin_index..i.*];
194 return result;258 return result;
195 },259 },
260 .Start,
261 .Minus,
262 .Done,
196 .NumLitIntSuffixU,263 .NumLitIntSuffixU,
197 .NumLitIntSuffixL,264 .NumLitIntSuffixL,
198 .NumLitIntSuffixUL,265 .NumLitIntSuffixUL,
...@@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
212 => return error.TokenizingFailed,279 => return error.TokenizingFailed,
213 }280 }
214 }281 }
215 i.* += 1;
216 switch (state) {282 switch (state) {
217 .Start => {283 .Start => {
218 switch (c) {284 switch (c) {
...@@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
220 '\'' => {286 '\'' => {
221 state = .CharLit;287 state = .CharLit;
222 result.id = .CharLit;288 result.id = .CharLit;
223 begin_index = i.* - 1;289 begin_index = i.*;
224 },290 },
225 '\"' => {291 '\"' => {
226 state = .String;292 state = .String;
227 result.id = .StrLit;293 result.id = .StrLit;
228 begin_index = i.* - 1;294 begin_index = i.*;
229 },295 },
230 '/' => {296 '/' => {
231 state = .OpenComment;297 state = .OpenComment;
...@@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
239 'a'...'z', 'A'...'Z', '_' => {305 'a'...'z', 'A'...'Z', '_' => {
240 state = .Identifier;306 state = .Identifier;
241 result.id = .Identifier;307 result.id = .Identifier;
242 begin_index = i.* - 1;308 begin_index = i.*;
243 },309 },
244 '1'...'9' => {310 '1'...'9' => {
245 state = .Decimal;311 state = .Decimal;
246 result.id = .NumLitInt;312 result.id = .NumLitInt;
247 begin_index = i.* - 1;313 begin_index = i.*;
248 },314 },
249 '0' => {315 '0' => {
250 state = .GotZero;316 state = .GotZero;
251 result.id = .NumLitInt;317 result.id = .NumLitInt;
252 begin_index = i.* - 1;318 begin_index = i.*;
253 },319 },
254 '.' => {320 '.' => {
255 result.id = .Dot;321 result.id = .Dot;
256 return result;322 state = .Done;
257 },323 },
258 '<' => {324 '<' => {
259 result.id = .Lt;325 result.id = .Lt;
...@@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
261 },327 },
262 '(' => {328 '(' => {
263 result.id = .LParen;329 result.id = .LParen;
264 return result;330 state = .Done;
265 },331 },
266 ')' => {332 ')' => {
267 result.id = .RParen;333 result.id = .RParen;
268 return result;334 state = .Done;
269 },335 },
270 '*' => {336 '*' => {
271 result.id = .Asterisk;337 result.id = .Asterisk;
272 return result;338 state = .Done;
273 },339 },
274 '-' => {340 '-' => {
341 state = .Minus;
275 result.id = .Minus;342 result.id = .Minus;
276 return result;
277 },343 },
278 '!' => {344 '!' => {
279 result.id = .Bang;345 result.id = .Bang;
280 return result;346 state = .Done;
281 },347 },
282 '~' => {348 '~' => {
283 result.id = .Tilde;349 result.id = .Tilde;
284 return result;350 state = .Done;
285 },351 },
286 ',' => {352 ',' => {
287 result.id = .Comma;353 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;
289 },367 },
290 else => return error.TokenizingFailed,368 else => return error.TokenizingFailed,
291 }369 }
292 },370 },
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 },
293 .GotLt => {383 .GotLt => {
294 switch (c) {384 switch (c) {
295 '<' => {385 '<' => {
296 result.id = .Shl;386 result.id = .Shl;
297 return result;387 state = .Done;
298 },388 },
299 else => {389 else => {
300 return result;390 return result;
...@@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
310 'f',400 'f',
311 'F',401 'F',
312 => {402 => {
313 i.* -= 1;
314 result.num_lit_suffix = .F;403 result.num_lit_suffix = .F;
315 result.bytes = chars[begin_index..i.*];404 result.bytes = chars[begin_index..i.*];
316 return result;405 state = .Done;
317 },406 },
318 'l', 'L' => {407 'l', 'L' => {
319 i.* -= 1;
320 result.num_lit_suffix = .L;408 result.num_lit_suffix = .L;
321 result.bytes = chars[begin_index..i.*];409 result.bytes = chars[begin_index..i.*];
322 return result;410 state = .Done;
323 },411 },
324 else => {412 else => {
325 i.* -= 1;
326 result.bytes = chars[begin_index..i.*];413 result.bytes = chars[begin_index..i.*];
327 return result;414 return result;
328 },415 },
...@@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
352 '0'...'9' => {},439 '0'...'9' => {},
353 'f', 'F' => {440 'f', 'F' => {
354 result.num_lit_suffix = .F;441 result.num_lit_suffix = .F;
355 result.bytes = chars[begin_index .. i.* - 1];442 result.bytes = chars[begin_index..i.*];
356 return result;443 state = .Done;
357 },444 },
358 'l', 'L' => {445 'l', 'L' => {
359 result.num_lit_suffix = .L;446 result.num_lit_suffix = .L;
360 result.bytes = chars[begin_index .. i.* - 1];447 result.bytes = chars[begin_index..i.*];
361 return result;448 state = .Done;
362 },449 },
363 else => {450 else => {
364 i.* -= 1;
365 result.bytes = chars[begin_index..i.*];451 result.bytes = chars[begin_index..i.*];
366 return result;452 return result;
367 },453 },
...@@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
374 'u', 'U' => {460 'u', 'U' => {
375 state = .NumLitIntSuffixU;461 state = .NumLitIntSuffixU;
376 result.num_lit_suffix = .U;462 result.num_lit_suffix = .U;
377 result.bytes = chars[begin_index .. i.* - 1];463 result.bytes = chars[begin_index..i.*];
378 },464 },
379 'l', 'L' => {465 'l', 'L' => {
380 state = .NumLitIntSuffixL;466 state = .NumLitIntSuffixL;
381 result.num_lit_suffix = .L;467 result.num_lit_suffix = .L;
382 result.bytes = chars[begin_index .. i.* - 1];468 result.bytes = chars[begin_index..i.*];
383 },469 },
384 '.' => {470 '.' => {
385 result.id = .NumLitFloat;471 result.id = .NumLitFloat;
386 state = .Float;472 state = .Float;
387 },473 },
388 else => {474 else => {
389 i.* -= 1;
390 result.bytes = chars[begin_index..i.*];475 result.bytes = chars[begin_index..i.*];
391 return result;476 return result;
392 },477 },
...@@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
407 'u', 'U' => {492 'u', 'U' => {
408 state = .NumLitIntSuffixU;493 state = .NumLitIntSuffixU;
409 result.num_lit_suffix = .U;494 result.num_lit_suffix = .U;
410 result.bytes = chars[begin_index .. i.* - 1];495 result.bytes = chars[begin_index..i.*];
411 },496 },
412 'l', 'L' => {497 'l', 'L' => {
413 state = .NumLitIntSuffixL;498 state = .NumLitIntSuffixL;
414 result.num_lit_suffix = .L;499 result.num_lit_suffix = .L;
415 result.bytes = chars[begin_index .. i.* - 1];500 result.bytes = chars[begin_index..i.*];
416 },501 },
417 else => {502 else => {
418 i.* -= 1;503 i.* -= 1;
...@@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
425 '0'...'7' => {},510 '0'...'7' => {},
426 '8', '9' => return error.TokenizingFailed,511 '8', '9' => return error.TokenizingFailed,
427 else => {512 else => {
428 i.* -= 1;
429 result.bytes = chars[begin_index..i.*];513 result.bytes = chars[begin_index..i.*];
430 return result;514 return result;
431 },515 },
...@@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
438 // marks the number literal as unsigned522 // marks the number literal as unsigned
439 state = .NumLitIntSuffixU;523 state = .NumLitIntSuffixU;
440 result.num_lit_suffix = .U;524 result.num_lit_suffix = .U;
441 result.bytes = chars[begin_index .. i.* - 1];525 result.bytes = chars[begin_index..i.*];
442 },526 },
443 'l', 'L' => {527 'l', 'L' => {
444 // marks the number literal as long528 // marks the number literal as long
445 state = .NumLitIntSuffixL;529 state = .NumLitIntSuffixL;
446 result.num_lit_suffix = .L;530 result.num_lit_suffix = .L;
447 result.bytes = chars[begin_index .. i.* - 1];531 result.bytes = chars[begin_index..i.*];
448 },532 },
449 else => {533 else => {
450 i.* -= 1;
451 result.bytes = chars[begin_index..i.*];534 result.bytes = chars[begin_index..i.*];
452 return result;535 return result;
453 },536 },
...@@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
461 // marks the number literal as unsigned544 // marks the number literal as unsigned
462 state = .NumLitIntSuffixU;545 state = .NumLitIntSuffixU;
463 result.num_lit_suffix = .U;546 result.num_lit_suffix = .U;
464 result.bytes = chars[begin_index .. i.* - 1];547 result.bytes = chars[begin_index..i.*];
465 },548 },
466 'l', 'L' => {549 'l', 'L' => {
467 // marks the number literal as long550 // marks the number literal as long
468 state = .NumLitIntSuffixL;551 state = .NumLitIntSuffixL;
469 result.num_lit_suffix = .L;552 result.num_lit_suffix = .L;
470 result.bytes = chars[begin_index .. i.* - 1];553 result.bytes = chars[begin_index..i.*];
471 },554 },
472 else => {555 else => {
473 i.* -= 1;
474 result.bytes = chars[begin_index..i.*];556 result.bytes = chars[begin_index..i.*];
475 return result;557 return result;
476 },558 },
...@@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
483 state = .NumLitIntSuffixUL;565 state = .NumLitIntSuffixUL;
484 },566 },
485 else => {567 else => {
486 i.* -= 1;
487 return result;568 return result;
488 },569 },
489 }570 }
...@@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
496 },577 },
497 'u', 'U' => {578 'u', 'U' => {
498 result.num_lit_suffix = .LU;579 result.num_lit_suffix = .LU;
499 return result;580 state = .Done;
500 },581 },
501 else => {582 else => {
502 i.* -= 1;
503 return result;583 return result;
504 },584 },
505 }585 }
...@@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
508 switch (c) {588 switch (c) {
509 'u', 'U' => {589 'u', 'U' => {
510 result.num_lit_suffix = .LLU;590 result.num_lit_suffix = .LLU;
511 return result;591 state = .Done;
512 },592 },
513 else => {593 else => {
514 i.* -= 1;
515 return result;594 return result;
516 },595 },
517 }596 }
...@@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
520 switch (c) {599 switch (c) {
521 'l', 'L' => {600 'l', 'L' => {
522 result.num_lit_suffix = .LLU;601 result.num_lit_suffix = .LLU;
523 return result;602 state = .Done;
524 },603 },
525 else => {604 else => {
526 i.* -= 1;
527 return result;605 return result;
528 },606 },
529 }607 }
...@@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
532 switch (c) {610 switch (c) {
533 '_', 'a'...'z', 'A'...'Z', '0'...'9' => {},611 '_', 'a'...'z', 'A'...'Z', '0'...'9' => {},
534 else => {612 else => {
535 i.* -= 1;
536 result.bytes = chars[begin_index..i.*];613 result.bytes = chars[begin_index..i.*];
537 return result;614 return result;
538 },615 },
539 }616 }
540 },617 },
541 .String => { // TODO char escapes618 .String => {
542 switch (c) {619 switch (c) {
543 '\"' => {620 '\"' => {
544 result.bytes = chars[begin_index..i.*];621 result.bytes = chars[begin_index .. i.* + 1];
545 return result;622 state = .Done;
546 },623 },
547 else => {},624 else => {},
548 }625 }
...@@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
550 .CharLit => {627 .CharLit => {
551 switch (c) {628 switch (c) {
552 '\'' => {629 '\'' => {
553 result.bytes = chars[begin_index..i.*];630 result.bytes = chars[begin_index .. i.* + 1];
554 return result;631 state = .Done;
555 },632 },
556 else => {},633 else => {},
557 }634 }
...@@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
566 },643 },
567 else => {644 else => {
568 result.id = .Slash;645 result.id = .Slash;
569 return result;646 state = .Done;
570 },647 },
571 }648 }
572 },649 },
...@@ -598,6 +675,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {...@@ -598,6 +675,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken {
598 }675 }
599 },676 },
600 }677 }
678 i.* += 1;
601 }679 }
602 unreachable;680 unreachable;
603}681}
...@@ -645,7 +723,7 @@ test "tokenize macro" {...@@ -645,7 +723,7 @@ test "tokenize macro" {
645 expect(it.next() == null);723 expect(it.next() == null);
646 tl.shrink(0);724 tl.shrink(0);
647725
648 const src5 = "FOO 0l";726 const src5 = "FOO 0ull";
649 try tokenizeCMacro(&tl, src5);727 try tokenizeCMacro(&tl, src5);
650 it = tl.iterator(0);728 it = tl.iterator(0);
651 expect(it.next().?.id == .Identifier);729 expect(it.next().?.id == .Identifier);
...@@ -654,3 +732,25 @@ test "tokenize macro" {...@@ -654,3 +732,25 @@ test "tokenize macro" {
654 expect(it.next() == null);732 expect(it.next() == null);
655 tl.shrink(0);733 tl.shrink(0);
656}734}
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();...@@ -76,6 +76,10 @@ pub const struct_ZigClangFunctionType = @OpaqueType();
76pub const struct_ZigClangPredefinedExpr = @OpaqueType();76pub const struct_ZigClangPredefinedExpr = @OpaqueType();
77pub const struct_ZigClangInitListExpr = @OpaqueType();77pub const struct_ZigClangInitListExpr = @OpaqueType();
78pub const ZigClangPreprocessingRecord = @OpaqueType();78pub const ZigClangPreprocessingRecord = @OpaqueType();
79pub const ZigClangFloatingLiteral = @OpaqueType();
80pub const ZigClangConstantExpr = @OpaqueType();
81pub const ZigClangCharacterLiteral = @OpaqueType();
82pub const ZigClangStmtExpr = @OpaqueType();
7983
80pub const ZigClangBO = extern enum {84pub const ZigClangBO = extern enum {
81 PtrMemD,85 PtrMemD,
...@@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum {...@@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum {
710 UTF32,714 UTF32,
711};715};
712716
717pub const ZigClangCharacterLiteral_CharacterKind = extern enum {
718 Ascii,
719 Wide,
720 UTF8,
721 UTF16,
722 UTF32,
723};
724
713pub const ZigClangRecordDecl_field_iterator = extern struct {725pub const ZigClangRecordDecl_field_iterator = extern struct {
714 opaque: *c_void,726 opaque: *c_void,
715};727};
...@@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum {...@@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum {
730 InclusionDirectiveKind,742 InclusionDirectiveKind,
731};743};
732744
745pub const ZigClangExpr_ConstExprUsage = extern enum {
746 EvaluateForCodeGen,
747 EvaluateForMangling,
748};
749
733pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;750pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
734pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;751pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
735pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;752pub 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...@@ -744,6 +761,8 @@ pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumTyp
744pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;761pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
745pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;762pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
746pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl;763pub 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;
747pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl;766pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl;
748pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl;767pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl;
749pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation;768pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation;
...@@ -791,16 +810,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList...@@ -791,16 +810,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList
791pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;810pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;
792pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint;811pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint;
793pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind;812pub 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;
795pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint;814pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint;
796pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint;815pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint;
797pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase;816pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase;
798pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool;817pub extern fn ZigClangAPSInt_isSigned(self: *const struct_ZigClangAPSInt) bool;
799pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool;818pub extern fn ZigClangAPSInt_isNegative(self: *const struct_ZigClangAPSInt) bool;
800pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt;819pub extern fn ZigClangAPSInt_negate(self: *const struct_ZigClangAPSInt) *const struct_ZigClangAPSInt;
801pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void;820pub extern fn ZigClangAPSInt_free(self: *const struct_ZigClangAPSInt) void;
802pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64;821pub extern fn ZigClangAPSInt_getRawData(self: *const struct_ZigClangAPSInt) [*:0]const u64;
803pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint;822pub extern fn ZigClangAPSInt_getNumWords(self: *const struct_ZigClangAPSInt) c_uint;
804823
805pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;824pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64;
806pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;825pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr;
...@@ -822,6 +841,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy...@@ -822,6 +841,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy
822pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool;841pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool;
823pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint;842pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint;
824pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType;843pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType;
844pub extern fn ZigClangFunctionProtoType_getReturnType(self: *const ZigClangFunctionProtoType) ZigClangQualType;
825845
826pub const ZigClangSourceLocation = struct_ZigClangSourceLocation;846pub const ZigClangSourceLocation = struct_ZigClangSourceLocation;
827pub const ZigClangQualType = struct_ZigClangQualType;847pub const ZigClangQualType = struct_ZigClangQualType;
...@@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple...@@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple
976pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType;996pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType;
977pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt;997pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt;
978pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl;998pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl;
999pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl;
9791000
980pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;1001pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
9811002
...@@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti...@@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti
1036pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8;1057pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8;
1037pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;1058pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;
1038pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation;1059pub 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;...@@ -8,6 +8,7 @@ const Token = std.zig.Token;
8usingnamespace @import("clang.zig");8usingnamespace @import("clang.zig");
9const ctok = @import("c_tokenizer.zig");9const ctok = @import("c_tokenizer.zig");
10const CToken = ctok.CToken;10const CToken = ctok.CToken;
11const mem = std.mem;
1112
12const CallingConvention = std.builtin.TypeInfo.CallingConvention;13const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1314
...@@ -47,35 +48,34 @@ const Scope = struct {...@@ -47,35 +48,34 @@ const Scope = struct {
47 Switch,48 Switch,
48 Block,49 Block,
49 Root,50 Root,
50 While,51 Condition,
51 FnDef,52 Loop,
52 Ref,
53 };53 };
5454
55 const Switch = struct {55 const Switch = struct {
56 base: Scope,56 base: Scope,
57 };57 pending_block: *ast.Node.Block,
5858 cases: *ast.Node.Switch.CaseList,
59 /// used when getting a member `a.b`59 has_default: bool = false,
60 const Ref = struct {
61 base: Scope,
62 };60 };
6361
64 const Block = struct {62 const Block = struct {
65 base: Scope,63 base: Scope,
66 block_node: *ast.Node.Block,64 block_node: *ast.Node.Block,
67 variables: AliasList,65 variables: AliasList,
66 label: ?[]const u8,
6867
69 /// Don't forget to set rbrace token later68 /// Don't forget to set rbrace token and block_node later
70 fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block {69 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block {
71 const block = try c.a().create(Block);70 const block = try c.a().create(Block);
72 block.* = .{71 block.* = .{
73 .base = .{72 .base = .{
74 .id = .Block,73 .id = .Block,
75 .parent = parent,74 .parent = parent,
76 },75 },
77 .block_node = block_node,76 .block_node = undefined,
78 .variables = AliasList.init(c.a()),77 .variables = AliasList.init(c.a()),
78 .label = label,
79 };79 };
80 return block;80 return block;
81 }81 }
...@@ -83,7 +83,7 @@ const Scope = struct {...@@ -83,7 +83,7 @@ const Scope = struct {
83 fn getAlias(scope: *Block, name: []const u8) ?[]const u8 {83 fn getAlias(scope: *Block, name: []const u8) ?[]const u8 {
84 var it = scope.variables.iterator(0);84 var it = scope.variables.iterator(0);
85 while (it.next()) |p| {85 while (it.next()) |p| {
86 if (std.mem.eql(u8, p.name, name))86 if (mem.eql(u8, p.name, name))
87 return p.alias;87 return p.alias;
88 }88 }
89 return scope.base.parent.?.getAlias(name);89 return scope.base.parent.?.getAlias(name);
...@@ -92,7 +92,7 @@ const Scope = struct {...@@ -92,7 +92,7 @@ const Scope = struct {
92 fn contains(scope: *Block, name: []const u8) bool {92 fn contains(scope: *Block, name: []const u8) bool {
93 var it = scope.variables.iterator(0);93 var it = scope.variables.iterator(0);
94 while (it.next()) |p| {94 while (it.next()) |p| {
95 if (std.mem.eql(u8, p.name, name))95 if (mem.eql(u8, p.name, name))
96 return true;96 return true;
97 }97 }
98 return scope.base.parent.?.contains(name);98 return scope.base.parent.?.contains(name);
...@@ -120,52 +120,23 @@ const Scope = struct {...@@ -120,52 +120,23 @@ const Scope = struct {
120 }120 }
121 };121 };
122122
123 const While = struct {123 fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block {
124 base: Scope,124 var scope = inner;
125 };125 while (true) {
126126 switch (scope.id) {
127 const FnDef = struct {127 .Root => unreachable,
128 base: Scope,128 .Block => return @fieldParentPtr(Block, "base", scope),
129 params: AliasList,129 .Condition => {
130130 // comma operator used
131 fn init(c: *Context) FnDef {131 return try Block.init(c, scope, "blk");
132 return .{
133 .base = .{
134 .id = .FnDef,
135 .parent = &c.global_scope.base,
136 },132 },
137 .params = AliasList.init(c.a()),133 else => scope = scope.parent.?,
138 };
139 }
140
141 fn getAlias(scope: *FnDef, name: []const u8) ?[]const u8 {
142 var it = scope.params.iterator(0);
143 while (it.next()) |p| {
144 if (std.mem.eql(u8, p.name, name))
145 return p.alias;
146 }134 }
147 return scope.base.parent.?.getAlias(name);
148 }
149
150 fn contains(scope: *FnDef, name: []const u8) bool {
151 var it = scope.params.iterator(0);
152 while (it.next()) |p| {
153 if (std.mem.eql(u8, p.name, name))
154 return true;
155 }
156 return scope.base.parent.?.contains(name);
157 }
158 };
159
160 fn findBlockScope(inner: *Scope) *Scope.Block {
161 var scope = inner;
162 while (true) : (scope = scope.parent orelse unreachable) {
163 if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope);
164 }135 }
165 }136 }
166137
167 fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 {138 fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 {
168 if (scope.contains(name)) {139 if (isZigPrimitiveType(name) or scope.contains(name)) {
169 return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() });140 return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() });
170 }141 }
171 return null;142 return null;
...@@ -174,22 +145,41 @@ const Scope = struct {...@@ -174,22 +145,41 @@ const Scope = struct {
174 fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 {145 fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 {
175 return switch (scope.id) {146 return switch (scope.id) {
176 .Root => null,147 .Root => null,
177 .Ref => null,
178 .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
179 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),148 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
180 else => @panic("TODO Scope.getAlias"),149 .Switch, .Loop, .Condition => scope.parent.?.getAlias(name),
181 };150 };
182 }151 }
183152
184 fn contains(scope: *Scope, name: []const u8) bool {153 fn contains(scope: *Scope, name: []const u8) bool {
185 return switch (scope.id) {154 return switch (scope.id) {
186 .Ref => false,
187 .Root => @fieldParentPtr(Root, "base", scope).contains(name),155 .Root => @fieldParentPtr(Root, "base", scope).contains(name),
188 .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
189 .Block => @fieldParentPtr(Block, "base", scope).contains(name),156 .Block => @fieldParentPtr(Block, "base", scope).contains(name),
190 else => @panic("TODO Scope.contains"),157 .Switch, .Loop, .Condition => scope.parent.?.contains(name),
191 };158 };
192 }159 }
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 }
193};183};
194184
195const Context = struct {185const Context = struct {
...@@ -200,7 +190,6 @@ const Context = struct {...@@ -200,7 +190,6 @@ const Context = struct {
200 decl_table: DeclTable,190 decl_table: DeclTable,
201 alias_list: AliasList,191 alias_list: AliasList,
202 global_scope: *Scope.Root,192 global_scope: *Scope.Root,
203 ptr_params: std.BufSet,
204 clang_context: *ZigClangASTContext,193 clang_context: *ZigClangASTContext,
205 mangle_count: u64 = 0,194 mangle_count: u64 = 0,
206195
...@@ -209,13 +198,13 @@ const Context = struct {...@@ -209,13 +198,13 @@ const Context = struct {
209 return c.mangle_count;198 return c.mangle_count;
210 }199 }
211200
212 fn a(c: *Context) *std.mem.Allocator {201 fn a(c: *Context) *mem.Allocator {
213 return &c.tree.arena_allocator.allocator;202 return &c.tree.arena_allocator.allocator;
214 }203 }
215204
216 /// Convert a null-terminated C string to a slice allocated in the arena205 /// Convert a null-terminated C string to a slice allocated in the arena
217 fn str(c: *Context, s: [*:0]const u8) ![]u8 {206 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));
219 }208 }
220209
221 /// Convert a clang source location to a file:line:column string210 /// Convert a clang source location to a file:line:column string
...@@ -231,7 +220,7 @@ const Context = struct {...@@ -231,7 +220,7 @@ const Context = struct {
231};220};
232221
233pub fn translate(222pub fn translate(
234 backing_allocator: *std.mem.Allocator,223 backing_allocator: *mem.Allocator,
235 args_begin: [*]?[*]const u8,224 args_begin: [*]?[*]const u8,
236 args_end: [*]?[*]const u8,225 args_end: [*]?[*]const u8,
237 errors: *[]ClangErrMsg,226 errors: *[]ClangErrMsg,
...@@ -286,7 +275,6 @@ pub fn translate(...@@ -286,7 +275,6 @@ pub fn translate(
286 .decl_table = DeclTable.init(arena),275 .decl_table = DeclTable.init(arena),
287 .alias_list = AliasList.init(arena),276 .alias_list = AliasList.init(arena),
288 .global_scope = try arena.create(Scope.Root),277 .global_scope = try arena.create(Scope.Root),
289 .ptr_params = std.BufSet.init(arena),
290 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,278 .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?,
291 };279 };
292 context.global_scope.* = Scope.Root.init(&context);280 context.global_scope.* = Scope.Root.init(&context);
...@@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {...@@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
333 return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));321 return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));
334 },322 },
335 .Typedef => {323 .Typedef => {
336 return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));324 _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
337 },325 },
338 .Enum => {326 .Enum => {
339 _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl));327 _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl));
340 },328 },
341 .Record => {329 .Record => {
342 return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));330 _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl));
343 },331 },
344 .Var => {332 .Var => {
345 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));333 return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl));
...@@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {...@@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
352}340}
353341
354fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {342fn 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);
357 const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl)));343 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);
359 const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl);347 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;
364 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);348 const has_body = ZigClangFunctionDecl_hasBody(fn_decl);
365 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);349 const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl);
366 const decl_ctx = FnDeclContext{350 const decl_ctx = FnDeclContext{
367 .fn_name = fn_name,351 .fn_name = fn_name,
368 .has_body = has_body,352 .has_body = has_body,
369 .storage_class = storage_class,353 .storage_class = storage_class,
370 .scope = &scope,
371 .is_export = switch (storage_class) {354 .is_export = switch (storage_class) {
372 .None => has_body,355 .None => has_body,
373 .Extern, .Static => false,356 .Extern, .Static => false,
...@@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
377 else => unreachable,360 else => unreachable,
378 },361 },
379 };362 };
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
380 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {372 const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
381 .FunctionProto => blk: {373 .FunctionProto => blk: {
382 const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type);374 const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type);
...@@ -396,7 +388,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -396,7 +388,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
396 error.OutOfMemory => |e| return e,388 error.OutOfMemory => |e| return e,
397 };389 };
398 },390 },
399 else => unreachable,391 else => return failDecl(c, fn_decl_loc, fn_name, "unable to resolve function type {}", .{ZigClangType_getTypeClass(fn_type)}),
400 };392 };
401393
402 if (!decl_ctx.has_body) {394 if (!decl_ctx.has_body) {
...@@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {...@@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
406398
407 // actual function definition with body399 // actual function definition with body
408 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);400 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) {
410 error.OutOfMemory => |e| return e,428 error.OutOfMemory => |e| return e,
411 error.UnsupportedTranslation,429 error.UnsupportedTranslation,
412 error.UnsupportedType,430 error.UnsupportedType,
413 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),431 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
414 };432 };
415 assert(body_node.id == .Block);433 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
416 proto_node.body_node = body_node;434 proto_node.body_node = &block_node.base;
417
418 return addTopLevelDecl(c, fn_name, &proto_node.base);435 return addTopLevelDecl(c, fn_name, &proto_node.base);
419}436}
420437
421fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {438fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
422 if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice439 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
423 const rp = makeRestorePoint(c);442 const rp = makeRestorePoint(c);
424 const visib_tok = try appendToken(c, .Keyword_pub, "pub");443 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
425444
...@@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
429 try appendToken(c, .Keyword_threadlocal, "threadlocal");448 try appendToken(c, .Keyword_threadlocal, "threadlocal");
430449
431 const scope = &c.global_scope.base;450 const scope = &c.global_scope.base;
432 const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl)));451
433 _ = try c.decl_table.put(@ptrToInt(var_decl), var_name);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;
434 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);455 const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
435456
436 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);457 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
...@@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
449 else470 else
450 try appendToken(c, .Keyword_var, "var");471 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
454 _ = try appendToken(c, .Colon, ":");475 _ = try appendToken(c, .Colon, ":");
455 const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) {476 const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) {
456 error.UnsupportedType => {477 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", .{});
458 },479 },
459 error.OutOfMemory => |e| return e,480 error.OutOfMemory => |e| return e,
460 };481 };
...@@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
469 error.UnsupportedTranslation,490 error.UnsupportedTranslation,
470 error.UnsupportedType,491 error.UnsupportedType,
471 => {492 => {
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", .{});
473 },494 },
474 error.OutOfMemory => |e| return e,495 error.OutOfMemory => |e| return e,
475 }496 }
476 else497 else
477 try transCreateNodeUndefinedLiteral(c);498 try transCreateNodeUndefinedLiteral(c);
478 } else if (storage_class != .Extern) {499 } 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", .{});
480 }501 }
481502
482 const node = try c.a().create(ast.Node.VarDecl);503 const node = try c.a().create(ast.Node.VarDecl);
...@@ -496,269 +517,538 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -496,269 +517,538 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
496 .init_node = init_node,517 .init_node = init_node,
497 .semicolon_token = try appendToken(c, .Semicolon, ";"),518 .semicolon_token = try appendToken(c, .Semicolon, ";"),
498 };519 };
499 return addTopLevelDecl(c, var_name, &node.base);520 return addTopLevelDecl(c, checked_name, &node.base);
500}521}
501522
502fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {523fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, builtin_name: []const u8) !*ast.Node {
503 if (c.decl_table.contains(524 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), builtin_name);
504 @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)),525 return transCreateNodeIdentifier(c, builtin_name);
505 )) return; // Avoid processing this decl twice526}
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
506 const rp = makeRestorePoint(c);531 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
510 const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));533 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
511 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name);560 _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name);
512 const name_tok = try appendIdentifier(c, typedef_name);561 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
513 const eq_tok = try appendToken(c, .Equal, "=");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
515 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);566 const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
516 const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);567 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) {
518 error.UnsupportedType => {569 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;
520 },572 },
521 error.OutOfMemory => |e| return e,573 error.OutOfMemory => |e| return e,
522 };574 };
523575 node.semicolon_token = try appendToken(c, .Semicolon, ";");
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 };
541 try addTopLevelDecl(c, typedef_name, &node.base);576 try addTopLevelDecl(c, typedef_name, &node.base);
577 return transCreateNodeIdentifier(c, typedef_name);
542}578}
543579
544fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void {580fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
545 if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice581 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|
546 const rp = makeRestorePoint(c);582 return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
547583 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
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});
556584
557 if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0)585 var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl)));
558 return;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");592 var container_kind_name: []const u8 = undefined;
561 const const_tok = try appendToken(c, .Keyword_const, "const");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
563 const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });605 const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
564 _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);606 _ = 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, "=");608 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
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, ";");
575609
576 const node = try c.a().create(ast.Node.VarDecl);610 node.eq_token = try appendToken(c, .Equal, "=");
577 node.* = ast.Node.VarDecl{611
578 .doc_comments = null,612 var semicolon: ast.TokenIndex = undefined;
579 .visib_token = visib_tok,613 node.init_node = blk: {
580 .thread_local_token = null,614 const rp = makeRestorePoint(c);
581 .name_token = name_tok,615 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
582 .eq_token = eq_tok,616 const opaque = try transCreateNodeOpaqueType(c);
583 .mut_token = const_tok,617 semicolon = try appendToken(c, .Semicolon, ";");
584 .comptime_token = null,618 break :blk opaque;
585 .extern_export_token = null,619 };
586 .lib_name = null,620
587 .type_node = null,621 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
588 .align_node = null,622 const container_tok = try appendToken(c, container_kind, container_kind_name);
589 .section_node = null,623 const lbrace_token = try appendToken(c, .LBrace, "{");
590 .init_node = init_node,624
591 .semicolon_token = semicolon_token,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;
592 };675 };
676 node.semicolon_token = semicolon;
593677
594 try addTopLevelDecl(c, name, &node.base);678 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);
596}682}
597683
598fn createAlias(c: *Context, alias: var) !void {684fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
599 const visib_tok = try appendToken(c, .Keyword_pub, "pub");685 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
600 const mut_tok = try appendToken(c, .Keyword_const, "const");686 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
601 const name_tok = try appendIdentifier(c, alias.alias);687 const rp = makeRestorePoint(c);
688 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
602689
603 const eq_tok = try appendToken(c, .Equal, "=");690 var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl)));
604 const init_node = try transCreateNodeIdentifier(c, alias.name);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);697 const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
607 node.* = ast.Node.VarDecl{698 _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
608 .doc_comments = null,699 const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
609 .visib_token = visib_tok,700 node.eq_token = try appendToken(c, .Equal, "=");
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}
625701
626const ResultUsed = enum {702 node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {
627 used,703 var pure_enum = true;
628 unused,704 var it = ZigClangEnumDecl_enumerator_begin(enum_def);
629};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 {714 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
632 l_value,715 const container_tok = try appendToken(c, .Keyword_enum, "enum");
633 r_value,
634};
635716
636fn transStmt(717 const container_node = try c.a().create(ast.Node.ContainerDecl);
637 rp: RestorePoint,718 container_node.* = .{
638 scope: *Scope,719 .layout_token = extern_tok,
639 stmt: *const ZigClangStmt,720 .kind_token = container_tok,
640 result_used: ResultUsed,721 .init_arg_expr = .None,
641 lrvalue: LRValue,722 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),
642) TransError!*ast.Node {723 .lbrace_token = undefined,
643 const sc = ZigClangStmt_getStmtClass(stmt);724 .rbrace_token = undefined,
644 switch (sc) {725 };
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}
668726
669fn transBinaryOperator(727 const int_type = ZigClangEnumDecl_getIntegerType(enum_decl);
670 rp: RestorePoint,728
671 scope: *Scope,729 // TODO only emit this tag type if the enum tag type is not the default.
672 stmt: *const ZigClangBinaryOperator,730 // I don't know what the default is, need to figure out how clang is deciding.
673 result_used: ResultUsed,731 // it appears to at least be different across gcc/msvc
674) TransError!*ast.Node {732 if (!isCBuiltinType(int_type, .UInt) and
675 const op = ZigClangBinaryOperator_getOpcode(stmt);733 !isCBuiltinType(int_type, .Int))
676 const qt = ZigClangBinaryOperator_getType(stmt);734 {
677 switch (op) {735 _ = try appendToken(c, .LParen, "(");
678 .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(736 container_node.init_arg_expr = .{
679 rp,737 .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
680 error.UnsupportedTranslation,738 error.UnsupportedType => {
681 ZigClangBinaryOperator_getBeginLoc(stmt),739 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
682 "TODO: handle more C binary operators: {}",740 return null;
683 .{op},741 },
684 ),742 else => |e| return e,
685 .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base,743 },
686 .Add => {744 };
687 const node = if (cIsUnsignedInteger(qt))745 _ = try appendToken(c, .RParen, ")");
688 try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)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..]
689 else759 else
690 try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);760 enum_val_name;
691 return maybeSuppressResult(rp, scope, result_used, node);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;
692 },850 },
693 .Sub => {851 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),
694 const node = if (cIsUnsignedInteger(qt))852 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
695 try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)853 .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)),
696 else854 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
697 try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);855 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
698 return maybeSuppressResult(rp, scope, result_used, node);856 .NullStmtClass => {
857 const block = try transCreateNodeBlock(rp.c, null);
858 block.rbrace = try appendToken(rp.c, .RBrace, "}");
859 return &block.base;
699 },860 },
700 .Mul => {861 .ContinueStmtClass => return try transCreateNodeContinue(rp.c),
701 const node = if (cIsUnsignedInteger(qt))862 .BreakStmtClass => return transBreak(rp, scope),
702 try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)863 .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)),
703 else864 .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const ZigClangFloatingLiteral, stmt), result_used),
704 try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);865 .ConditionalOperatorClass => return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used),
705 return maybeSuppressResult(rp, scope, result_used, node);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 }
706 },933 },
707 .Div => {934 .Div => {
708 if (!cIsUnsignedInteger(qt)) {935 if (!cIsUnsignedInteger(qt)) {
709 // signed integer division uses @divTrunc936 // signed integer division uses @divTrunc
710 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");937 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
711 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);938 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
712 try div_trunc_node.params.push(lhs);
713 _ = try appendToken(rp.c, .Comma, ",");939 _ = try appendToken(rp.c, .Comma, ",");
714 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);940 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
715 try div_trunc_node.params.push(rhs);941 try div_trunc_node.params.push(rhs);
716 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");942 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
717 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);943 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);
722 }944 }
723 },945 },
724 .Rem => {946 .Rem => {
725 if (!cIsUnsignedInteger(qt)) {947 if (!cIsUnsignedInteger(qt)) {
726 // signed integer division uses @rem948 // signed integer division uses @rem
727 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");949 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
728 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);950 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
729 try rem_node.params.push(lhs);
730 _ = try appendToken(rp.c, .Comma, ",");951 _ = try appendToken(rp.c, .Comma, ",");
731 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);952 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
732 try rem_node.params.push(rhs);953 try rem_node.params.push(rhs);
733 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");954 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
734 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);955 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;
735 } else {982 } else {
736 // unsigned/float division uses the operator983 op_token = try appendToken(rp.c, .Plus, "+");
737 const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);984 op_id = .Add;
738 return maybeSuppressResult(rp, scope, result_used, node);
739 }985 }
740 },986 },
741 .Shl,987 .Sub => {
742 .Shr,988 if (cIsUnsignedInteger(qt)) {
743 .LT,989 op_token = try appendToken(rp.c, .MinusPercent, "-%");
744 .GT,990 op_id = .SubWrap;
745 .LE,991 } else {
746 .GE,992 op_token = try appendToken(rp.c, .Minus, "-");
747 .EQ,993 op_id = .Sub;
748 .NE,994 }
749 .And,995 },
750 .Xor,996 .Mul => {
751 .Or,997 if (cIsUnsignedInteger(qt)) {
752 .LAnd,998 op_token = try appendToken(rp.c, .AsteriskPercent, "*%");
753 .LOr,999 op_id = .MulWrap;
754 .Comma,1000 } else {
755 => return revertAndWarn(1001 op_token = try appendToken(rp.c, .Asterisk, "*");
756 rp,1002 op_id = .Mul;
757 error.UnsupportedTranslation,1003 }
758 ZigClangBinaryOperator_getBeginLoc(stmt),1004 },
759 "TODO: handle more C binary operators: {}",1005 .Div => {
760 .{op},1006 // unsigned/float division uses the operator
761 ),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,
762 .MulAssign,1052 .MulAssign,
763 .DivAssign,1053 .DivAssign,
764 .RemAssign,1054 .RemAssign,
...@@ -772,6 +1062,9 @@ fn transBinaryOperator(...@@ -772,6 +1062,9 @@ fn transBinaryOperator(
772 => unreachable,1062 => unreachable,
773 else => unreachable,1063 else => unreachable,
774 }1064 }
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);
775}1068}
7761069
777fn transCompoundStmtInline(1070fn transCompoundStmtInline(
...@@ -790,11 +1083,11 @@ fn transCompoundStmtInline(...@@ -790,11 +1083,11 @@ fn transCompoundStmtInline(
790}1083}
7911084
792fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {1085fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
793 const block_node = try transCreateNodeBlock(rp.c, null);1086 const block_scope = try Scope.Block.init(rp.c, scope, null);
794 const block_scope = try Scope.Block.init(rp.c, scope, block_node);1087 block_scope.block_node = try transCreateNodeBlock(rp.c, null);
795 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node);1088 try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
796 block_node.rbrace = try appendToken(rp.c, .RBrace, "}");1089 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
797 return &block_node.base;1090 return &block_scope.block_node.base;
798}1091}
7991092
800fn transCStyleCastExprClass(1093fn transCStyleCastExprClass(
...@@ -818,7 +1111,7 @@ fn transCStyleCastExprClass(...@@ -818,7 +1111,7 @@ fn transCStyleCastExprClass(
8181111
819fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {1112fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node {
820 const c = rp.c;1113 const c = rp.c;
821 const block_scope = scope.findBlockScope();1114 const block_scope = scope.findBlockScope(c) catch unreachable;
8221115
823 var it = ZigClangDeclStmt_decl_begin(stmt);1116 var it = ZigClangDeclStmt_decl_begin(stmt);
824 const end_it = ZigClangDeclStmt_decl_end(stmt);1117 const end_it = ZigClangDeclStmt_decl_end(stmt);
...@@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)...@@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
832 else1125 else
833 try appendToken(c, .Keyword_threadlocal, "threadlocal");1126 try appendToken(c, .Keyword_threadlocal, "threadlocal");
834 const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);1127 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");
839 const name = try c.str(ZigClangDecl_getName_bytes_begin(1128 const name = try c.str(ZigClangDecl_getName_bytes_begin(
840 @ptrCast(*const ZigClangDecl, var_decl),1129 @ptrCast(*const ZigClangDecl, var_decl),
841 ));1130 ));
...@@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)...@@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
843 try block_scope.variables.push(.{ .name = name, .alias = a });1132 try block_scope.variables.push(.{ .name = name, .alias = a });
844 break :blk a;1133 break :blk a;
845 } else name;1134 } 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, ":");
849 const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt));1138 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, "=");1141 node.eq_token = try appendToken(c, .Equal, "=");
853 const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|1142 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
854 try transExpr(rp, scope, expr, .used, .r_value)1143 try transExpr(rp, scope, expr, .used, .r_value)
855 else1144 else
856 try transCreateNodeUndefinedLiteral(c);1145 try transCreateNodeUndefinedLiteral(c);
857 const semicolon_token = try appendToken(c, .Semicolon, ";");1146 if (isBoolRes(init_node)) {
8581147 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
859 const node = try c.a().create(ast.Node.VarDecl);1148 try builtin_node.params.push(init_node);
860 node.* = ast.Node.VarDecl{1149 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
861 .doc_comments = null,1150 init_node = &builtin_node.base;
862 .visib_token = null,1151 }
863 .thread_local_token = thread_local_token,1152 node.init_node = init_node;
864 .name_token = name_token,1153 node.semicolon_token = try appendToken(c, .Semicolon, ";");
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 };
876 try block_scope.block_node.statements.push(&node.base);1154 try block_scope.block_node.statements.push(&node.base);
877 },1155 },
878 else => |kind| return revertAndWarn(1156 else => |kind| return revertAndWarn(
...@@ -896,7 +1174,6 @@ fn transDeclRefExpr(...@@ -896,7 +1174,6 @@ fn transDeclRefExpr(
896 const value_decl = ZigClangDeclRefExpr_getDecl(expr);1174 const value_decl = ZigClangDeclRefExpr_getDecl(expr);
897 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));1175 const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl)));
898 const checked_name = if (scope.getAlias(name)) |a| a else name;1176 const checked_name = if (scope.getAlias(name)) |a| a else name;
899 if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name);
900 return transCreateNodeIdentifier(rp.c, checked_name);1177 return transCreateNodeIdentifier(rp.c, checked_name);
901}1178}
9021179
...@@ -909,25 +1186,58 @@ fn transImplicitCastExpr(...@@ -909,25 +1186,58 @@ fn transImplicitCastExpr(
909 const c = rp.c;1186 const c = rp.c;
910 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);1187 const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr);
911 const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value);1188 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);
912 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {1191 switch (ZigClangImplicitCastExpr_getCastKind(expr)) {
913 .BitCast => {1192 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => {
914 const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr));
915 const src_type = getExprQualType(c, sub_expr);
916 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);1193 return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node);
917 },1194 },
918 .IntegralCast => {1195 .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => {
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 => {
924 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);1196 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
925 },1197 },
926 .LValueToRValue, .NoOp => {
927 return transExpr(rp, scope, sub_expr, .used, .r_value);
928 },
929 .NullToPointer => {1198 .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);
931 },1241 },
932 else => |kind| return revertAndWarn(1242 else => |kind| return revertAndWarn(
933 rp,1243 rp,
...@@ -939,50 +1249,195 @@ fn transImplicitCastExpr(...@@ -939,50 +1249,195 @@ fn transImplicitCastExpr(
939 }1249 }
940}1250}
9411251
942fn transIntegerLiteral(1252fn transBoolExpr(
943 rp: RestorePoint,1253 rp: RestorePoint,
944 scope: *Scope,1254 scope: *Scope,
945 expr: *const ZigClangIntegerLiteral,1255 expr: *const ZigClangExpr,
946 result_used: ResultUsed,1256 used: ResultUsed,
1257 lrvalue: LRValue,
1258 grouped: bool,
947) TransError!*ast.Node {1259) TransError!*ast.Node {
948 var eval_result: ZigClangExprEvalResult = undefined;1260 const lparen = if (grouped)
949 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {1261 try appendToken(rp.c, .LParen, "(")
950 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);1262 else
951 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});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);
952 }1290 }
953 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
954 return maybeSuppressResult(rp, scope, result_used, node);
955}1291}
9561292
957fn transReturnStmt(1293fn isBoolRes(res: *ast.Node) bool {
958 rp: RestorePoint,1294 switch (res.id) {
959 scope: *Scope,1295 .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
960 expr: *const ZigClangReturnStmt,1296 .BoolOr,
961) TransError!*ast.Node {1297 .BoolAnd,
962 const node = try transCreateNodeReturnExpr(rp.c);1298 .EqualEqual,
963 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {1299 .BangEqual,
964 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);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 => {},
965 }1316 }
966 _ = try appendToken(rp.c, .Semicolon, ";");1317 return false;
967 return &node.base;
968}1318}
9691319
970fn transStringLiteral(1320fn finishBoolExpr(
971 rp: RestorePoint,1321 rp: RestorePoint,
972 scope: *Scope,1322 scope: *Scope,
973 stmt: *const ZigClangStringLiteral,1323 loc: ZigClangSourceLocation,
974 result_used: ResultUsed,1324 ty: *const ZigClangType,
1325 node: *ast.Node,
1326 used: ResultUsed,
975) TransError!*ast.Node {1327) TransError!*ast.Node {
976 const kind = ZigClangStringLiteral_getKind(stmt);1328 switch (ZigClangType_getTypeClass(ty)) {
977 switch (kind) {1329 .Builtin => {
978 .Ascii, .UTF8 => {1330 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
979 var len: usize = undefined;1331
980 const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len);1332 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
981 const str = bytes_ptr[0..len];1333 .Bool => return node,
9821334 .Char_U,
983 var char_buf: [4]u8 = undefined;1335 .UChar,
984 len = 0;1336 .Char_S,
985 for (str) |c| len += escapeChar(c, &char_buf).len;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
987 const buf = try rp.c.a().alloc(u8, len + "\"\"".len);1442 const buf = try rp.c.a().alloc(u8, len + "\"\"".len);
988 buf[0] = '"';1443 buf[0] = '"';
...@@ -991,7 +1446,7 @@ fn transStringLiteral(...@@ -991,7 +1446,7 @@ fn transStringLiteral(
9911446
992 const token = try appendToken(rp.c, .StringLiteral, buf);1447 const token = try appendToken(rp.c, .StringLiteral, buf);
993 const node = try rp.c.a().create(ast.Node.StringLiteral);1448 const node = try rp.c.a().create(ast.Node.StringLiteral);
994 node.* = ast.Node.StringLiteral{1449 node.* = .{
995 .token = token,1450 .token = token,
996 };1451 };
997 return maybeSuppressResult(rp, scope, result_used, &node.base);1452 return maybeSuppressResult(rp, scope, result_used, &node.base);
...@@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {...@@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
1019 var i: usize = 0;1474 var i: usize = 0;
1020 for (s) |c| {1475 for (s) |c| {
1021 const escaped = escapeChar(c, &char_buf);1476 const escaped = escapeChar(c, &char_buf);
1022 std.mem.copy(u8, buf[i..], escaped);1477 mem.copy(u8, buf[i..], escaped);
1023 i += escaped.len;1478 i += escaped.len;
1024 }1479 }
1025}1480}
10261481
1027// Returns either a string literal or a slice of `buf`.1482// Returns either a string literal or a slice of `buf`.
1028fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {1483fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
1029 // TODO: https://github.com/ziglang/zig/issues/27491484 return switch (c) {
1030 const escaped = switch (c) {1485 '\"' => "\\\""[0..],
1031 // Printable ASCII except for ' " \1486 '\'' => "\\'"[0..],
1032 ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..],1487 '\\' => "\\\\"[0..],
1033 '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..],1488 '\n' => "\\n"[0..],
1034 '\n' => return "\\n"[0..],1489 '\r' => "\\r"[0..],
1035 '\r' => return "\\r"[0..],1490 '\t' => "\\t"[0..],
1036 '\t' => return "\\t"[0..],1491 else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable,
1037 else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable,
1038 };1492 };
1039 std.mem.copy(u8, char_buf, escaped);
1040 return char_buf[0..escaped.len];
1041}1493}
10421494
1043fn transCCast(1495fn transCCast(
...@@ -1071,6 +1523,55 @@ fn transCCast(...@@ -1071,6 +1523,55 @@ fn transCCast(
1071 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1523 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1072 return &builtin_node.base;1524 return &builtin_node.base;
1073 }1525 }
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 }
1074 // TODO: maybe widen to increase size1575 // TODO: maybe widen to increase size
1075 // TODO: maybe bitcast to change sign1576 // TODO: maybe bitcast to change sign
1076 // TODO: maybe truncate to reduce size1577 // TODO: maybe truncate to reduce size
...@@ -1124,7 +1625,7 @@ fn transInitListExpr(...@@ -1124,7 +1625,7 @@ fn transInitListExpr(
1124 var cat_tok: ast.TokenIndex = undefined;1625 var cat_tok: ast.TokenIndex = undefined;
1125 if (init_count != 0) {1626 if (init_count != 0) {
1126 const dot_tok = try appendToken(rp.c, .Period, ".");1627 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);
1128 var i: c_uint = 0;1629 var i: c_uint = 0;
1129 while (i < init_count) : (i += 1) {1630 while (i < init_count) : (i += 1) {
1130 const elem_expr = ZigClangInitListExpr_getInit(expr, i);1631 const elem_expr = ZigClangInitListExpr_getInit(expr, i);
...@@ -1139,7 +1640,7 @@ fn transInitListExpr(...@@ -1139,7 +1640,7 @@ fn transInitListExpr(
1139 }1640 }
11401641
1141 const dot_tok = try appendToken(rp.c, .Period, ".");1642 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);
1143 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);1644 const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr);
1144 try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value));1645 try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value));
1145 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");1646 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
...@@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr(...@@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr(
1185 .Builtin => blk: {1686 .Builtin => blk: {
1186 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);1687 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1187 switch (ZigClangBuiltinType_getKind(builtin_ty)) {1688 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1188 .Bool => return transCreateNodeBoolLiteral(rp.c, false),1689 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),
1189 .Char_U,1690 .Char_U,
1190 .UChar,1691 .UChar,
1191 .Char_S,1692 .Char_S,
...@@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr(...@@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr(
1215 };1716 };
1216}1717}
12171718
1218fn transCPtrCast(1719fn transIfStmt(
1219 rp: RestorePoint,1720 rp: RestorePoint,
1220 loc: ZigClangSourceLocation,1721 scope: *Scope,
1221 dst_type: ZigClangQualType,1722 stmt: *const ZigClangIfStmt,
1222 src_type: ZigClangQualType,1723) TransError!*ast.Node {
1223 expr: *ast.Node,1724 // if (c) t
1224) !*ast.Node {1725 // if (c) t else e
1225 const ty = ZigClangQualType_getTypePtr(dst_type);1726 const if_node = try transCreateNodeIf(rp.c);
1226 const child_type = ZigClangType_getPointeeType(ty);
12271727
1228 // Implicit downcasting from higher to lower alignment values is forbidden,1728 var cond_scope = Scope{
1229 // use @alignCast to side-step this problem1729 .parent = scope,
1230 const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast");1730 .id = .Condition,
1231 const dst_type_node = try transType(rp, ty, loc);1731 };
1232 try ptrcast_node.params.push(dst_type_node);1732 if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);
1233 _ = try appendToken(rp.c, .Comma, ",");1733 _ = try appendToken(rp.c, .RParen, ")");
12341734
1235 if (ZigClangType_isVoidType(qualTypeCanon(child_type))) {1735 if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);
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, ")");
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;
1253}1743}
12541744
1255fn maybeSuppressResult(1745fn transWhileLoop(
1256 rp: RestorePoint,1746 rp: RestorePoint,
1257 scope: *Scope,1747 scope: *Scope,
1258 used: ResultUsed,1748 stmt: *const ZigClangWhileStmt,
1259 result: *ast.Node,
1260) TransError!*ast.Node {1749) TransError!*ast.Node {
1261 if (used == .used) return result;1750 const while_node = try transCreateNodeWhile(rp.c);
1262 // NOTE: This is backwards, but the semicolon must immediately follow the node.1751
1263 _ = try appendToken(rp.c, .Semicolon, ";");1752 var cond_scope = Scope{
1264 const lhs = try transCreateNodeIdentifier(rp.c, "_");1753 .parent = scope,
1265 const op_token = try appendToken(rp.c, .Equal, "=");1754 .id = .Condition,
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,
1272 };1755 };
1273 return &op_node.base;1756 while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);
1274}1757 _ = try appendToken(rp.c, .RParen, ")");
12751758
1276fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {1759 var loop_scope = Scope{
1277 try c.tree.root_node.decls.push(decl_node);1760 .parent = scope,
1278 _ = try c.global_scope.sym_table.put(name, decl_node);1761 .id = .Loop,
1762 };
1763 while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
1764 return &while_node.base;
1279}1765}
12801766
1281fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node {1767fn transDoWhileLoop(
1282 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);1768 rp: RestorePoint,
1283}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 {1782 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
1286 const rp = makeRestorePoint(c);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;1822 try body_node.statements.push(&if_node.base);
1291 var container_kind: std.zig.Token.Id = undefined;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)) {1829fn transForLoop(
1294 container_kind_name = "union";1830 rp: RestorePoint,
1295 container_kind = .Keyword_union;1831 scope: *Scope,
1296 } else if (ZigClangRecordDecl_isStruct(record_decl)) {1832 stmt: *const ZigClangForStmt,
1297 container_kind_name = "struct";1833) TransError!*ast.Node {
1298 container_kind = .Keyword_struct;1834 var loop_scope = Scope{
1299 } else {1835 .parent = scope,
1300 return revertAndWarn(1836 .id = .Loop,
1301 rp,1837 };
1302 error.UnsupportedType,1838 var block = false;
1303 record_loc,1839 var block_scope: ?*Scope.Block = null;
1304 "unsupported record type",1840 if (ZigClangForStmt_getInit(stmt)) |init| {
1305 .{},1841 block_scope = try Scope.Block.init(rp.c, scope, null);
1306 );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);
1307 }1845 }
13081846 var cond_scope = Scope{
1309 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {1847 .parent = scope,
1310 return transCreateNodeOpaqueType(c);1848 .id = .Condition,
1311 };1849 };
13121850
1313 const extern_tok = try appendToken(c, .Keyword_extern, "extern");1851 const while_node = try transCreateNodeWhile(rp.c);
1314 const container_tok = try appendToken(c, container_kind, container_kind_name);1852 while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|
1315 const lbrace_token = try appendToken(c, .LBrace, "{");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);1874fn transSwitch(
1318 container_node.* = .{1875 rp: RestorePoint,
1319 .layout_token = extern_tok,1876 scope: *Scope,
1320 .kind_token = container_tok,1877 stmt: *const ZigClangSwitchStmt,
1321 .init_arg_expr = .None,1878) TransError!*ast.Node {
1322 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),1879 const switch_node = try transCreateNodeSwitch(rp.c);
1323 .lbrace_token = lbrace_token,1880 var switch_scope = Scope.Switch{
1324 .rbrace_token = undefined,1881 .base = .{
1882 .id = .Switch,
1883 .parent = scope,
1884 },
1885 .cases = &switch_node.cases,
1886 .pending_block = undefined,
1325 };1887 };
13261888
1327 var it = ZigClangRecordDecl_field_begin(record_def);1889 var cond_scope = Scope{
1328 const end_it = ZigClangRecordDecl_field_end(record_def);1890 .parent = scope,
1329 while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {1891 .id = .Condition,
1330 const field_decl = ZigClangRecordDecl_field_iterator_deref(it);1892 };
1331 const field_loc = ZigClangFieldDecl_getLocation(field_decl);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)) {1898 const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
1334 rp.activate();1899 // tmp block that all statements will go before being picked up by a case or default
1335 const node = try transCreateNodeOpaqueType(c);1900 const block = try transCreateNodeBlock(rp.c, null);
1336 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});1901 block_scope.block_node = block;
1337 return node;
1338 }
13391902
1340 const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));1903 const switch_block = try transCreateNodeBlock(rp.c, null);
1341 _ = try appendToken(c, .Colon, ":");1904 try switch_block.statements.push(&switch_node.base);
1342 const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc);1905 switch_scope.pending_block = switch_block;
13431906
1344 const field_node = try c.a().create(ast.Node.ContainerField);1907 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
1345 field_node.* = .{1908 _ = try appendToken(rp.c, .Semicolon, ";");
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 };
13531909
1354 try container_node.fields_and_decls.push(&field_node.base);1910 // take all pending statements
1355 _ = try appendToken(c, .Comma, ",");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.*);
1356 }1914 }
13571915
1358 container_node.rbrace_token = try appendToken(c, .RBrace, "}");1916 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");
1359 return &container_node.base;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;
1360}1926}
13611927
1362fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {1928fn transCase(
1363 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|1929 rp: RestorePoint,
1364 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice1930 scope: *Scope,
1365 const rp = makeRestorePoint(c);1931 stmt: *const ZigClangCaseStmt,
1366 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);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");1938 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
1369 const const_tok = try appendToken(c, .Keyword_const, "const");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)));1943 const node = try rp.c.a().create(ast.Node.InfixOp);
1372 var is_unnamed = false;1944 node.* = .{
1373 if (bare_name.len == 0) {1945 .op_token = ellips,
1374 bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});1946 .lhs = lhs_node,
1375 is_unnamed = true;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.*);
1376 }1969 }
1970 block_scope.block_node.statements.shrink(0);
13771971
1378 const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});1972 switch_scope.pending_block = block;
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, "=");
13821973
1383 const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: {1974 return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value);
1384 var pure_enum = true;1975}
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 }
13941976
1395 const extern_tok = try appendToken(c, .Keyword_extern, "extern");1977fn transDefault(
1396 const container_tok = try appendToken(c, .Keyword_enum, "enum");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);1988 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
1399 container_node.* = .{1989 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
1400 .layout_token = extern_tok,1990 _ = try appendToken(rp.c, .Comma, ",");
1401 .kind_token = container_tok,1991 try switch_scope.cases.push(&else_prong.base);
1402 .init_arg_expr = .None,1992
1403 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()),1993 const block = try transCreateNodeBlock(rp.c, null);
1404 .lbrace_token = undefined,1994 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
1405 .rbrace_token = undefined,1995 _ = try appendToken(rp.c, .Colon, ":");
1406 };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.2010fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, used: ResultUsed) TransError!*ast.Node {
1411 // I don't know what the default is, need to figure out how clang is deciding.2011 var result: ZigClangExprEvalResult = undefined;
1412 // it appears to at least be different across gcc/msvc2012 if (!ZigClangExpr_EvaluateAsConstantExpr(expr, &result, .EvaluateForCodeGen, rp.c.clang_context))
1413 if (!isCBuiltinType(int_type, .UInt) and2013 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangExpr_getBeginLoc(expr), "invalid constant expression", .{});
1414 !isCBuiltinType(int_type, .Int))2014 return maybeSuppressResult(rp, scope, used, try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)));
1415 {2015}
1416 _ = try appendToken(c, .LParen, "(");2016
1417 container_node.init_arg_expr = .{2017fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPredefinedExpr, used: ResultUsed) TransError!*ast.Node {
1418 .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {2018 return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used);
1419 error.UnsupportedType => {2019}
1420 if (is_unnamed) {2020
1421 try emitWarning(c, enum_loc, "unable to translate enum tag type", .{});2021fn transCharLiteral(
1422 } else {2022 rp: RestorePoint,
1423 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});2023 scope: *Scope,
1424 }2024 stmt: *const ZigClangCharacterLiteral,
1425 return null;2025 result_used: ResultUsed,
1426 },2026) TransError!*ast.Node {
1427 else => |e| return e,2027 const kind = ZigClangCharacterLiteral_getKind(stmt);
1428 },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,
1429 };2042 };
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 }
1431 }2129 }
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);2147 if (fn_ty) |ty| {
1436 end_it = ZigClangEnumDecl_enumerator_end(enum_def);2148 const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty));
1437 while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) {2149 const ret_ty = ZigClangQualType_getTypePtr(canon);
1438 const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it);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))2159fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType {
1443 enum_val_name[bare_name.len..]2160 const canon = ZigClangQualType_getCanonicalType(qt);
1444 else2161 var ty = ZigClangQualType_getTypePtr(canon);
1445 enum_val_name;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: {2175fn transUnaryExprOrTypeTraitExpr(
1450 _ = try appendToken(c, .Colon, "=");2176 rp: RestorePoint,
1451 break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));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);
1452 } else2248 } 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);2268fn transCreatePreCrement(
1456 field_node.* = .{2269 rp: RestorePoint,
1457 .doc_comments = null,2270 scope: *Scope,
1458 .comptime_token = null,2271 stmt: *const ZigClangUnaryOperator,
1459 .name_token = field_name_tok,2272 op: ast.Node.InfixOp.Op,
1460 .type_expr = null,2273 op_tok_id: std.zig.Token.Id,
1461 .value_expr = int_node,2274 bytes: []const u8,
1462 .align_expr = null,2275 used: ResultUsed,
1463 };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);2332fn transCreatePostCrement(
1466 _ = try appendToken(c, .Comma, ",");2333 rp: RestorePoint,
1467 // In C each enum value is in the global namespace. So we put them there too.2334 scope: *Scope,
1468 // At this point we can rely on the enum emitting successfully.2335 stmt: *const ZigClangUnaryOperator,
1469 try addEnumTopLevel(c, name, field_name, enum_val_name);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;
1470 }2465 }
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;2505 _ = try appendToken(rp.c, .Semicolon, ";");
1474 } else
1475 try transCreateNodeOpaqueType(c);
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);2511 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
1480 node.* = ast.Node.VarDecl{2512 break_node.rhs = ref_node;
1481 .visib_token = visib_tok,2513 try block_scope.block_node.statements.push(&break_node.base);
1482 .mut_token = const_tok,2514 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
1483 .name_token = name_tok,2515 // semicolon must immediately follow rbrace because it is the last token in a block
1484 .eq_token = eq_tok,2516 _ = try appendToken(rp.c, .Semicolon, ";");
1485 .init_node = init_node,2517 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
1486 .semicolon_token = semicolon_token,2518 grouped_expr.* = .{
1487 .doc_comments = null,2519 .lparen = try appendToken(rp.c, .LParen, "("),
1488 .comptime_token = null,2520 .expr = &block_scope.block_node.base,
1489 .extern_export_token = null,2521 .rparen = try appendToken(rp.c, .RParen, ")"),
1490 .thread_local_token = null,
1491 .lib_name = null,
1492 .type_node = null,
1493 .align_node = null,
1494 .section_node = null,
1495 };2522 };
2523 return &grouped_expr.base;
2524}
14962525
1497 try addTopLevelDecl(c, name, &node.base);2526fn transCPtrCast(
1498 if (!is_unnamed)2527 rp: RestorePoint,
1499 try c.alias_list.push(.{ .alias = bare_name, .name = name });2528 loc: ZigClangSourceLocation,
1500 return transCreateNodeIdentifier(c, name);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;
1501}2561}
15022562
1503fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void {2563fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
1504 const visib_tok = try appendToken(c, .Keyword_pub, "pub");2564 const break_scope = scope.getBreakableScope();
1505 const const_tok = try appendToken(c, .Keyword_const, "const");2565 const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch)
1506 const name_tok = try appendIdentifier(c, enum_val_name);2566 "__switch"
1507 const eq_tok = try appendToken(c, .Equal, "=");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);2573fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
1510 const period_tok = try appendToken(c, .Period, ".");2574 // TODO use something more accurate
1511 const field_ident = try transCreateNodeIdentifier(c, field_name);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);2583fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node {
1514 field_access_node.* = .{2584 const grouped = scope.id == .Condition;
1515 .op_token = period_tok,2585 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
1516 .lhs = enum_ident,2586 const if_node = try transCreateNodeIf(rp.c);
1517 .op = .Period,2587 var cond_scope = Scope{
1518 .rhs = field_ident,2588 .parent = scope,
2589 .id = .Condition,
1519 };2590 };
1520 const semicolon_token = try appendToken(c, .Semicolon, ";");
15212591
1522 const node = try c.a().create(ast.Node.VarDecl);2592 const cond_expr = ZigClangConditionalOperator_getCond(stmt);
1523 node.* = ast.Node.VarDecl{2593 const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt);
1524 .visib_token = visib_tok,2594 const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt);
1525 .mut_token = const_tok,2595
1526 .name_token = name_tok,2596 if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false);
1527 .eq_token = eq_tok,2597 _ = try appendToken(rp.c, .RParen, ")");
1528 .init_node = &field_access_node.base,2598
1529 .semicolon_token = semicolon_token,2599 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
1530 .thread_local_token = null,2600
1531 .doc_comments = null,2601 if_node.@"else" = try transCreateNodeElse(rp.c);
1532 .comptime_token = null,2602 if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);
1533 .extern_export_token = null,2603
1534 .lib_name = null,2604 if (grouped) {
1535 .type_node = null,2605 const rparen = try appendToken(rp.c, .RParen, ")");
1536 .align_node = null,2606 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
1537 .section_node = null,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,
1538 };2643 };
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);
1541}2654}
15422655
1543fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {2656fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
...@@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {...@@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
1552 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;2665 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
1553}2666}
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
1555fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {2757fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
1556 const ty = ZigClangQualType_getTypePtr(qt);2758 const ty = ZigClangQualType_getTypePtr(qt);
15572759
...@@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {...@@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
1601 return ZigClangExpr_getType(expr);2803 return ZigClangExpr_getType(expr);
1602}2804}
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
1604fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {2814fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {
1605 switch (ZigClangType_getTypeClass(ty)) {2815 switch (ZigClangType_getTypeClass(ty)) {
1606 .Builtin => {2816 .Builtin => {
...@@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {...@@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
1657 };2867 };
1658}2868}
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
1660fn transCreateNodeAssign(2901fn transCreateNodeAssign(
1661 rp: RestorePoint,2902 rp: RestorePoint,
1662 scope: *Scope,2903 scope: *Scope,
1663 result_used: ResultUsed,2904 result_used: ResultUsed,
1664 lhs: *const ZigClangExpr,2905 lhs: *const ZigClangExpr,
1665 rhs: *const ZigClangExpr,2906 rhs: *const ZigClangExpr,
1666) !*ast.Node.InfixOp {2907) !*ast.Node {
1667 // common case2908 // common case
1668 // c: lhs = rhs2909 // c: lhs = rhs
1669 // zig: lhs = rhs2910 // zig: lhs = rhs
1670 if (result_used == .unused) {2911 if (result_used == .unused) {
1671 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2912 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
1672 const eq_token = try appendToken(rp.c, .Equal, "=");2913 const eq_token = try appendToken(rp.c, .Equal, "=");
1673 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);2914 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
1674 _ = try appendToken(rp.c, .Semicolon, ";");2915 if (isBoolRes(rhs_node)) {
16752916 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
1676 const node = try rp.c.a().create(ast.Node.InfixOp);2917 try builtin_node.params.push(rhs_node);
1677 node.* = .{2918 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1678 .op_token = eq_token,2919 rhs_node = &builtin_node.base;
1679 .lhs = lhs_node,2920 }
1680 .op = .Assign,2921 if (scope.id != .Condition)
1681 .rhs = rhs_node,2922 _ = try appendToken(rp.c, .Semicolon, ";");
1682 };2923 return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false);
1683 return node;
1684 }2924 }
16852925
1686 // worst case2926 // worst case
1687 // c: lhs = rhs2927 // c: lhs = rhs
1688 // zig: (x: {2928 // zig: (blk: {
1689 // zig: const _tmp = rhs;2929 // zig: const _tmp = rhs;
1690 // zig: lhs = _tmp;2930 // zig: lhs = _tmp;
1691 // zig: break :x _tmp2931 // zig: break :blk _tmp
1692 // zig: })2932 // zig: })
1693 return revertAndWarn(2933 const block_scope = try Scope.Block.init(rp.c, scope, "blk");
1694 rp,2934 block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
1695 error.UnsupportedTranslation,2935 const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()});
1696 ZigClangExpr_getBeginLoc(lhs),2936
1697 "TODO: worst case assign op expr",2937 const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
1698 .{},2938 node.eq_token = try appendToken(rp.c, .Equal, "=");
1699 );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;
1700}2966}
17012967
1702fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall {2968fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall {
1703 const builtin_token = try appendToken(c, .Builtin, name);2969 const builtin_token = try appendToken(c, .Builtin, name);
1704 _ = try appendToken(c, .LParen, "(");2970 _ = try appendToken(c, .LParen, "(");
1705 const node = try c.a().create(ast.Node.BuiltinCall);2971 const node = try c.a().create(ast.Node.BuiltinCall);
1706 node.* = ast.Node.BuiltinCall{2972 node.* = .{
1707 .builtin_token = builtin_token,2973 .builtin_token = builtin_token,
1708 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),2974 .params = ast.Node.BuiltinCall.ParamList.init(c.a()),
1709 .rparen_token = undefined, // set after appending args2975 .rparen_token = undefined, // set after appending args
...@@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti...@@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti
1714fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {2980fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
1715 _ = try appendToken(c, .LParen, "(");2981 _ = try appendToken(c, .LParen, "(");
1716 const node = try c.a().create(ast.Node.SuffixOp);2982 const node = try c.a().create(ast.Node.SuffixOp);
1717 node.* = ast.Node.SuffixOp{2983 node.* = .{
1718 .lhs = .{ .node = fn_expr },2984 .lhs = .{ .node = fn_expr },
1719 .op = ast.Node.SuffixOp.Op{2985 .op = .{
1720 .Call = ast.Node.SuffixOp.Op.Call{2986 .Call = .{
1721 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),2987 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
1722 .async_token = null,2988 .async_token = null,
1723 },2989 },
...@@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {...@@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
1727 return node;2993 return node;
1728}2994}
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
1730fn transCreateNodePrefixOp(3007fn transCreateNodePrefixOp(
1731 c: *Context,3008 c: *Context,
1732 op: ast.Node.PrefixOp.Op,3009 op: ast.Node.PrefixOp.Op,
...@@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp(...@@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp(
1745fn transCreateNodeInfixOp(3022fn transCreateNodeInfixOp(
1746 rp: RestorePoint,3023 rp: RestorePoint,
1747 scope: *Scope,3024 scope: *Scope,
1748 stmt: *const ZigClangBinaryOperator,3025 lhs_node: *ast.Node,
1749 op: ast.Node.InfixOp.Op,3026 op: ast.Node.InfixOp.Op,
1750 op_tok_id: std.zig.Token.Id,3027 op_token: ast.TokenIndex,
1751 bytes: []const u8,3028 rhs_node: *ast.Node,
3029 used: ResultUsed,
1752 grouped: bool,3030 grouped: bool,
1753) !*ast.Node {3031) !*ast.Node {
1754 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;3032 var lparen = if (grouped)
1755 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);3033 try appendToken(rp.c, .LParen, "(")
1756 const op_token = try appendToken(rp.c, op_tok_id, bytes);3034 else
1757 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);3035 null;
1758 const node = try rp.c.a().create(ast.Node.InfixOp);3036 const node = try rp.c.a().create(ast.Node.InfixOp);
1759 node.* = ast.Node.InfixOp{3037 node.* = .{
1760 .op_token = op_token,3038 .op_token = op_token,
1761 .lhs = lhs,3039 .lhs = lhs_node,
1762 .op = op,3040 .op = op,
1763 .rhs = rhs,3041 .rhs = rhs_node,
1764 };3042 };
1765 if (!grouped) return &node.base;3043 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
1766 const rparen = try appendToken(rp.c, .RParen, ")");3044 const rparen = try appendToken(rp.c, .RParen, ")");
1767 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3045 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
1768 grouped_expr.* = ast.Node.GroupedExpression{3046 grouped_expr.* = .{
1769 .lparen = lparen,3047 .lparen = lparen.?,
1770 .expr = &node.base,3048 .expr = &node.base,
1771 .rparen = rparen,3049 .rparen = rparen,
1772 };3050 };
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 );
1774}3081}
17753082
1776fn transCreateNodePtrType(3083fn transCreateNodePtrType(
...@@ -1797,9 +3104,9 @@ fn transCreateNodePtrType(...@@ -1797,9 +3104,9 @@ fn transCreateNodePtrType(
1797 .Asterisk => try appendToken(c, .Asterisk, "*"),3104 .Asterisk => try appendToken(c, .Asterisk, "*"),
1798 else => unreachable,3105 else => unreachable,
1799 };3106 };
1800 node.* = ast.Node.PrefixOp{3107 node.* = .{
1801 .op_token = op_token,3108 .op_token = op_token,
1802 .op = ast.Node.PrefixOp.Op{3109 .op = .{
1803 .PtrType = .{3110 .PtrType = .{
1804 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,3111 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
1805 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,3112 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
...@@ -1810,11 +3117,17 @@ fn transCreateNodePtrType(...@@ -1810,11 +3117,17 @@ fn transCreateNodePtrType(
1810 return node;3117 return node;
1811}3118}
18123119
1813fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {3120fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
1814 const num_limbs = ZigClangAPSInt_getNumWords(int.?);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);
1815 var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);3126 var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);
3127 if (is_negative)
3128 big.negate();
1816 defer big.deinit();3129 defer big.deinit();
1817 const data = ZigClangAPSInt_getRawData(int.?);3130 const data = ZigClangAPSInt_getRawData(aps_int);
1818 var i: @TypeOf(num_limbs) = 0;3131 var i: @TypeOf(num_limbs) = 0;
1819 while (i < num_limbs) : (i += 1) big.limbs[i] = data[i];3132 while (i < num_limbs) : (i += 1) big.limbs[i] = data[i];
1820 const str = big.toString(c.a(), 10) catch |err| switch (err) {3133 const str = big.toString(c.a(), 10) catch |err| switch (err) {
...@@ -1823,16 +3136,18 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {...@@ -1823,16 +3136,18 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
1823 };3136 };
1824 const token = try appendToken(c, .IntegerLiteral, str);3137 const token = try appendToken(c, .IntegerLiteral, str);
1825 const node = try c.a().create(ast.Node.IntegerLiteral);3138 const node = try c.a().create(ast.Node.IntegerLiteral);
1826 node.* = ast.Node.IntegerLiteral{3139 node.* = .{
1827 .token = token,3140 .token = token,
1828 };3141 };
3142 if (is_negative)
3143 ZigClangAPSInt_free(aps_int);
1829 return &node.base;3144 return &node.base;
1830}3145}
18313146
1832fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {3147fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
1833 const ltoken = try appendToken(c, .Keyword_return, "return");3148 const ltoken = try appendToken(c, .Keyword_return, "return");
1834 const node = try c.a().create(ast.Node.ControlFlowExpression);3149 const node = try c.a().create(ast.Node.ControlFlowExpression);
1835 node.* = ast.Node.ControlFlowExpression{3150 node.* = .{
1836 .ltoken = ltoken,3151 .ltoken = ltoken,
1837 .kind = .Return,3152 .kind = .Return,
1838 .rhs = null,3153 .rhs = null,
...@@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {...@@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
1843fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {3158fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
1844 const token = try appendToken(c, .Keyword_undefined, "undefined");3159 const token = try appendToken(c, .Keyword_undefined, "undefined");
1845 const node = try c.a().create(ast.Node.UndefinedLiteral);3160 const node = try c.a().create(ast.Node.UndefinedLiteral);
1846 node.* = ast.Node.UndefinedLiteral{3161 node.* = .{
1847 .token = token,3162 .token = token,
1848 };3163 };
1849 return &node.base;3164 return &node.base;
...@@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {...@@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
1852fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {3167fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
1853 const token = try appendToken(c, .Keyword_null, "null");3168 const token = try appendToken(c, .Keyword_null, "null");
1854 const node = try c.a().create(ast.Node.NullLiteral);3169 const node = try c.a().create(ast.Node.NullLiteral);
1855 node.* = ast.Node.NullLiteral{3170 node.* = .{
1856 .token = token,3171 .token = token,
1857 };3172 };
1858 return &node.base;3173 return &node.base;
...@@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {...@@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
1864 else3179 else
1865 try appendToken(c, .Keyword_false, "false");3180 try appendToken(c, .Keyword_false, "false");
1866 const node = try c.a().create(ast.Node.BoolLiteral);3181 const node = try c.a().create(ast.Node.BoolLiteral);
1867 node.* = ast.Node.BoolLiteral{3182 node.* = .{
1868 .token = token,3183 .token = token,
1869 };3184 };
1870 return &node.base;3185 return &node.base;
1871}3186}
18723187
1873fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp {3188fn transCreateNodeContainerInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp {
1874 _ = try appendToken(c, .LBrace, "{");3189 _ = try appendToken(c, .LBrace, "{");
1875 const node = try c.a().create(ast.Node.SuffixOp);3190 const node = try c.a().create(ast.Node.SuffixOp);
1876 node.* = ast.Node.SuffixOp{3191 node.* = ast.Node.SuffixOp{
...@@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N...@@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N
1886fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {3201fn transCreateNodeInt(c: *Context, int: var) !*ast.Node {
1887 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});3202 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
1888 const node = try c.a().create(ast.Node.IntegerLiteral);3203 const node = try c.a().create(ast.Node.IntegerLiteral);
1889 node.* = ast.Node.IntegerLiteral{3204 node.* = .{
1890 .token = token,3205 .token = token,
1891 };3206 };
1892 return &node.base;3207 return &node.base;
...@@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {...@@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
1907 return &call_node.base;3222 return &call_node.base;
1908}3223}
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 {
1911 const scope = &c.global_scope.base;3226 const scope = &c.global_scope.base;
19123227
1913 const pub_tok = try appendToken(c, .Keyword_pub, "pub");3228 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...@@ -1916,8 +3231,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
1916 const name_tok = try appendIdentifier(c, name);3231 const name_tok = try appendIdentifier(c, name);
1917 _ = try appendToken(c, .LParen, "(");3232 _ = try appendToken(c, .LParen, "(");
19183233
1919 const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?;
1920
1921 var fn_params = ast.Node.FnProto.ParamList.init(c.a());3234 var fn_params = ast.Node.FnProto.ParamList.init(c.a());
1922 var it = proto_alias.params.iterator(0);3235 var it = proto_alias.params.iterator(0);
1923 while (it.next()) |pn| {3236 while (it.next()) |pn| {
...@@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {...@@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block {
2046 return block_node;3359 return block_node;
2047}3360}
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
2049const RestorePoint = struct {3528const RestorePoint = struct {
2050 c: *Context,3529 c: *Context,
2051 token_index: ast.TokenIndex,3530 token_index: ast.TokenIndex,
...@@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
2092 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),3571 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2093 });3572 });
2094 },3573 },
2095 .FunctionProto => {3574 .FunctionProto, .FunctionNoProto => {
2096 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);3575 const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty);
2097 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);3576 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);
2098 return &fn_proto.base;3577 return &fn_proto.base;
...@@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
2167 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);3646 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
21683647
2169 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);3648 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
2170 const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));3649 return (try transTypeDef(rp.c, typedef_decl)) orelse
2171 return transCreateNodeIdentifier(rp.c, typedef_name);3650 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
2172 },3651 },
2173 .Record => {3652 .Record => {
2174 const record_ty = @ptrCast(*const ZigClangRecordType, ty);3653 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 // };
2183 const record_decl = ZigClangRecordType_getDecl(record_ty);3655 const record_decl = ZigClangRecordType_getDecl(record_ty);
2184 if (try getContainerName(rp, record_decl)) |name|3656 return (try transRecordDecl(rp.c, record_decl)) orelse
2185 return transCreateNodeIdentifier(rp.c, name)3657 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
2186 else
2187 return transRecordDecl(rp.c, record_decl);
2188 },3658 },
2189 .Enum => {3659 .Enum => {
2190 const enum_ty = @ptrCast(*const ZigClangEnumType, ty);3660 const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
...@@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
2205 const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty);3675 const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty);
2206 return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc);3676 return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc);
2207 },3677 },
3678 .MacroQualified => {
3679 const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty);
3680 return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc);
3681 },
2208 else => {3682 else => {
2209 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));3683 const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
2210 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});3684 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...@@ -2212,22 +3686,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
2212 }3686 }
2213}3687}
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
2231fn isCVoid(qt: ZigClangQualType) bool {3689fn isCVoid(qt: ZigClangQualType) bool {
2232 const ty = ZigClangQualType_getTypePtr(qt);3690 const ty = ZigClangQualType_getTypePtr(qt);
2233 if (ZigClangType_getTypeClass(ty) == .Builtin) {3691 if (ZigClangType_getTypeClass(ty) == .Builtin) {
...@@ -2241,7 +3699,6 @@ const FnDeclContext = struct {...@@ -2241,7 +3699,6 @@ const FnDeclContext = struct {
2241 fn_name: []const u8,3699 fn_name: []const u8,
2242 has_body: bool,3700 has_body: bool,
2243 storage_class: ZigClangStorageClass,3701 storage_class: ZigClangStorageClass,
2244 scope: **Scope,
2245 is_export: bool,3702 is_export: bool,
2246};3703};
22473704
...@@ -2307,9 +3764,6 @@ fn finishTransFnProto(...@@ -2307,9 +3764,6 @@ fn finishTransFnProto(
2307 // TODO check for always_inline attribute3764 // TODO check for always_inline attribute
2308 // TODO check for align attribute3765 // TODO check for align attribute
23093766
2310 var fndef_scope = Scope.FnDef.init(rp.c);
2311 const scope = &fndef_scope.base;
2312
2313 // pub extern fn name(...) T3767 // pub extern fn name(...) T
2314 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;3768 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
2315 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;3769 const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null;
...@@ -2335,15 +3789,11 @@ fn finishTransFnProto(...@@ -2335,15 +3789,11 @@ fn finishTransFnProto(
2335 const param_name_tok: ?ast.TokenIndex = blk: {3789 const param_name_tok: ?ast.TokenIndex = blk: {
2336 if (fn_decl != null) {3790 if (fn_decl != null) {
2337 const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i));3791 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)));
2339 if (param_name.len < 1)3793 if (param_name.len < 1)
2340 param_name = "arg"[0..];3794 break :blk null;
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;
23453795
2346 const result = try appendIdentifier(rp.c, checked_param_name);3796 const result = try appendIdentifier(rp.c, param_name);
2347 _ = try appendToken(rp.c, .Colon, ":");3797 _ = try appendToken(rp.c, .Colon, ":");
2348 break :blk result;3798 break :blk result;
2349 }3799 }
...@@ -2410,14 +3860,13 @@ fn finishTransFnProto(...@@ -2410,14 +3860,13 @@ fn finishTransFnProto(
2410 };3860 };
24113861
2412 const fn_proto = try rp.c.a().create(ast.Node.FnProto);3862 const fn_proto = try rp.c.a().create(ast.Node.FnProto);
2413 fn_proto.* = ast.Node.FnProto{3863 fn_proto.* = .{
2414 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2415 .doc_comments = null,3864 .doc_comments = null,
2416 .visib_token = pub_tok,3865 .visib_token = pub_tok,
2417 .fn_token = fn_tok,3866 .fn_token = fn_tok,
2418 .name_token = name_tok,3867 .name_token = name_tok,
2419 .params = fn_params,3868 .params = fn_params,
2420 .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node },3869 .return_type = .{ .Explicit = return_type_node },
2421 .var_args_token = null, // TODO this field is broken in the AST data model3870 .var_args_token = null, // TODO this field is broken in the AST data model
2422 .extern_export_inline_token = extern_export_inline_tok,3871 .extern_export_inline_token = extern_export_inline_tok,
2423 .cc_token = cc_tok,3872 .cc_token = cc_tok,
...@@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8,...@@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8,
2523 return token_index;3972 return token_index;
2524}3973}
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
2526fn isValidZigIdentifier(name: []const u8) bool {4010fn isValidZigIdentifier(name: []const u8) bool {
2527 for (name) |c, i| {4011 for (name) |c, i| {
2528 switch (c) {4012 switch (c) {
...@@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
2573 const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro);4057 const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro);
25744058
2575 const name = try c.str(raw_name);4059 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)) {
2577 continue;4065 continue;
2578 }4066 }
2579 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);4067 const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc);
2580 ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) {4068 ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) {
2581 error.OutOfMemory => |e| return e,4069 error.OutOfMemory => |e| return e,
2582 else => {4070 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", .{});
2584 continue;4072 continue;
2585 },4073 },
2586 };4074 };
25874075
2588 var tok_it = tok_list.iterator(0);4076 var tok_it = tok_list.iterator(0);
2589 const first_tok = tok_it.next().?;4077 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));
2591 const next = tok_it.peek().?;4079 const next = tok_it.peek().?;
2592 switch (next.id) {4080 switch (next.id) {
2593 .Identifier => {4081 .Identifier => {
2594 // if it equals itself, ignore. for example, from stdio.h:4082 // if it equals itself, ignore. for example, from stdio.h:
2595 // #define stdin stdin4083 // #define stdin stdin
2596 if (std.mem.eql(u8, name, next.bytes)) {4084 if (mem.eql(u8, checked_name, next.bytes)) {
2597 continue;4085 continue;
2598 }4086 }
2599 },4087 },
...@@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {...@@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
2610 } else false;4098 } else false;
26114099
2612 (if (macro_fn)4100 (if (macro_fn)
2613 transMacroFnDefine(c, &tok_it, name, begin_loc)4101 transMacroFnDefine(c, &tok_it, checked_name, begin_loc)
2614 else4102 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) {
2616 error.UnsupportedTranslation,4104 error.UnsupportedTranslation,
2617 error.ParseError,4105 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", .{}),
2619 error.OutOfMemory => |e| return e,4107 error.OutOfMemory => |e| return e,
2620 };4108 };
2621 },4109 },
...@@ -2628,37 +4116,28 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8,...@@ -2628,37 +4116,28 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8,
2628 const rp = makeRestorePoint(c);4116 const rp = makeRestorePoint(c);
2629 const scope = &c.global_scope.base;4117 const scope = &c.global_scope.base;
26304118
2631 const visib_tok = try appendToken(c, .Keyword_pub, "pub");4119 const node = try transCreateNodeVarDecl(c, true, true, name);
2632 const mut_tok = try appendToken(c, .Keyword_const, "const");4120 node.eq_token = try appendToken(c, .Equal, "=");
2633 const name_tok = try appendIdentifier(c, name);
2634 const eq_tok = 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);4133 node.semicolon_token = try appendToken(c, .Semicolon, ";");
2639 node.* = ast.Node.VarDecl{
2640 .doc_comments = null,
2641 .visib_token = visib_tok,
2642 .thread_local_token = null,
2643 .name_token = name_tok,
2644 .eq_token = eq_tok,
2645 .mut_token = mut_tok,
2646 .comptime_token = null,
2647 .extern_export_token = null,
2648 .lib_name = null,
2649 .type_node = null,
2650 .align_node = null,
2651 .section_node = null,
2652 .init_node = init_node,
2653 .semicolon_token = try appendToken(c, .Semicolon, ";"),
2654 };
2655 _ = try c.global_scope.macro_table.put(name, &node.base);4134 _ = try c.global_scope.macro_table.put(name, &node.base);
2656}4135}
26574136
2658fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {4137fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void {
2659 const rp = makeRestorePoint(c);4138 const rp = makeRestorePoint(c);
2660 var fndef_scope = Scope.FnDef.init(c);4139 const block_scope = try Scope.Block.init(c, &c.global_scope.base, null);
2661 const scope = &fndef_scope.base;4140 const scope = &block_scope.base;
26624141
2663 const pub_tok = try appendToken(c, .Keyword_pub, "pub");4142 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
2664 const inline_tok = try appendToken(c, .Keyword_inline, "inline");4143 const inline_tok = try appendToken(c, .Keyword_inline, "inline");
...@@ -2676,7 +4155,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u...@@ -2676,7 +4155,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
2676 return error.ParseError;4155 return error.ParseError;
26774156
2678 const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: {4157 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 });
2680 break :blk alias;4159 break :blk alias;
2681 } else param_tok.bytes;4160 } else param_tok.bytes;
26824161
...@@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u...@@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
27374216
2738 const return_expr = try transCreateNodeReturnExpr(c);4217 const return_expr = try transCreateNodeReturnExpr(c);
2739 const expr = try parseCExpr(rp, it, source_loc, scope);4218 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 );
2740 _ = try appendToken(c, .Semicolon, ";");4228 _ = try appendToken(c, .Semicolon, ";");
2741 try type_of.params.push(expr);4229 try type_of.params.push(expr);
2742 return_expr.rhs = expr;4230 return_expr.rhs = expr;
...@@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:...@@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
28384326
2839 if (it.peek().?.id == .RParen) {4327 if (it.peek().?.id == .RParen) {
2840 _ = it.next();4328 _ = it.next();
2841 return inner_node;4329 if (it.peek().?.id != .LParen) {
4330 return inner_node;
4331 }
4332 _ = it.next();
2842 }4333 }
28434334
2844 // hack to get zig fmt to render a comma in builtin calls4335 // 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:...@@ -2930,8 +4421,8 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc:
2930 rp,4421 rp,
2931 error.UnsupportedTranslation,4422 error.UnsupportedTranslation,
2932 source_loc,4423 source_loc,
2933 "unable to translate C expr",4424 "unable to translate C expr, unexpected token: {}",
2934 .{},4425 .{tok.id},
2935 ),4426 ),
2936 }4427 }
2937}4428}
...@@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
2944 .Dot => {4435 .Dot => {
2945 const name_tok = it.next().?;4436 const name_tok = it.next().?;
2946 if (name_tok.id != .Identifier)4437 if (name_tok.id != .Identifier)
2947 return revertAndWarn(4438 return error.ParseError;
2948 rp,4439
2949 error.ParseError,4440 node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes);
2950 source_loc,4441 },
2951 "unable to translate C expr",4442 .Arrow => {
2952 .{},4443 const name_tok = it.next().?;
2953 );4444 if (name_tok.id != .Identifier)
29544445 return error.ParseError;
2955 const op_token = try appendToken(rp.c, .Period, ".");4446
2956 const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes);4447 const deref = try transCreateNodePtrDeref(rp.c, node);
2957 const access_node = try rp.c.a().create(ast.Node.InfixOp);4448 node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes);
2958 access_node.* = .{
2959 .op_token = op_token,
2960 .lhs = node,
2961 .op = .Period,
2962 .rhs = rhs,
2963 };
2964 node = &access_node.base;
2965 },4449 },
2966 .Asterisk => {4450 .Asterisk => {
2967 if (it.peek().?.id == .RParen) {4451 if (it.peek().?.id == .RParen) {
...@@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
2977 // expr * expr4461 // expr * expr
2978 const op_token = try appendToken(rp.c, .Asterisk, "*");4462 const op_token = try appendToken(rp.c, .Asterisk, "*");
2979 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);4463 const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope);
2980 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);4464 const mul_node = try rp.c.a().create(ast.Node.InfixOp);
2981 bitshift_node.* = .{4465 mul_node.* = .{
2982 .op_token = op_token,4466 .op_token = op_token,
2983 .lhs = node,4467 .lhs = node,
2984 .op = .BitShiftLeft,4468 .op = .BitShiftLeft,
2985 .rhs = rhs,4469 .rhs = rhs,
2986 };4470 };
2987 node = &bitshift_node.base;4471 node = &mul_node.base;
2988 }4472 }
2989 },4473 },
2990 .Shl => {4474 .Shl => {
2991 const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<");4475 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);
2993 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);4477 const bitshift_node = try rp.c.a().create(ast.Node.InfixOp);
2994 bitshift_node.* = .{4478 bitshift_node.* = .{
2995 .op_token = op_token,4479 .op_token = op_token,
...@@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
2999 };4483 };
3000 node = &bitshift_node.base;4484 node = &bitshift_node.base;
3001 },4485 },
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 },
3002 else => {4522 else => {
3003 _ = it.prev();4523 _ = it.prev();
3004 return node;4524 return node;
...@@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
3028 },4548 },
3029 .Asterisk => {4549 .Asterisk => {
3030 const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope);4550 const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope);
3031 const node = try rp.c.a().create(ast.Node.SuffixOp);4551 return try transCreateNodePtrDeref(rp.c, prefix_op_expr);
3032 node.* = .{
3033 .lhs = .{ .node = prefix_op_expr },
3034 .op = .Deref,
3035 .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"),
3036 };
3037 return &node.base;
3038 },4552 },
3039 else => {4553 else => {
3040 _ = it.prev();4554 _ = it.prev();
...@@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc...@@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc
3043 }4557 }
3044}4558}
30454559
3046fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 {4560fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
3047 const tok = c.tree.tokens.at(token);4561 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];
3049}4563}
30504564
3051fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {4565fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
3052 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null;4566 if (node.id == .ContainerDecl) {
3053 const name = if (init.cast(ast.Node.Identifier)) |id|4567 return node;
3054 tokenSlice(c, id.token)4568 } else if (node.id == .PrefixOp) {
3055 else4569 return node;
3056 return null;4570 } else if (node.cast(ast.Node.Identifier)) |ident| {
3057 // TODO a.b.c4571 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {
3058 if (c.global_scope.sym_table.get(name)) |kv| {4572 if (kv.value.cast(ast.Node.VarDecl)) |var_decl|
3059 if (kv.value.cast(ast.Node.VarDecl)) |val| {4573 return getContainer(c, var_decl.init_node.?);
3060 if (val.type_node) |type_node| {4574 }
3061 if (type_node.cast(ast.Node.PrefixOp)) |casted| {4575 } else if (node.cast(ast.Node.InfixOp)) |infix| {
3062 if (casted.rhs.id == .FnProto) {4576 if (infix.op != .Period)
3063 return casted.rhs;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.?);
3064 }4613 }
3065 }4614 }
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 }
3066 }4630 }
3067 }4631 }
3068 }4632 }
...@@ -3072,7 +4636,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -3072,7 +4636,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node {
3072fn addMacros(c: *Context) !void {4636fn addMacros(c: *Context) !void {
3073 var macro_it = c.global_scope.macro_table.iterator();4637 var macro_it = c.global_scope.macro_table.iterator();
3074 while (macro_it.next()) |kv| {4638 while (macro_it.next()) |kv| {
3075 if (getFnDecl(c, kv.value)) |proto_node| {4639 if (getFnProto(c, kv.value)) |proto_node| {
3076 // If a macro aliases a global variable which is a function pointer, we conclude that4640 // If a macro aliases a global variable which is a function pointer, we conclude that
3077 // the macro is intended to represent a function that assumes the function pointer4641 // the macro is intended to represent a function that assumes the function pointer
3078 // variable is non-null and calls it.4642 // variable is non-null and calls it.
src/zig_clang.cpp+15
...@@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi...@@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi
1571 return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl);1571 return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl);
1572}1572}
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
1574const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) {1584const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) {
1575 const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl);1585 const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl);
1576 const clang::RecordDecl *definition = record_decl->getDefinition();1586 const clang::RecordDecl *definition = record_decl->getDefinition();
...@@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D...@@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D
2161 return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM);2171 return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM);
2162}2172}
21632173
2174double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self) {
2175 auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self);
2176 return casted->getValueAsApproximateDouble();
2177}
2178
2164enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) {2179enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) {
2165 auto casted = reinterpret_cast<const clang::StringLiteral *>(self);2180 auto casted = reinterpret_cast<const clang::StringLiteral *>(self);
2166 return (ZigClangStringLiteral_StringKind)casted->getKind();2181 return (ZigClangStringLiteral_StringKind)casted->getKind();
src/zig_clang.h+3
...@@ -856,6 +856,8 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc...@@ -856,6 +856,8 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc
856ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl);856ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl);
857ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *);857ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *);
858ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *);858ZIG_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
860ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *);862ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *);
861ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *);863ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *);
...@@ -985,6 +987,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st...@@ -985,6 +987,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st
985987
986ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,988ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST,
987 unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);989 unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM);
990ZIG_EXTERN_C double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self);
988991
989ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self);992ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self);
990ZIG_EXTERN_C const char *ZigClangStringLiteral_getString_bytes_begin_size(const struct ZigClangStringLiteral *self,993ZIG_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 {...@@ -127,16 +127,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
127 });127 });
128128
129 cases.addC_both("add, sub, mul, div, rem",129 cases.addC_both("add, sub, mul, div, rem",
130 \\int s(int a, int b) {130 \\int s() {
131 \\ int c;131 \\ int a, b, c;
132 \\ c = a + b;132 \\ c = a + b;
133 \\ c = a - b;133 \\ c = a - b;
134 \\ c = a * b;134 \\ c = a * b;
135 \\ c = a / b;135 \\ c = a / b;
136 \\ c = a % b;136 \\ c = a % b;
137 \\}137 \\}
138 \\unsigned u(unsigned a, unsigned b) {138 \\unsigned u() {
139 \\ unsigned c;139 \\ unsigned a, b, c;
140 \\ c = a + b;140 \\ c = a + b;
141 \\ c = a - b;141 \\ c = a - b;
142 \\ c = a * b;142 \\ c = a * b;
...@@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
144 \\ c = a % b;144 \\ c = a % b;
145 \\}145 \\}
146 , &[_][]const u8{146 , &[_][]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;
148 \\ var c: c_int = undefined;150 \\ var c: c_int = undefined;
149 \\ c = (a + b);151 \\ c = (a + b);
150 \\ c = (a - b);152 \\ c = (a - b);
...@@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
152 \\ c = @divTrunc(a, b);154 \\ c = @divTrunc(a, b);
153 \\ c = @rem(a, b);155 \\ c = @rem(a, b);
154 \\}156 \\}
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;
156 \\ var c: c_uint = undefined;160 \\ var c: c_uint = undefined;
157 \\ c = (a +% b);161 \\ c = (a +% b);
158 \\ c = (a -% b);162 \\ c = (a -% b);
...@@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
162 \\}166 \\}
163 });167 });
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
209 cases.add_both("typedef of function in struct field",169 cases.add_both("typedef of function in struct field",
210 \\typedef void lws_callback_function(void);170 \\typedef void lws_callback_function(void);
211 \\struct Foo {171 \\struct Foo {
...@@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
228 \\ struct Foo *foo;188 \\ struct Foo *foo;
229 \\};189 \\};
230 , &[_][]const u8{190 , &[_][]const u8{
231 \\pub const struct_Foo = @OpaqueType()191 \\pub const struct_Foo = @OpaqueType();
232 ,192 ,
233 \\pub const struct_Bar = extern struct {193 \\pub const struct_Bar = extern struct {
234 \\ foo: ?*struct_Foo,194 \\ foo: ?*struct_Foo,
...@@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
426 },386 },
427 );387 );
428388
429 /////////////// Cases that pass for only stage2 ////////////////389 cases.addC_both("null statements",
430390 \\void foo(void) {
431 cases.add_2("Parameterless function prototypes",391 \\ ;;;;;
432 \\void a() {}392 \\}
433 \\void b(void) {}
434 \\void c();
435 \\void d(void);
436 , &[_][]const u8{393 , &[_][]const u8{
437 \\pub export fn a() void {}394 \\pub export fn foo() void {
438 \\pub export fn b() void {}395 \\ {}
439 \\pub extern fn c(...) void;396 \\ {}
440 \\pub extern fn d() void;397 \\ {}
398 \\ {}
399 \\ {}
400 \\}
441 });401 });
442402
443 cases.add_2("variable declarations",403 if (builtin.os != builtin.Os.windows) {
444 \\extern char arr0[] = "hello";404 // Windows treats this as an enum with type c_int
445 \\static char arr1[] = "hello";405 cases.add_both("big negative enum init values when C ABI supports long long enums",
446 \\char arr2[] = "hello";406 \\enum EnumWithInits {
447 , &[_][]const u8{407 \\ VAL01 = 0,
448 \\pub extern var arr0: [*c]u8 = "hello";408 \\ VAL02 = 1,
449 \\pub var arr1: [*c]u8 = "hello";409 \\ VAL03 = 2,
450 \\pub export var arr2: [*c]u8 = "hello";410 \\ VAL04 = 3,
451 });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",460 cases.addC_both("predefined expressions",
454 \\static void foo(void){461 \\void foo(void) {
455 \\ char arr[10] ={1};462 \\ __func__;
456 \\ char *arr1[10] ={0};463 \\ __FUNCTION__;
464 \\ __PRETTY_FUNCTION__;
457 \\}465 \\}
458 , &[_][]const u8{466 , &[_][]const u8{
459 \\pub fn foo() void {467 \\pub export fn foo() void {
460 \\ var arr: [10]u8 = .{468 \\ _ = "foo";
461 \\ @as(u8, 1),469 \\ _ = "foo";
462 \\ } ++ .{0} ** 9;470 \\ _ = "void foo(void)";
463 \\ var arr1: [10][*c]u8 = .{
464 \\ null,
465 \\ } ++ .{null} ** 9;
466 \\}471 \\}
467 });472 });
468473
469 cases.add_2("enums",474 cases.addC_both("ignore result, no function arguments",
470 \\typedef enum {475 \\void foo() {
471 \\ a,476 \\ int a;
472 \\ b,477 \\ 1;
473 \\ c,478 \\ "hey";
474 \\} d;479 \\ 1 + 1;
475 \\enum {480 \\ 1 - 1;
476 \\ e,481 \\ a = 1;
477 \\ f = 4,482 \\}
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 \\};
493 , &[_][]const u8{483 , &[_][]const u8{
494 \\pub const a = enum_unnamed_1.a;484 \\pub export fn foo() void {
495 \\pub const b = enum_unnamed_1.b;485 \\ var a: c_int = undefined;
496 \\pub const c = enum_unnamed_1.c;486 \\ _ = 1;
497 \\pub const enum_unnamed_1 = extern enum {487 \\ _ = "hey";
498 \\ a,488 \\ _ = (1 + 1);
499 \\ b,489 \\ _ = (1 - 1);
500 \\ c,490 \\ a = 1;
501 \\};491 \\}
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;
534 });492 });
535493
536 cases.add_2("#define a char literal",494 cases.add_both("constant size array",
537 \\#define A_CHAR 'a'495 \\void func(int array[20]);
538 , &[_][]const u8{496 , &[_][]const u8{
539 \\pub const A_CHAR = 'a';497 \\pub extern fn func(array: [*c]c_int) void;
540 });498 });
541499
542 cases.add_2("comment after integer literal",500 cases.add_both("__cdecl doesn't mess up function pointers",
543 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */501 \\void foo(void (__cdecl *fn_ptr)(void));
544 , &[_][]const u8{502 , &[_][]const u8{
545 \\pub const SDL_INIT_VIDEO = 0x00000020;503 \\pub extern fn foo(fn_ptr: ?extern fn () void) void;
546 });504 });
547505
548 cases.add_2("u integer suffix after hex literal",506 cases.addC_both("void cast",
549 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */507 \\void foo() {
508 \\ int a;
509 \\ (void) a;
510 \\}
550 , &[_][]const u8{511 , &[_][]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 \\}
552 });516 });
553517
554 cases.add_2("l integer suffix after hex literal",518 cases.addC_both("implicit cast to void *",
555 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */519 \\void *foo() {
520 \\ unsigned short *x;
521 \\ return x;
522 \\}
556 , &[_][]const u8{523 , &[_][]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 \\}
558 });528 });
559529
560 cases.add_2("ul integer suffix after hex literal",530 cases.addC_both("null pointer implicit cast",
561 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */531 \\int* foo(void) {
532 \\ return 0;
533 \\}
562 , &[_][]const u8{534 , &[_][]const u8{
563 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);535 \\pub export fn foo() [*c]c_int {
536 \\ return null;
537 \\}
564 });538 });
565539
566 cases.add_2("lu integer suffix after hex literal",540 cases.add_both("simple union",
567 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */541 \\union Foo {
542 \\ int x;
543 \\ double y;
544 \\};
568 , &[_][]const u8{545 , &[_][]const u8{
569 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);546 \\pub const union_Foo = extern union {
570 });547 \\ x: c_int,
571548 \\ y: f64,
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 \\ },
635 \\};549 \\};
636 ,550 ,
637 \\pub extern var glProcs: union_OpenGLProcs;551 \\pub const Foo = union_Foo;
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";
672 });552 });
673553
674 cases.add_2("variable aliasing",554 cases.addC_both("string literal",
675 \\static long a = 2;555 \\const char *foo(void) {
676 \\static long b = 2;556 \\ return "bar";
677 \\static int c = 4;
678 \\void foo(char c) {
679 \\ int a;
680 \\ char b = 123;
681 \\ b = (char) a;
682 \\ {
683 \\ int d = 5;
684 \\ }
685 \\ unsigned d = 440;
686 \\}557 \\}
687 , &[_][]const u8{558 , &[_][]const u8{
688 \\pub var a: c_long = @as(c_long, 2);559 \\pub export fn foo() [*c]const u8 {
689 \\pub var b: c_long = @as(c_long, 2);560 \\ return "bar";
690 \\pub var c: c_int = 4;
691 \\pub export fn foo(c_1: u8) void {
692 \\ var a_2: c_int = undefined;
693 \\ var b_3: u8 = @as(u8, 123);
694 \\ b_3 = @as(u8, a_2);
695 \\ {
696 \\ var d: c_int = 5;
697 \\ }
698 \\ var d: c_uint = @as(c_uint, 440);
699 \\}561 \\}
700 });562 });
701563
702 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////564 cases.addC_both("return void",
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",
762 \\void foo(void) {565 \\void foo(void) {
763 \\ __func__;566 \\ return;
764 \\ __FUNCTION__;
765 \\ __PRETTY_FUNCTION__;
766 \\}567 \\}
767 , &[_][]const u8{568 , &[_][]const u8{
768 \\pub fn foo() void {569 \\pub export fn foo() void {
769 \\ _ = "foo";570 \\ return;
770 \\ _ = "foo";
771 \\ _ = "void foo(void)";
772 \\}571 \\}
773 });572 });
774573
775 cases.add("ignore result, no function arguments",574 cases.addC_both("for loop",
776 \\void foo() {575 \\void foo(void) {
777 \\ int a;576 \\ for (int i = 0; i; i = i + 1) { }
778 \\ 1;
779 \\ "hey";
780 \\ 1 + 1;
781 \\ 1 - 1;
782 \\ a = 1;
783 \\}577 \\}
784 , &[_][]const u8{578 , &[_][]const u8{
785 \\pub fn foo() void {579 \\pub export fn foo() void {
786 \\ var a: c_int = undefined;580 \\ {
787 \\ _ = 1;581 \\ var i: c_int = 0;
788 \\ _ = "hey";582 \\ while (i != 0) : (i = (i + 1)) {}
789 \\ _ = (1 + 1);583 \\ }
790 \\ _ = (1 - 1);
791 \\ a = 1;
792 \\}584 \\}
793 });585 });
794586
795 cases.add("for loop with var init but empty body",587 cases.addC_both("empty for loop",
796 \\void foo(void) {588 \\void foo(void) {
797 \\ for (int x = 0; x < 10; x++);589 \\ for (;;) { }
798 \\}590 \\}
799 , &[_][]const u8{591 , &[_][]const u8{
800 \\pub fn foo() void {592 \\pub export fn foo() void {
801 \\ {593 \\ while (true) {}
802 \\ var x: c_int = 0;
803 \\ while (x < 10) : (x += 1) {}
804 \\ }
805 \\}594 \\}
806 });595 });
807596
808 cases.add("do while with empty body",597 cases.addC_both("break statement",
809 \\void foo(void) {598 \\void foo(void) {
810 \\ do ; while (1);599 \\ for (;;) {
600 \\ break;
601 \\ }
811 \\}602 \\}
812 , &[_][]const u8{ // TODO this should be if (1 != 0) break603 , &[_][]const u8{
813 \\pub fn foo() void {604 \\pub export fn foo() void {
814 \\ while (true) {605 \\ while (true) {
815 \\ {}606 \\ break;
816 \\ if (!1) break;
817 \\ }607 \\ }
818 \\}608 \\}
819 });609 });
820610
821 cases.add("for with empty body",611 cases.addC_both("continue statement",
822 \\void foo(void) {612 \\void foo(void) {
823 \\ for (;;);613 \\ for (;;) {
614 \\ continue;
615 \\ }
824 \\}616 \\}
825 , &[_][]const u8{617 , &[_][]const u8{
826 \\pub fn foo() void {618 \\pub export fn foo() void {
827 \\ while (true) {}619 \\ while (true) {
620 \\ continue;
621 \\ }
828 \\}622 \\}
829 });623 });
830624
831 cases.add("while with empty body",625 cases.addC_both("pointer casting",
832 \\void foo(void) {626 \\float *ptrcast() {
833 \\ while (1);627 \\ int *a;
628 \\ return (float *)a;
834 \\}629 \\}
835 , &[_][]const u8{630 , &[_][]const u8{
836 \\pub fn foo() void {631 \\pub export fn ptrcast() [*c]f32 {
837 \\ while (1 != 0) {}632 \\ var a: [*c]c_int = undefined;
633 \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
838 \\}634 \\}
839 });635 });
840636
841 cases.addAllowWarnings("simple data types",637 cases.addC_both("pointer conversion with different alignment",
842 \\#include <stdint.h>638 \\void test_ptr_cast() {
843 \\int foo(char a, unsigned char b, signed char c);639 \\ void *p;
844 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype640 \\ {
845 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);641 \\ char *to_char = (char *)p;
846 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);642 \\ short *to_short = (short *)p;
847 , &[_][]const u8{643 \\ int *to_int = (int *)p;
848 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;644 \\ long long *to_longlong = (long long *)p;
849 ,645 \\ }
850 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;646 \\ {
851 ,647 \\ char *to_char = p;
852 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;648 \\ short *to_short = p;
853 });649 \\ int *to_int = p;
854650 \\ long long *to_longlong = p;
855 cases.addC("simple function",651 \\ }
856 \\int abs(int a) {
857 \\ return a < 0 ? -a : a;
858 \\}652 \\}
859 , &[_][]const u8{653 , &[_][]const u8{
860 \\export fn abs(a: c_int) c_int {654 \\pub export fn test_ptr_cast() void {
861 \\ return if (a < 0) -a else a;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 \\ }
862 \\}668 \\}
863 });669 });
864670
865 cases.add("restrict -> noalias",671 cases.addC_both("while on non-bool",
866 \\void foo(void *restrict bar, void *restrict);672 \\int while_none_bool() {
867 , &[_][]const u8{673 \\ int a;
868 \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void;674 \\ float b;
869 });675 \\ void *c;
870676 \\ while (a) return 0;
871 cases.add("qualified struct and enum",677 \\ while (b) return 1;
872 \\struct Foo {678 \\ while (c) return 2;
873 \\ int x;679 \\ return 3;
874 \\ int y;680 \\}
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'
931 , &[_][]const u8{681 , &[_][]const u8{
932 \\pub const FOO = "aoeu\x13 derp";682 \\pub export fn while_none_bool() c_int {
933 ,683 \\ var a: c_int = undefined;
934 \\pub const FOO2 = "aoeu\x134 derp";684 \\ var b: f32 = undefined;
935 ,685 \\ var c: ?*c_void = undefined;
936 \\pub const FOO_CHAR = 63;686 \\ while (a != 0) return 0;
687 \\ while (b != 0) return 1;
688 \\ while (c != null) return 2;
689 \\ return 3;
690 \\}
937 });691 });
938692
939 cases.addC("post increment",693 cases.addC_both("for on non-bool",
940 \\unsigned foo1(unsigned a) {694 \\int for_none_bool() {
941 \\ a++;695 \\ int a;
942 \\ return a;696 \\ float b;
943 \\}697 \\ void *c;
944 \\int foo2(int a) {698 \\ for (;a;) return 0;
945 \\ a++;699 \\ for (;b;) return 1;
946 \\ return a;700 \\ for (;c;) return 2;
701 \\ return 3;
947 \\}702 \\}
948 , &[_][]const u8{703 , &[_][]const u8{
949 \\pub export fn foo1(_arg_a: c_uint) c_uint {704 \\pub export fn for_none_bool() c_int {
950 \\ var a = _arg_a;705 \\ var a: c_int = undefined;
951 \\ a +%= 1;706 \\ var b: f32 = undefined;
952 \\ return a;707 \\ var c: ?*c_void = undefined;
953 \\}708 \\ while (a != 0) return 0;
954 \\pub export fn foo2(_arg_a: c_int) c_int {709 \\ while (b != 0) return 1;
955 \\ var a = _arg_a;710 \\ while (c != null) return 2;
956 \\ a += 1;711 \\ return 3;
957 \\ return a;
958 \\}712 \\}
959 });713 });
960714
961 cases.addC("shift right assign",715 cases.addC_both("bitshift",
962 \\int log2(unsigned a) {716 \\int foo(void) {
963 \\ int i = 0;717 \\ return (1 << 2) >> 1;
964 \\ while (a > 0) {
965 \\ a >>= 1;
966 \\ }
967 \\ return i;
968 \\}718 \\}
969 , &[_][]const u8{719 , &[_][]const u8{
970 \\pub export fn log2(_arg_a: c_uint) c_int {720 \\pub export fn foo() c_int {
971 \\ var a = _arg_a;721 \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
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;
977 \\}722 \\}
978 });723 });
979724
980 cases.addC("if statement",725 cases.addC_both("sizeof",
981 \\int max(int a, int b) {726 \\#include <stddef.h>
982 \\ if (a < b)727 \\size_t size_of(void) {
983 \\ return b;728 \\ return sizeof(int);
984 \\
985 \\ if (a < b)
986 \\ return b;
987 \\ else
988 \\ return a;
989 \\
990 \\ if (a < b) ; else ;
991 \\}729 \\}
992 , &[_][]const u8{730 , &[_][]const u8{
993 \\pub export fn max(a: c_int, b: c_int) c_int {731 \\pub export fn size_of() usize {
994 \\ if (a < b) return b;732 \\ return @sizeOf(c_int);
995 \\ if (a < b) return b else return a;
996 \\ if (a < b) {} else {}
997 \\}733 \\}
998 });734 });
999735
1000 cases.addC("==, !=",736 cases.addC_both("normal deref",
1001 \\int max(int a, int b) {737 \\void foo() {
1002 \\ if (a == b)738 \\ int *x;
1003 \\ return a;739 \\ *x = 1;
1004 \\ if (a != b)
1005 \\ return b;
1006 \\ return a;
1007 \\}740 \\}
1008 , &[_][]const u8{741 , &[_][]const u8{
1009 \\pub export fn max(a: c_int, b: c_int) c_int {742 \\pub export fn foo() void {
1010 \\ if (a == b) return a;743 \\ var x: [*c]c_int = undefined;
1011 \\ if (a != b) return b;744 \\ x.?.* = 1;
1012 \\ return a;
1013 \\}745 \\}
1014 });746 });
1015747
1016 cases.addC("bitwise binary operators",748 cases.addC_both("address of operator",
1017 \\int max(int a, int b) {749 \\int foo(void) {
1018 \\ return (a & b) ^ (a | b);750 \\ int x = 1234;
751 \\ int *ptr = &x;
752 \\ return *ptr;
1019 \\}753 \\}
1020 , &[_][]const u8{754 , &[_][]const u8{
1021 \\pub export fn max(a: c_int, b: c_int) c_int {755 \\pub export fn foo() c_int {
1022 \\ return (a & b) ^ (a | b);756 \\ var x: c_int = 1234;
757 \\ var ptr: [*c]c_int = &x;
758 \\ return ptr.?.*;
1023 \\}759 \\}
1024 });760 });
1025761
1026 cases.addC("logical and, logical or",762 cases.addC_both("bin not",
1027 \\int max(int a, int b) {763 \\int foo() {
1028 \\ if (a < b || a == b)764 \\ int x;
1029 \\ return b;765 \\ return ~x;
1030 \\ if (a >= b && a == b)
1031 \\ return a;
1032 \\ return a;
1033 \\}766 \\}
1034 , &[_][]const u8{767 , &[_][]const u8{
1035 \\pub export fn max(a: c_int, b: c_int) c_int {768 \\pub export fn foo() c_int {
1036 \\ if ((a < b) or (a == b)) return b;769 \\ var x: c_int = undefined;
1037 \\ if ((a >= b) and (a == b)) return a;770 \\ return ~x;
1038 \\ return a;
1039 \\}771 \\}
1040 });772 });
1041773
1042 cases.addC("logical and, logical or on none bool values",774 cases.addC_both("bool not",
1043 \\int and_or_none_bool(int a, float b, void *c) {775 \\int foo() {
1044 \\ if (a && b) return 0;776 \\ int a;
1045 \\ if (b && c) return 1;777 \\ float b;
1046 \\ if (a && c) return 2;778 \\ void *c;
1047 \\ if (a || b) return 3;779 \\ return !(a == 0);
1048 \\ if (b || c) return 4;780 \\ return !a;
1049 \\ if (a || c) return 5;781 \\ return !b;
1050 \\ return 6;782 \\ return !c;
1051 \\}783 \\}
1052 , &[_][]const u8{784 , &[_][]const u8{
1053 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {785 \\pub export fn foo() c_int {
1054 \\ if ((a != 0) and (b != 0)) return 0;786 \\ var a: c_int = undefined;
1055 \\ if ((b != 0) and (c != null)) return 1;787 \\ var b: f32 = undefined;
1056 \\ if ((a != 0) and (c != null)) return 2;788 \\ var c: ?*c_void = undefined;
1057 \\ if ((a != 0) or (b != 0)) return 3;789 \\ return !(a == 0);
1058 \\ if ((b != 0) or (c != null)) return 4;790 \\ return !(a != 0);
1059 \\ if ((a != 0) or (c != null)) return 5;791 \\ return !(b != 0);
1060 \\ return 6;792 \\ return !(c != null);
1061 \\}793 \\}
1062 });794 });
1063795
1064 cases.addC("assign",796 cases.addC("__extension__ cast",
1065 \\int max(int a) {797 \\int foo(void) {
1066 \\ int tmp;798 \\ return __extension__ 1;
1067 \\ tmp = a;
1068 \\ a = tmp;
1069 \\}799 \\}
1070 , &[_][]const u8{800 , &[_][]const u8{
1071 \\pub export fn max(_arg_a: c_int) c_int {801 \\pub export fn foo() c_int {
1072 \\ var a = _arg_a;802 \\ return 1;
1073 \\ var tmp: c_int = undefined;
1074 \\ tmp = a;
1075 \\ a = tmp;
1076 \\}803 \\}
1077 });804 });
1078805
1079 cases.addC("chaining assign",806 if (builtin.os != builtin.Os.windows) {
1080 \\void max(int a) {807 // sysv_abi not currently supported on windows
1081 \\ int b, c;808 cases.add_both("Macro qualified functions",
1082 \\ c = b = a;809 \\void __attribute__((sysv_abi)) foo(void);
1083 \\}810 , &[_][]const u8{
1084 , &[_][]const u8{811 \\pub extern fn foo() void;
1085 \\pub export fn max(a: c_int) void {812 });
1086 \\ var b: c_int = undefined;813 }
1087 \\ var c: c_int = undefined;
1088 \\ c = (x: {
1089 \\ const _tmp = a;
1090 \\ b = _tmp;
1091 \\ break :x _tmp;
1092 \\ });
1093 \\}
1094 });
1095814
1096 cases.addC("shift right assign with a fixed size type",815 /////////////// Cases that pass for only stage2 ////////////////
1097 \\#include <stdint.h>816
1098 \\int log2(uint32_t a) {817 cases.add_2("Parameterless function prototypes",
1099 \\ int i = 0;818 \\void a() {}
1100 \\ while (a > 0) {819 \\void b(void) {}
1101 \\ a >>= 1;820 \\void c();
1102 \\ }821 \\void d(void);
1103 \\ return i;
1104 \\}
1105 , &[_][]const u8{822 , &[_][]const u8{
1106 \\pub export fn log2(_arg_a: u32) c_int {823 \\pub export fn a() void {}
1107 \\ var a = _arg_a;824 \\pub export fn b() void {}
1108 \\ var i: c_int = 0;825 \\pub extern fn c(...) void;
1109 \\ while (a > @as(c_uint, 0)) {826 \\pub extern fn d() void;
1110 \\ a >>= @as(u5, 1);
1111 \\ }
1112 \\ return i;
1113 \\}
1114 });827 });
1115828
1116 cases.add("anonymous enum",829 cases.add_2("variable declarations",
1117 \\enum {830 \\extern char arr0[] = "hello";
1118 \\ One,831 \\static char arr1[] = "hello";
1119 \\ Two,832 \\char arr2[] = "hello";
1120 \\};
1121 , &[_][]const u8{833 , &[_][]const u8{
1122 \\pub const One = 0;834 \\pub extern var arr0: [*c]u8 = "hello";
1123 \\pub const Two = 1;835 \\pub var arr1: [*c]u8 = "hello";
836 \\pub export var arr2: [*c]u8 = "hello";
1124 });837 });
1125838
1126 cases.addC("function call",839 cases.add_2("array initializer expr",
1127 \\static void bar(void) { }840 \\static void foo(void){
1128 \\static int baz(void) { return 0; }841 \\ char arr[10] ={1};
1129 \\void foo(void) {842 \\ char *arr1[10] ={0};
1130 \\ bar();
1131 \\ baz();
1132 \\}843 \\}
1133 , &[_][]const u8{844 , &[_][]const u8{
1134 \\pub fn bar() void {}845 \\pub fn foo() void {
1135 \\pub fn baz() c_int {846 \\ var arr: [10]u8 = .{
1136 \\ return 0;847 \\ @as(u8, 1),
1137 \\}848 \\ } ++ .{0} ** 9;
1138 \\pub export fn foo() void {849 \\ var arr1: [10][*c]u8 = .{
1139 \\ bar();850 \\ null,
1140 \\ _ = baz();851 \\ } ++ .{null} ** 9;
1141 \\}852 \\}
1142 });853 });
1143854
1144 cases.addC("field access expression",855 cases.add_2("enums",
1145 \\struct Foo {856 \\typedef enum {
1146 \\ int field;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,
1147 \\};878 \\};
1148 \\int read_field(struct Foo *foo) {
1149 \\ return foo->field;
1150 \\}
1151 , &[_][]const u8{879 , &[_][]const u8{
1152 \\pub const struct_Foo = extern struct {880 \\pub const a = 0;
1153 \\ field: c_int,881 \\pub const b = 1;
882 \\pub const c = 2;
883 \\const enum_unnamed_1 = extern enum {
884 \\ a,
885 \\ b,
886 \\ c,
1154 \\};887 \\};
1155 \\pub export fn read_field(foo: [*c]struct_Foo) c_int {888 \\pub const d = enum_unnamed_1;
1156 \\ return foo.*.field;889 \\pub const e = 0;
1157 \\}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;
1158 });920 });
1159921
1160 cases.addC("null statements",922 cases.add_2("#define a char literal",
1161 \\void foo(void) {923 \\#define A_CHAR 'a'
1162 \\ ;;;;;
1163 \\}
1164 , &[_][]const u8{924 , &[_][]const u8{
1165 \\pub export fn foo() void {925 \\pub const A_CHAR = 'a';
1166 \\ {}
1167 \\ {}
1168 \\ {}
1169 \\ {}
1170 \\ {}
1171 \\}
1172 });926 });
1173927
1174 cases.add("undefined array global",928 cases.add_2("comment after integer literal",
1175 \\int array[100];929 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1176 , &[_][]const u8{930 , &[_][]const u8{
1177 \\pub var array: [100]c_int = undefined;931 \\pub const SDL_INIT_VIDEO = 0x00000020;
1178 });932 });
1179933
1180 cases.addC("array access",934 cases.add_2("u integer suffix after hex literal",
1181 \\int array[100];935 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1182 \\int foo(int index) {
1183 \\ return array[index];
1184 \\}
1185 , &[_][]const u8{936 , &[_][]const u8{
1186 \\pub var array: [100]c_int = undefined;937 \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020);
1187 \\pub export fn foo(index: c_int) c_int {
1188 \\ return array[index];
1189 \\}
1190 });938 });
1191939
1192 cases.addC("c style cast",940 cases.add_2("l integer suffix after hex literal",
1193 \\int float_to_int(float a) {941 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1194 \\ return (int)a;
1195 \\}
1196 , &[_][]const u8{942 , &[_][]const u8{
1197 \\pub export fn float_to_int(a: f32) c_int {943 \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020);
1198 \\ return @as(c_int, a);
1199 \\}
1200 });944 });
1201945
1202 cases.addC("void cast",946 cases.add_2("ul integer suffix after hex literal",
1203 \\void foo(int a) {947 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1204 \\ (void) a;
1205 \\}
1206 , &[_][]const u8{948 , &[_][]const u8{
1207 \\pub export fn foo(a: c_int) void {949 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1208 \\ _ = a;
1209 \\}
1210 });950 });
1211951
1212 cases.addC("implicit cast to void *",952 cases.add_2("lu integer suffix after hex literal",
1213 \\void *foo(unsigned short *x) {953 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1214 \\ return x;
1215 \\}
1216 , &[_][]const u8{954 , &[_][]const u8{
1217 \\pub export fn foo(x: [*c]c_ushort) ?*c_void {955 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020);
1218 \\ return @ptrCast(?*c_void, x);
1219 \\}
1220 });956 });
1221957
1222 cases.addC("sizeof",958 cases.add_2("ll integer suffix after hex literal",
1223 \\#include <stddef.h>959 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1224 \\size_t size_of(void) {
1225 \\ return sizeof(int);
1226 \\}
1227 , &[_][]const u8{960 , &[_][]const u8{
1228 \\pub export fn size_of() usize {961 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020);
1229 \\ return @sizeOf(c_int);
1230 \\}
1231 });962 });
1232963
1233 cases.addC("null pointer implicit cast",964 cases.add_2("ull integer suffix after hex literal",
1234 \\int* foo(void) {965 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1235 \\ return 0;
1236 \\}
1237 , &[_][]const u8{966 , &[_][]const u8{
1238 \\pub export fn foo() [*c]c_int {967 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1239 \\ return null;
1240 \\}
1241 });968 });
1242969
1243 cases.addC("comma operator",970 cases.add_2("llu integer suffix after hex literal",
1244 \\int foo(void) {971 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
1245 \\ return 1, 2;
1246 \\}
1247 , &[_][]const u8{972 , &[_][]const u8{
1248 \\pub export fn foo() c_int {973 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020);
1249 \\ return x: {
1250 \\ _ = 1;
1251 \\ break :x 2;
1252 \\ };
1253 \\}
1254 });974 });
1255975
1256 cases.addC("statement expression",976 cases.add_2("generate inline func for #define global extern fn",
1257 \\int foo(void) {977 \\extern void (*fn_ptr)(void);
1258 \\ return ({978 \\#define foo fn_ptr
1259 \\ int a = 1;979 \\
1260 \\ a;980 \\extern char (*fn_ptr2)(int, float);
1261 \\ });981 \\#define bar fn_ptr2
1262 \\}
1263 , &[_][]const u8{982 , &[_][]const u8{
1264 \\pub export fn foo() c_int {983 \\pub extern var fn_ptr: ?extern fn () void;
1265 \\ return x: {984 ,
1266 \\ var a: c_int = 1;985 \\pub inline fn foo() void {
1267 \\ break :x a;986 \\ return fn_ptr.?();
1268 \\ };
1269 \\}987 \\}
1270 });988 ,
1271989 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;
1272 cases.addC("__extension__ cast",990 ,
1273 \\int foo(void) {991 \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 {
1274 \\ return __extension__ 1;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);
1275 \\}1165 \\}
1276 , &[_][]const u8{1166 , &[_][]const u8{
1277 \\pub export fn foo() c_int {1167 \\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 \\ }
1279 \\}1185 \\}
1280 });1186 });
12811187
1282 cases.addC("bitshift",1188 cases.add_2("for loops",
1283 \\int foo(void) {1189 \\int foo() {
1284 \\ return (1 << 2) >> 1;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;
1285 \\}1195 \\}
1286 , &[_][]const u8{1196 , &[_][]const u8{
1287 \\pub export fn foo() c_int {1197 \\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);
1289 \\}1209 \\}
1290 });1210 });
12911211
1292 cases.addC("compound assignment operators",1212 cases.add_2("shadowing primitive types",
1293 \\void foo(void) {1213 \\unsigned anyerror = 2;
1294 \\ int a = 0;1214 , &[_][]const u8{
1295 \\ a += (a += 1);1215 \\pub export var _anyerror: c_uint = @as(c_uint, 2);
1296 \\ a -= (a -= 1);1216 });
1297 \\ a *= (a *= 1);1217
1298 \\ a &= (a &= 1);1218 cases.add_2("floats",
1299 \\ a |= (a |= 1);1219 \\float a = 3.1415;
1300 \\ a ^= (a ^= 1);1220 \\double b = 3.1415;
1301 \\ a >>= (a >>= 1);1221 \\int c = 3.1415;
1302 \\ a <<= (a <<= 1);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;
1303 \\}1234 \\}
1304 , &[_][]const u8{1235 , &[_][]const u8{
1305 \\pub export fn foo() void {1236 \\pub export fn bar() c_int {
1306 \\ var a: c_int = 0;1237 \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2;
1307 \\ a += (x: {1238 \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6;
1308 \\ const _ref = &a;1239 \\}
1309 \\ _ref.* = (_ref.* + 1);1240 });
1310 \\ break :x _ref.*;1241
1311 \\ });1242 cases.add_2("switch on int",
1312 \\ a -= (x: {1243 \\int switch_fn(int i) {
1313 \\ const _ref = &a;1244 \\ int res = 0;
1314 \\ _ref.* = (_ref.* - 1);1245 \\ switch (i) {
1315 \\ break :x _ref.*;1246 \\ case 0:
1316 \\ });1247 \\ res = 1;
1317 \\ a *= (x: {1248 \\ case 1 ... 3:
1318 \\ const _ref = &a;1249 \\ res = 2;
1319 \\ _ref.* = (_ref.* * 1);1250 \\ default:
1320 \\ break :x _ref.*;1251 \\ res = 3 * i;
1321 \\ });1252 \\ break;
1322 \\ a &= (x: {1253 \\ case 4:
1323 \\ const _ref = &a;1254 \\ res = 5;
1324 \\ _ref.* = (_ref.* & 1);1255 \\ }
1325 \\ break :x _ref.*;1256 \\}
1326 \\ });1257 , &[_][]const u8{
1327 \\ a |= (x: {1258 \\pub export fn switch_fn(_arg_i: c_int) c_int {
1328 \\ const _ref = &a;1259 \\ var i = _arg_i;
1329 \\ _ref.* = (_ref.* | 1);1260 \\ var res: c_int = 0;
1330 \\ break :x _ref.*;1261 \\ __switch: {
1331 \\ });1262 \\ __case_2: {
1332 \\ a ^= (x: {1263 \\ __default: {
1333 \\ const _ref = &a;1264 \\ __case_1: {
1334 \\ _ref.* = (_ref.* ^ 1);1265 \\ __case_0: {
1335 \\ break :x _ref.*;1266 \\ switch (i) {
1336 \\ });1267 \\ 0 => break :__case_0,
1337 \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: {1268 \\ 1...3 => break :__case_1,
1338 \\ const _ref = &a;1269 \\ else => break :__default,
1339 \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));1270 \\ 4 => break :__case_2,
1340 \\ break :x _ref.*;1271 \\ }
1341 \\ }));1272 \\ }
1342 \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: {1273 \\ res = 1;
1343 \\ const _ref = &a;1274 \\ }
1344 \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));1275 \\ res = 2;
1345 \\ break :x _ref.*;1276 \\ }
1346 \\ }));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;
1347 \\}1318 \\}
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;
1348 });2432 });
13492433
1350 cases.addC("compound assignment operators unsigned",2434 cases.addC("assign",
1351 \\void foo(void) {2435 \\int max(int a) {
1352 \\ unsigned a = 0;2436 \\ int tmp;
1353 \\ a += (a += 1);2437 \\ tmp = a;
1354 \\ a -= (a -= 1);2438 \\ a = tmp;
1355 \\ a *= (a *= 1);
1356 \\ a &= (a &= 1);
1357 \\ a |= (a |= 1);
1358 \\ a ^= (a ^= 1);
1359 \\ a >>= (a >>= 1);
1360 \\ a <<= (a <<= 1);
1361 \\}2439 \\}
1362 , &[_][]const u8{2440 , &[_][]const u8{
1363 \\pub export fn foo() void {2441 \\pub export fn max(_arg_a: c_int) c_int {
1364 \\ var a: c_uint = @as(c_uint, 0);2442 \\ var a = _arg_a;
1365 \\ a +%= (x: {2443 \\ var tmp: c_int = undefined;
1366 \\ const _ref = &a;2444 \\ tmp = a;
1367 \\ _ref.* = (_ref.* +% @as(c_uint, 1));2445 \\ a = tmp;
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 \\ }));
1405 \\}2446 \\}
1406 });2447 });
14072448
1408 cases.addC("post increment/decrement",2449 cases.addC("chaining assign",
1409 \\void foo(void) {2450 \\void max(int a) {
1410 \\ int i = 0;2451 \\ int b, c;
1411 \\ unsigned u = 0;2452 \\ c = b = a;
1412 \\ i++;
1413 \\ i--;
1414 \\ u++;
1415 \\ u--;
1416 \\ i = i++;
1417 \\ i = i--;
1418 \\ u = u++;
1419 \\ u = u--;
1420 \\}2453 \\}
1421 , &[_][]const u8{2454 , &[_][]const u8{
1422 \\pub export fn foo() void {2455 \\pub export fn max(a: c_int) void {
1423 \\ var i: c_int = 0;2456 \\ var b: c_int = undefined;
1424 \\ var u: c_uint = @as(c_uint, 0);2457 \\ var c: c_int = undefined;
1425 \\ i += 1;2458 \\ c = (x: {
1426 \\ i -= 1;2459 \\ const _tmp = a;
1427 \\ u +%= 1;2460 \\ b = _tmp;
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;
1451 \\ break :x _tmp;2461 \\ break :x _tmp;
1452 \\ });2462 \\ });
1453 \\}2463 \\}
1454 });2464 });
14552465
1456 cases.addC("pre increment/decrement",2466 cases.add("anonymous enum",
1457 \\void foo(void) {2467 \\enum {
1458 \\ int i = 0;2468 \\ One,
1459 \\ unsigned u = 0;2469 \\ Two,
1460 \\ ++i;2470 \\};
1461 \\ --i;
1462 \\ ++u;
1463 \\ --u;
1464 \\ i = ++i;
1465 \\ i = --i;
1466 \\ u = ++u;
1467 \\ u = --u;
1468 \\}
1469 , &[_][]const u8{2471 , &[_][]const u8{
1470 \\pub export fn foo() void {2472 \\pub const One = 0;
1471 \\ var i: c_int = 0;2473 \\pub const Two = 1;
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 \\}
1498 });2474 });
14992475
1500 cases.addC("do loop",2476 cases.addC("c style cast",
1501 \\void foo(void) {2477 \\int float_to_int(float a) {
1502 \\ int a = 2;2478 \\ return (int)a;
1503 \\ do {
1504 \\ a--;
1505 \\ } while (a != 0);
1506 \\
1507 \\ int b = 2;
1508 \\ do
1509 \\ b--;
1510 \\ while (b != 0);
1511 \\}2479 \\}
1512 , &[_][]const u8{2480 , &[_][]const u8{
1513 \\pub export fn foo() void {2481 \\pub export fn float_to_int(a: f32) c_int {
1514 \\ var a: c_int = 2;2482 \\ return @as(c_int, a);
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 \\ }
1524 \\}2483 \\}
1525 });2484 });
15262485
1527 cases.addC("deref function pointer",2486 cases.addC("comma operator",
1528 \\void foo(void) {}2487 \\int foo(void) {
1529 \\int baz(void) { return 0; }2488 \\ return 1, 2;
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();
1539 \\}2489 \\}
1540 , &[_][]const u8{2490 , &[_][]const u8{
1541 \\pub export fn foo() void {}2491 \\pub export fn foo() c_int {
1542 \\pub export fn baz() c_int {2492 \\ return x: {
1543 \\ return 0;2493 \\ _ = 1;
1544 \\}2494 \\ break :x 2;
1545 \\pub export fn bar() void {2495 \\ };
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();
1554 \\}2496 \\}
1555 });2497 });
15562498
1557 cases.addC("normal deref",2499 cases.addC("escape sequences",
1558 \\void foo(int *x) {2500 \\const char *escapes() {
1559 \\ *x = 1;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\"";
1560 \\}2513 \\}
2514 \\
1561 , &[_][]const u8{2515 , &[_][]const u8{
1562 \\pub export fn foo(x: [*c]c_int) void {2516 \\pub export fn escapes() [*c]const u8 {
1563 \\ x.?.* = 1;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\"";
1564 \\}2529 \\}
2530 \\
1565 });2531 });
15662532
1567 cases.add("simple union",2533 cases.addC("do loop",
1568 \\union Foo {2534 \\void foo(void) {
1569 \\ int x;2535 \\ int a = 2;
1570 \\ double y;2536 \\ do {
1571 \\};2537 \\ a--;
2538 \\ } while (a != 0);
2539 \\
2540 \\ int b = 2;
2541 \\ do
2542 \\ b--;
2543 \\ while (b != 0);
2544 \\}
1572 , &[_][]const u8{2545 , &[_][]const u8{
1573 \\pub const union_Foo = extern union {2546 \\pub export fn foo() void {
1574 \\ x: c_int,2547 \\ var a: c_int = 2;
1575 \\ y: f64,2548 \\ while (true) {
1576 \\};2549 \\ a -= 1;
1577 ,2550 \\ if (!(a != 0)) break;
1578 \\pub const Foo = union_Foo;2551 \\ }
2552 \\ var b: c_int = 2;
2553 \\ while (true) {
2554 \\ b -= 1;
2555 \\ if (!(b != 0)) break;
2556 \\ }
2557 \\}
1579 });2558 });
15802559
1581 cases.add("address of operator",2560 cases.addC("==, !=",
1582 \\int foo(void) {2561 \\int max(int a, int b) {
1583 \\ int x = 1234;2562 \\ if (a == b)
1584 \\ int *ptr = &x;2563 \\ return a;
1585 \\ return *ptr;2564 \\ if (a != b)
2565 \\ return b;
2566 \\ return a;
1586 \\}2567 \\}
1587 , &[_][]const u8{2568 , &[_][]const u8{
1588 \\pub fn foo() c_int {2569 \\pub export fn max(a: c_int, b: c_int) c_int {
1589 \\ var x: c_int = 1234;2570 \\ if (a == b) return a;
1590 \\ var ptr: [*c]c_int = &x;2571 \\ if (a != b) return b;
1591 \\ return ptr.?.*;2572 \\ return a;
1592 \\}2573 \\}
1593 });2574 });
15942575
1595 cases.add("string literal",2576 cases.addC("bitwise binary operators",
1596 \\const char *foo(void) {2577 \\int max(int a, int b) {
1597 \\ return "bar";2578 \\ return (a & b) ^ (a | b);
1598 \\}2579 \\}
1599 , &[_][]const u8{2580 , &[_][]const u8{
1600 \\pub fn foo() [*c]const u8 {2581 \\pub export fn max(a: c_int, b: c_int) c_int {
1601 \\ return "bar";2582 \\ return (a & b) ^ (a | b);
1602 \\}2583 \\}
1603 });2584 });
16042585
1605 cases.add("return void",2586 cases.addC("statement expression",
1606 \\void foo(void) {2587 \\int foo(void) {
1607 \\ return;2588 \\ return ({
2589 \\ int a = 1;
2590 \\ a;
2591 \\ });
1608 \\}2592 \\}
1609 , &[_][]const u8{2593 , &[_][]const u8{
1610 \\pub fn foo() void {2594 \\pub export fn foo() c_int {
1611 \\ return;2595 \\ return x: {
2596 \\ var a: c_int = 1;
2597 \\ break :x a;
2598 \\ };
1612 \\}2599 \\}
1613 });2600 });
16142601
1615 cases.add("for loop",2602 cases.addC("field access expression",
1616 \\void foo(void) {2603 \\struct Foo {
1617 \\ for (int i = 0; i < 10; i += 1) { }2604 \\ int field;
2605 \\};
2606 \\int read_field(struct Foo *foo) {
2607 \\ return foo->field;
1618 \\}2608 \\}
1619 , &[_][]const u8{2609 , &[_][]const u8{
1620 \\pub fn foo() void {2610 \\pub const struct_Foo = extern struct {
1621 \\ {2611 \\ field: c_int,
1622 \\ var i: c_int = 0;2612 \\};
1623 \\ while (i < 10) : (i += 1) {}2613 \\pub export fn read_field(foo: [*c]struct_Foo) c_int {
1624 \\ }2614 \\ return foo.*.field;
1625 \\}2615 \\}
1626 });2616 });
16272617
1628 cases.add("empty for loop",2618 cases.addC("array access",
1629 \\void foo(void) {2619 \\int array[100];
1630 \\ for (;;) { }2620 \\int foo(int index) {
2621 \\ return array[index];
1631 \\}2622 \\}
1632 , &[_][]const u8{2623 , &[_][]const u8{
1633 \\pub fn foo() void {2624 \\pub var array: [100]c_int = undefined;
1634 \\ while (true) {}2625 \\pub export fn foo(index: c_int) c_int {
2626 \\ return array[index];
1635 \\}2627 \\}
1636 });2628 });
16372629
1638 cases.add("break statement",2630 cases.addC("logical and, logical or",
1639 \\void foo(void) {2631 \\int max(int a, int b) {
1640 \\ for (;;) {2632 \\ if (a < b || a == b)
1641 \\ break;2633 \\ return b;
1642 \\ }2634 \\ if (a >= b && a == b)
2635 \\ return a;
2636 \\ return a;
1643 \\}2637 \\}
1644 , &[_][]const u8{2638 , &[_][]const u8{
1645 \\pub fn foo() void {2639 \\pub export fn max(a: c_int, b: c_int) c_int {
1646 \\ while (true) {2640 \\ if ((a < b) or (a == b)) return b;
1647 \\ break;2641 \\ if ((a >= b) and (a == b)) return a;
1648 \\ }2642 \\ return a;
1649 \\}2643 \\}
1650 });2644 });
16512645
1652 cases.add("continue statement",2646 cases.addC("if statement",
1653 \\void foo(void) {2647 \\int max(int a, int b) {
1654 \\ for (;;) {2648 \\ if (a < b)
1655 \\ continue;2649 \\ return b;
1656 \\ }2650 \\
2651 \\ if (a < b)
2652 \\ return b;
2653 \\ else
2654 \\ return a;
2655 \\
2656 \\ if (a < b) ; else ;
1657 \\}2657 \\}
1658 , &[_][]const u8{2658 , &[_][]const u8{
1659 \\pub fn foo() void {2659 \\pub export fn max(a: c_int, b: c_int) c_int {
1660 \\ while (true) {2660 \\ if (a < b) return b;
1661 \\ continue;2661 \\ if (a < b) return b else return a;
1662 \\ }2662 \\ if (a < b) {} else {}
1663 \\}2663 \\}
1664 });2664 });
16652665
...@@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1683 \\}2683 \\}
1684 });2684 });
16852685
1686 cases.add("pointer casting",2686 cases.add("if on non-bool",
1687 \\float *ptrcast(int *a) {2687 \\enum SomeEnum { A, B, C };
1688 \\ return (float *)a;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;
1689 \\}2694 \\}
1690 , &[_][]const u8{2695 , &[_][]const u8{
1691 \\fn ptrcast(a: [*c]c_int) [*c]f32 {2696 \\pub const A = enum_SomeEnum.A;
1692 \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), 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;
1693 \\}2710 \\}
1694 });2711 });
16952712
1696 cases.add("bin not",2713 cases.addAllowWarnings("simple data types",
1697 \\int foo(int x) {2714 \\#include <stdint.h>
1698 \\ return ~x;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;
1699 \\}2730 \\}
1700 , &[_][]const u8{2731 , &[_][]const u8{
1701 \\pub fn foo(x: c_int) c_int {2732 \\pub export fn abs(a: c_int) c_int {
1702 \\ return ~x;2733 \\ return if (a < 0) -a else a;
1703 \\}2734 \\}
1704 });2735 });
17052736
1706 cases.add("bool not",2737 cases.addC("post increment",
1707 \\int foo(int a, float b, void *c) {2738 \\unsigned foo1(unsigned a) {
1708 \\ return !(a == 0);2739 \\ a++;
1709 \\ return !a;2740 \\ return a;
1710 \\ return !b;2741 \\}
1711 \\ return !c;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;
1712 \\}2801 \\}
1713 , &[_][]const u8{2802 , &[_][]const u8{
1714 \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {2803 \\pub export fn foo() void {
1715 \\ return !(a == 0);2804 \\ var i: c_int = 0;
1716 \\ return !(a != 0);2805 \\ var u: c_uint = @as(c_uint, 0);
1717 \\ return !(b != 0);2806 \\ i += 1;
1718 \\ return !(c != null);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 \\ });
1719 \\}2830 \\}
1720 });2831 });
17212832
1722 cases.add("primitive types included in defined symbols",2833 cases.addC("shift right assign",
1723 \\int foo(int u32) {2834 \\int log2(unsigned a) {
1724 \\ return u32;2835 \\ int i = 0;
2836 \\ while (a > 0) {
2837 \\ a >>= 1;
2838 \\ }
2839 \\ return i;
1725 \\}2840 \\}
1726 , &[_][]const u8{2841 , &[_][]const u8{
1727 \\pub fn foo(u32_0: c_int) c_int {2842 \\pub export fn log2(_arg_a: c_uint) c_int {
1728 \\ return u32_0;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;
1729 \\}2849 \\}
1730 });2850 });
17312851
1732 cases.add("if on non-bool",2852 cases.addC("shift right assign with a fixed size type",
1733 \\enum SomeEnum { A, B, C };2853 \\#include <stdint.h>
1734 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {2854 \\int log2(uint32_t a) {
1735 \\ if (a) return 0;2855 \\ int i = 0;
1736 \\ if (b) return 1;2856 \\ while (a > 0) {
1737 \\ if (c) return 2;2857 \\ a >>= 1;
1738 \\ if (d) return 3;2858 \\ }
1739 \\ return 4;2859 \\ return i;
1740 \\}2860 \\}
1741 , &[_][]const u8{2861 , &[_][]const u8{
1742 \\pub const A = enum_SomeEnum.A;2862 \\pub export fn log2(_arg_a: u32) c_int {
1743 \\pub const B = enum_SomeEnum.B;2863 \\ var a = _arg_a;
1744 \\pub const C = enum_SomeEnum.C;2864 \\ var i: c_int = 0;
1745 \\pub const enum_SomeEnum = extern enum {2865 \\ while (a > @as(c_uint, 0)) {
1746 \\ A,2866 \\ a >>= @as(u5, 1);
1747 \\ B,2867 \\ }
1748 \\ C,2868 \\ return i;
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;
1756 \\}2869 \\}
1757 });2870 });
17582871
1759 cases.add("while on non-bool",2872 cases.addC("compound assignment operators",
1760 \\int while_none_bool(int a, float b, void *c) {2873 \\void foo(void) {
1761 \\ while (a) return 0;2874 \\ int a = 0;
1762 \\ while (b) return 1;2875 \\ a += (a += 1);
1763 \\ while (c) return 2;2876 \\ a -= (a -= 1);
1764 \\ return 3;2877 \\ a *= (a *= 1);
2878 \\ a &= (a &= 1);
2879 \\ a |= (a |= 1);
2880 \\ a ^= (a ^= 1);
2881 \\ a >>= (a >>= 1);
2882 \\ a <<= (a <<= 1);
1765 \\}2883 \\}
1766 , &[_][]const u8{2884 , &[_][]const u8{
1767 \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {2885 \\pub export fn foo() void {
1768 \\ while (a != 0) return 0;2886 \\ var a: c_int = 0;
1769 \\ while (b != 0) return 1;2887 \\ a += (x: {
1770 \\ while (c != null) return 2;2888 \\ const _ref = &a;
1771 \\ return 3;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 \\ }));
1772 \\}2927 \\}
1773 });2928 });
17742929
1775 cases.add("for on non-bool",2930 cases.addC("compound assignment operators unsigned",
1776 \\int for_none_bool(int a, float b, void *c) {2931 \\void foo(void) {
1777 \\ for (;a;) return 0;2932 \\ unsigned a = 0;
1778 \\ for (;b;) return 1;2933 \\ a += (a += 1);
1779 \\ for (;c;) return 2;2934 \\ a -= (a -= 1);
1780 \\ return 3;2935 \\ a *= (a *= 1);
2936 \\ a &= (a &= 1);
2937 \\ a |= (a |= 1);
2938 \\ a ^= (a ^= 1);
2939 \\ a >>= (a >>= 1);
2940 \\ a <<= (a <<= 1);
1781 \\}2941 \\}
1782 , &[_][]const u8{2942 , &[_][]const u8{
1783 \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {2943 \\pub export fn foo() void {
1784 \\ while (a != 0) return 0;2944 \\ var a: c_uint = @as(c_uint, 0);
1785 \\ while (b != 0) return 1;2945 \\ a +%= (x: {
1786 \\ while (c != null) return 2;2946 \\ const _ref = &a;
1787 \\ return 3;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 \\ }));
1788 \\}2985 \\}
1789 });2986 });
17902987
1791 cases.add("switch on int",2988 cases.addC("post increment/decrement",
1792 \\int switch_fn(int i) {2989 \\void foo(void) {
1793 \\ int res = 0;2990 \\ int i = 0;
1794 \\ switch (i) {2991 \\ unsigned u = 0;
1795 \\ case 0:2992 \\ i++;
1796 \\ res = 1;2993 \\ i--;
1797 \\ case 1:2994 \\ u++;
1798 \\ res = 2;2995 \\ u--;
1799 \\ default:2996 \\ i = i++;
1800 \\ res = 3 * i;2997 \\ i = i--;
1801 \\ break;2998 \\ u = u++;
1802 \\ case 2:2999 \\ u = u--;
1803 \\ res = 5;
1804 \\ }
1805 \\}3000 \\}
1806 , &[_][]const u8{3001 , &[_][]const u8{
1807 \\pub fn switch_fn(i: c_int) c_int {3002 \\pub export fn foo() void {
1808 \\ var res: c_int = 0;3003 \\ var i: c_int = 0;
1809 \\ __switch: {3004 \\ var u: c_uint = @as(c_uint, 0);
1810 \\ __case_2: {3005 \\ i += 1;
1811 \\ __default: {3006 \\ i -= 1;
1812 \\ __case_1: {3007 \\ u +%= 1;
1813 \\ __case_0: {3008 \\ u -%= 1;
1814 \\ switch (i) {3009 \\ i = (x: {
1815 \\ 0 => break :__case_0,3010 \\ const _ref = &i;
1816 \\ 1 => break :__case_1,3011 \\ const _tmp = _ref.*;
1817 \\ else => break :__default,3012 \\ _ref.* += 1;
1818 \\ 2 => break :__case_2,3013 \\ break :x _tmp;
1819 \\ }3014 \\ });
1820 \\ }3015 \\ i = (x: {
1821 \\ res = 1;3016 \\ const _ref = &i;
1822 \\ }3017 \\ const _tmp = _ref.*;
1823 \\ res = 2;3018 \\ _ref.* -= 1;
1824 \\ }3019 \\ break :x _tmp;
1825 \\ res = (3 * i);3020 \\ });
1826 \\ break :__switch;3021 \\ u = (x: {
1827 \\ }3022 \\ const _ref = &u;
1828 \\ res = 5;3023 \\ const _tmp = _ref.*;
1829 \\ }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 \\ });
1830 \\}3033 \\}
1831 });3034 });
18323035
...@@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1885 \\}3088 \\}
1886 });3089 });
18873090
1888 cases.addC("pointer conversion with different alignment",3091 cases.addC("function call",
1889 \\void test_ptr_cast() {3092 \\static void bar(void) { }
1890 \\ void *p;3093 \\void foo(int *(baz)(void)) {
1891 \\ {3094 \\ bar();
1892 \\ char *to_char = (char *)p;3095 \\ baz();
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\"";
1936 \\}3096 \\}
1937 \\
1938 , &[_][]const u8{3097 , &[_][]const u8{
1939 \\pub export fn escapes() [*c]const u8 {3098 \\pub fn bar() void {}
1940 \\ var a: u8 = @as(u8, '\'');3099 \\pub export fn foo(baz: ?extern fn () [*c]c_int) void {
1941 \\ var b: u8 = @as(u8, '\\');3100 \\ bar();
1942 \\ var c: u8 = @as(u8, '\x07');3101 \\ _ = baz.?();
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\"";
1952 \\}3102 \\}
1953 \\
1954 });3103 });
19553104
1956 if (builtin.os != builtin.Os.windows) {3105 cases.add("macro defines string literal with hex",
1957 // sysv_abi not currently supported on windows3106 \\#define FOO "aoeu\xab derp"
1958 cases.add("Macro qualified functions",3107 \\#define FOO2 "aoeu\x0007a derp"
1959 \\void __attribute__((sysv_abi)) foo(void);3108 \\#define FOO_CHAR '\xfF'
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) {}
1969 , &[_][]const u8{3109 , &[_][]const u8{
1970 \\pub export fn foo() void {}3110 \\pub const FOO = "aoeu\xab derp";
1971 \\pub export fn bar() void {}3111 ,
3112 \\pub const FOO2 = "aoeuz derp";
3113 ,
3114 \\pub const FOO_CHAR = 255;
1972 });3115 });
19733116
1974 cases.add("#define a char literal",3117 cases.add("macro defines string literal with octal",
1975 \\#define A_CHAR 'a'3118 \\#define FOO "aoeu\023 derp"
3119 \\#define FOO2 "aoeu\0234 derp"
3120 \\#define FOO_CHAR '\077'
1976 , &[_][]const u8{3121 , &[_][]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;
1978 });3127 });
19793128
1980 cases.add("generate inline func for #define global extern fn",3129 cases.add("enums",
1981 \\extern void (*fn_ptr)(void);3130 \\enum Foo {
1982 \\#define foo fn_ptr3131 \\ FooA,
1983 \\3132 \\ FooB,
1984 \\extern char (*fn_ptr2)(int, float);3133 \\ Foo1,
1985 \\#define bar fn_ptr23134 \\};
1986 , &[_][]const u8{3135 , &[_][]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 \\};
1988 ,3141 ,
1989 \\pub inline fn foo() void {3142 \\pub const FooA = enum_Foo.A;
1990 \\ return fn_ptr.?();
1991 \\}
1992 ,3143 ,
1993 \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8;3144 \\pub const FooB = enum_Foo.B;
1994 ,3145 ,
1995 \\pub inline fn bar(arg0: c_int, arg1: f32) u8 {3146 \\pub const Foo1 = enum_Foo.@"1";
1996 \\ return fn_ptr2.?(arg0, arg1);3147 ,
1997 \\}3148 \\pub const Foo = enum_Foo;
1998 });
1999 cases.add("comment after integer literal",
2000 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2001 , &[_][]const u8{
2002 \\pub const SDL_INIT_VIDEO = 32;
2003 });
2004
2005 cases.add("u integer suffix after hex literal",
2006 \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2007 , &[_][]const u8{
2008 \\pub const SDL_INIT_VIDEO = @as(c_uint, 32);
2009 });
2010
2011 cases.add("l integer suffix after hex literal",
2012 \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2013 , &[_][]const u8{
2014 \\pub const SDL_INIT_VIDEO = @as(c_long, 32);
2015 });
2016
2017 cases.add("ul integer suffix after hex literal",
2018 \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2019 , &[_][]const u8{
2020 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2021 });
2022
2023 cases.add("lu integer suffix after hex literal",
2024 \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2025 , &[_][]const u8{
2026 \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32);
2027 });
2028
2029 cases.add("ll integer suffix after hex literal",
2030 \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2031 , &[_][]const u8{
2032 \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32);
2033 });
2034
2035 cases.add("ull integer suffix after hex literal",
2036 \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2037 , &[_][]const u8{
2038 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2039 });
2040
2041 cases.add("llu integer suffix after hex literal",
2042 \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2043 , &[_][]const u8{
2044 \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32);
2045 });3149 });
20463150
2047 cases.add("macros with field targets",3151 cases.add("enums",
2048 \\typedef unsigned int GLbitfield;3152 \\enum Foo {
2049 \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);3153 \\ FooA = 2,
2050 \\typedef void(*OpenGLProc)(void);3154 \\ FooB = 5,
2051 \\union OpenGLProcs {3155 \\ Foo1,
2052 \\ OpenGLProc ptr[1];
2053 \\ struct {
2054 \\ PFNGLCLEARPROC Clear;
2055 \\ } gl;
2056 \\};3156 \\};
2057 \\extern union OpenGLProcs glProcs;
2058 \\#define glClearUnion glProcs.gl.Clear
2059 \\#define glClearPFN PFNGLCLEARPROC
2060 , &[_][]const u8{3157 , &[_][]const u8{
2061 \\pub const GLbitfield = c_uint;3158 \\pub const enum_Foo = extern enum {
2062 ,3159 \\ A = 2,
2063 \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void;3160 \\ B = 5,
2064 ,3161 \\ @"1" = 6,
2065 \\pub const OpenGLProc = ?extern fn () void;
2066 ,
2067 \\pub const union_OpenGLProcs = extern union {
2068 \\ ptr: [1]OpenGLProc,
2069 \\ gl: extern struct {
2070 \\ Clear: PFNGLCLEARPROC,
2071 \\ },
2072 \\};3162 \\};
2073 ,3163 ,
2074 \\pub extern var glProcs: union_OpenGLProcs;3164 \\pub const FooA = enum_Foo.A;
2075 ,3165 ,
2076 \\pub const glClearPFN = PFNGLCLEARPROC;3166 \\pub const FooB = enum_Foo.B;
2077 ,3167 ,
2078 \\pub inline fn glClearUnion(arg0: GLbitfield) void {3168 \\pub const Foo1 = enum_Foo.@"1";
2079 \\ return glProcs.gl.Clear.?(arg0);
2080 \\}
2081 ,3169 ,
2082 \\pub const OpenGLProcs = union_OpenGLProcs;3170 \\pub const Foo = enum_Foo;
2083 });
2084
2085 cases.add("macro pointer cast",
2086 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
2087 , &[_][]const u8{
2088 \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
2089 });3171 });
2090}3172}