| author | |
| committer | |
| log | 28dbdba37eed0cfd875cfc337446da3048743dd9 |
| tree | 71d3d4479809da72c5410e7dd49855805f25abe5 |
| parent | ba1d213f480eb0cb7c8641a8d8cb1d6763e82438 |
| parent | 9d31b65b34a222ff8b11d5bcaefcfc3c22ef4250 |
| signature |
Translate-c-2 the rest10 files changed, 5146 insertions(+), 2288 deletions(-)
lib/std/fmt.zig+3-1| ... | ... | @@ -582,7 +582,9 @@ pub fn formatAsciiChar( |
| 582 | 582 | comptime Errors: type, |
| 583 | 583 | output: fn (@TypeOf(context), []const u8) Errors!void, |
| 584 | 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 | } |
| 587 | 589 | |
| 588 | 590 | pub fn formatBuf( |
lib/std/zig/ast.zig+16-16| ... | ... | @@ -1431,13 +1431,13 @@ pub const Node = struct { |
| 1431 | 1431 | AssignBitShiftRight, |
| 1432 | 1432 | AssignBitXor, |
| 1433 | 1433 | AssignDiv, |
| 1434 | AssignMinus, | |
| 1435 | AssignMinusWrap, | |
| 1434 | AssignSub, | |
| 1435 | AssignSubWrap, | |
| 1436 | 1436 | AssignMod, |
| 1437 | AssignPlus, | |
| 1438 | AssignPlusWrap, | |
| 1439 | AssignTimes, | |
| 1440 | AssignTimesWarp, | |
| 1437 | AssignAdd, | |
| 1438 | AssignAddWrap, | |
| 1439 | AssignMul, | |
| 1440 | AssignMulWrap, | |
| 1441 | 1441 | BangEqual, |
| 1442 | 1442 | BitAnd, |
| 1443 | 1443 | BitOr, |
| ... | ... | @@ -1456,8 +1456,8 @@ pub const Node = struct { |
| 1456 | 1456 | LessThan, |
| 1457 | 1457 | MergeErrorSets, |
| 1458 | 1458 | Mod, |
| 1459 | Mult, | |
| 1460 | MultWrap, | |
| 1459 | Mul, | |
| 1460 | MulWrap, | |
| 1461 | 1461 | Period, |
| 1462 | 1462 | Range, |
| 1463 | 1463 | Sub, |
| ... | ... | @@ -1490,13 +1490,13 @@ pub const Node = struct { |
| 1490 | 1490 | Op.AssignBitShiftRight, |
| 1491 | 1491 | Op.AssignBitXor, |
| 1492 | 1492 | Op.AssignDiv, |
| 1493 | Op.AssignMinus, | |
| 1494 | Op.AssignMinusWrap, | |
| 1493 | Op.AssignSub, | |
| 1494 | Op.AssignSubWrap, | |
| 1495 | 1495 | Op.AssignMod, |
| 1496 | Op.AssignPlus, | |
| 1497 | Op.AssignPlusWrap, | |
| 1498 | Op.AssignTimes, | |
| 1499 | Op.AssignTimesWarp, | |
| 1496 | Op.AssignAdd, | |
| 1497 | Op.AssignAddWrap, | |
| 1498 | Op.AssignMul, | |
| 1499 | Op.AssignMulWrap, | |
| 1500 | 1500 | Op.BangEqual, |
| 1501 | 1501 | Op.BitAnd, |
| 1502 | 1502 | Op.BitOr, |
| ... | ... | @@ -1514,8 +1514,8 @@ pub const Node = struct { |
| 1514 | 1514 | Op.LessThan, |
| 1515 | 1515 | Op.MergeErrorSets, |
| 1516 | 1516 | Op.Mod, |
| 1517 | Op.Mult, | |
| 1518 | Op.MultWrap, | |
| 1517 | Op.Mul, | |
| 1518 | Op.MulWrap, | |
| 1519 | 1519 | Op.Period, |
| 1520 | 1520 | Op.Range, |
| 1521 | 1521 | Op.Sub, |
lib/std/zig/parse.zig+8-8| ... | ... | @@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1981 | 1981 | |
| 1982 | 1982 | const token = nextToken(it); |
| 1983 | 1983 | const op = switch (token.ptr.id) { |
| 1984 | .AsteriskEqual => Op{ .AssignTimes = {} }, | |
| 1984 | .AsteriskEqual => Op{ .AssignMul = {} }, | |
| 1985 | 1985 | .SlashEqual => Op{ .AssignDiv = {} }, |
| 1986 | 1986 | .PercentEqual => Op{ .AssignMod = {} }, |
| 1987 | .PlusEqual => Op{ .AssignPlus = {} }, | |
| 1988 | .MinusEqual => Op{ .AssignMinus = {} }, | |
| 1987 | .PlusEqual => Op{ .AssignAdd = {} }, | |
| 1988 | .MinusEqual => Op{ .AssignSub = {} }, | |
| 1989 | 1989 | .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, |
| 1990 | 1990 | .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, |
| 1991 | 1991 | .AmpersandEqual => Op{ .AssignBitAnd = {} }, |
| 1992 | 1992 | .CaretEqual => Op{ .AssignBitXor = {} }, |
| 1993 | 1993 | .PipeEqual => Op{ .AssignBitOr = {} }, |
| 1994 | .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} }, | |
| 1995 | .PlusPercentEqual => Op{ .AssignPlusWrap = {} }, | |
| 1996 | .MinusPercentEqual => Op{ .AssignMinusWrap = {} }, | |
| 1994 | .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, | |
| 1995 | .PlusPercentEqual => Op{ .AssignAddWrap = {} }, | |
| 1996 | .MinusPercentEqual => Op{ .AssignSubWrap = {} }, | |
| 1997 | 1997 | .Equal => Op{ .Assign = {} }, |
| 1998 | 1998 | else => { |
| 1999 | 1999 | putBackToken(it, token.index); |
| ... | ... | @@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2120 | 2120 | const token = nextToken(it); |
| 2121 | 2121 | const op = switch (token.ptr.id) { |
| 2122 | 2122 | .PipePipe => ops{ .BoolOr = {} }, |
| 2123 | .Asterisk => ops{ .Mult = {} }, | |
| 2123 | .Asterisk => ops{ .Mul = {} }, | |
| 2124 | 2124 | .Slash => ops{ .Div = {} }, |
| 2125 | 2125 | .Percent => ops{ .Mod = {} }, |
| 2126 | 2126 | .AsteriskAsterisk => ops{ .ArrayMult = {} }, |
| 2127 | .AsteriskPercent => ops{ .MultWrap = {} }, | |
| 2127 | .AsteriskPercent => ops{ .MulWrap = {} }, | |
| 2128 | 2128 | else => { |
| 2129 | 2129 | putBackToken(it, token.index); |
| 2130 | 2130 | return null; |
lib/std/zig/render.zig+1-1| ... | ... | @@ -1635,7 +1635,7 @@ fn renderExpression( |
| 1635 | 1635 | .If => { |
| 1636 | 1636 | const if_node = @fieldParentPtr(ast.Node.If, "base", base); |
| 1637 | 1637 | |
| 1638 | const lparen = tree.prevToken(if_node.condition.firstToken()); | |
| 1638 | const lparen = tree.nextToken(if_node.if_token); | |
| 1639 | 1639 | const rparen = tree.nextToken(if_node.condition.lastToken()); |
| 1640 | 1640 | |
| 1641 | 1641 | 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 | 27 | Lt, |
| 28 | 28 | Comma, |
| 29 | 29 | Fn, |
| 30 | Arrow, | |
| 31 | LBrace, | |
| 32 | RBrace, | |
| 33 | Pipe, | |
| 30 | 34 | }; |
| 31 | 35 | |
| 32 | 36 | pub const NumLitSuffix = enum { |
| ... | ... | @@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken { |
| 71 | 75 | } |
| 72 | 76 | } else return tok; |
| 73 | 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 | 84 | var i: usize = 0; |
| 85 | var count: u8 = 0; | |
| 86 | var num: u8 = 0; | |
| 76 | 87 | for (tok.bytes) |c| { |
| 77 | if (escape) { | |
| 78 | switch (c) { | |
| 79 | 'n', 'r', 't', '\\', '\'', '\"', 'x' => { | |
| 80 | bytes[i] = c; | |
| 81 | }, | |
| 82 | 'a' => { | |
| 83 | bytes[i] = 'x'; | |
| 84 | i += 1; | |
| 85 | bytes[i] = '0'; | |
| 86 | i += 1; | |
| 87 | bytes[i] = '7'; | |
| 88 | }, | |
| 89 | 'b' => { | |
| 90 | bytes[i] = 'x'; | |
| 91 | i += 1; | |
| 92 | bytes[i] = '0'; | |
| 93 | i += 1; | |
| 94 | bytes[i] = '8'; | |
| 95 | }, | |
| 96 | 'f' => { | |
| 97 | bytes[i] = 'x'; | |
| 98 | i += 1; | |
| 99 | bytes[i] = '0'; | |
| 100 | i += 1; | |
| 101 | bytes[i] = 'C'; | |
| 102 | }, | |
| 103 | 'v' => { | |
| 104 | bytes[i] = 'x'; | |
| 105 | i += 1; | |
| 106 | bytes[i] = '0'; | |
| 107 | i += 1; | |
| 108 | bytes[i] = 'B'; | |
| 109 | }, | |
| 110 | '?' => { | |
| 111 | i -= 1; | |
| 112 | bytes[i] = '?'; | |
| 113 | }, | |
| 114 | 'u', 'U' => { | |
| 115 | // TODO unicode escape sequences | |
| 116 | return error.TokenizingFailed; | |
| 117 | }, | |
| 118 | '0'...'7' => { | |
| 119 | // TODO octal escape sequences | |
| 120 | return error.TokenizingFailed; | |
| 121 | }, | |
| 122 | else => { | |
| 123 | // unknown escape sequence | |
| 124 | return error.TokenizingFailed; | |
| 125 | }, | |
| 126 | } | |
| 127 | i += 1; | |
| 128 | escape = false; | |
| 129 | } else { | |
| 130 | if (c == '\\') { | |
| 131 | escape = true; | |
| 132 | } | |
| 133 | bytes[i] = c; | |
| 134 | i += 1; | |
| 88 | switch (state) { | |
| 89 | .Escape => { | |
| 90 | switch (c) { | |
| 91 | 'n', 'r', 't', '\\', '\'', '\"' => { | |
| 92 | bytes[i] = c; | |
| 93 | }, | |
| 94 | '0'...'7' => { | |
| 95 | count += 1; | |
| 96 | num += c - '0'; | |
| 97 | state = .Octal; | |
| 98 | bytes[i] = 'x'; | |
| 99 | }, | |
| 100 | 'x' => { | |
| 101 | state = .Hex; | |
| 102 | bytes[i] = 'x'; | |
| 103 | }, | |
| 104 | 'a' => { | |
| 105 | bytes[i] = 'x'; | |
| 106 | i += 1; | |
| 107 | bytes[i] = '0'; | |
| 108 | i += 1; | |
| 109 | bytes[i] = '7'; | |
| 110 | }, | |
| 111 | 'b' => { | |
| 112 | bytes[i] = 'x'; | |
| 113 | i += 1; | |
| 114 | bytes[i] = '0'; | |
| 115 | i += 1; | |
| 116 | bytes[i] = '8'; | |
| 117 | }, | |
| 118 | 'f' => { | |
| 119 | bytes[i] = 'x'; | |
| 120 | i += 1; | |
| 121 | bytes[i] = '0'; | |
| 122 | i += 1; | |
| 123 | bytes[i] = 'C'; | |
| 124 | }, | |
| 125 | 'v' => { | |
| 126 | bytes[i] = 'x'; | |
| 127 | i += 1; | |
| 128 | bytes[i] = '0'; | |
| 129 | i += 1; | |
| 130 | bytes[i] = 'B'; | |
| 131 | }, | |
| 132 | '?' => { | |
| 133 | i -= 1; | |
| 134 | bytes[i] = '?'; | |
| 135 | }, | |
| 136 | 'u', 'U' => { | |
| 137 | // TODO unicode escape sequences | |
| 138 | return error.TokenizingFailed; | |
| 139 | }, | |
| 140 | else => { | |
| 141 | // unknown escape sequence | |
| 142 | return error.TokenizingFailed; | |
| 143 | }, | |
| 144 | } | |
| 145 | i += 1; | |
| 146 | if (state == .Escape) | |
| 147 | state = .Start; | |
| 148 | }, | |
| 149 | .Start => { | |
| 150 | if (c == '\\') { | |
| 151 | state = .Escape; | |
| 152 | } | |
| 153 | bytes[i] = c; | |
| 154 | i += 1; | |
| 155 | }, | |
| 156 | .Hex => { | |
| 157 | switch (c) { | |
| 158 | '0'...'9' => { | |
| 159 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | |
| 160 | num += c - '0'; | |
| 161 | }, | |
| 162 | 'a'...'f' => { | |
| 163 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | |
| 164 | num += c - 'a' + 10; | |
| 165 | }, | |
| 166 | 'A'...'F' => { | |
| 167 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | |
| 168 | num += c - 'A' + 10; | |
| 169 | }, | |
| 170 | else => { | |
| 171 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2}); | |
| 172 | num = 0; | |
| 173 | if (c == '\\') | |
| 174 | state = .Escape | |
| 175 | else | |
| 176 | state = .Start; | |
| 177 | bytes[i] = c; | |
| 178 | i += 1; | |
| 179 | }, | |
| 180 | } | |
| 181 | }, | |
| 182 | .Octal => { | |
| 183 | switch (c) { | |
| 184 | '0'...'7' => { | |
| 185 | count += 1; | |
| 186 | num = std.math.mul(u8, num, 8) catch return error.TokenizingFailed; | |
| 187 | num += c - '0'; | |
| 188 | if (count < 3) | |
| 189 | continue; | |
| 190 | }, | |
| 191 | else => {}, | |
| 192 | } | |
| 193 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2}); | |
| 194 | state = .Start; | |
| 195 | count = 0; | |
| 196 | num = 0; | |
| 197 | }, | |
| 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 | 202 | return CToken{ |
| 138 | 203 | .id = tok.id, |
| 139 | 204 | .bytes = bytes[0..i], |
| ... | ... | @@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 164 | 229 | NumLitIntSuffixL, |
| 165 | 230 | NumLitIntSuffixLL, |
| 166 | 231 | NumLitIntSuffixUL, |
| 232 | Minus, | |
| 233 | Done, | |
| 167 | 234 | } = .Start; |
| 168 | 235 | |
| 169 | 236 | var result = CToken{ |
| ... | ... | @@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 178 | 245 | const c = chars[i.*]; |
| 179 | 246 | if (c == 0) { |
| 180 | 247 | switch (state) { |
| 181 | .Start => { | |
| 182 | return result; | |
| 183 | }, | |
| 184 | 248 | .Identifier, |
| 185 | 249 | .Decimal, |
| 186 | 250 | .Hex, |
| ... | ... | @@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 193 | 257 | result.bytes = chars[begin_index..i.*]; |
| 194 | 258 | return result; |
| 195 | 259 | }, |
| 260 | .Start, | |
| 261 | .Minus, | |
| 262 | .Done, | |
| 196 | 263 | .NumLitIntSuffixU, |
| 197 | 264 | .NumLitIntSuffixL, |
| 198 | 265 | .NumLitIntSuffixUL, |
| ... | ... | @@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 212 | 279 | => return error.TokenizingFailed, |
| 213 | 280 | } |
| 214 | 281 | } |
| 215 | i.* += 1; | |
| 216 | 282 | switch (state) { |
| 217 | 283 | .Start => { |
| 218 | 284 | switch (c) { |
| ... | ... | @@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 220 | 286 | '\'' => { |
| 221 | 287 | state = .CharLit; |
| 222 | 288 | result.id = .CharLit; |
| 223 | begin_index = i.* - 1; | |
| 289 | begin_index = i.*; | |
| 224 | 290 | }, |
| 225 | 291 | '\"' => { |
| 226 | 292 | state = .String; |
| 227 | 293 | result.id = .StrLit; |
| 228 | begin_index = i.* - 1; | |
| 294 | begin_index = i.*; | |
| 229 | 295 | }, |
| 230 | 296 | '/' => { |
| 231 | 297 | state = .OpenComment; |
| ... | ... | @@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 239 | 305 | 'a'...'z', 'A'...'Z', '_' => { |
| 240 | 306 | state = .Identifier; |
| 241 | 307 | result.id = .Identifier; |
| 242 | begin_index = i.* - 1; | |
| 308 | begin_index = i.*; | |
| 243 | 309 | }, |
| 244 | 310 | '1'...'9' => { |
| 245 | 311 | state = .Decimal; |
| 246 | 312 | result.id = .NumLitInt; |
| 247 | begin_index = i.* - 1; | |
| 313 | begin_index = i.*; | |
| 248 | 314 | }, |
| 249 | 315 | '0' => { |
| 250 | 316 | state = .GotZero; |
| 251 | 317 | result.id = .NumLitInt; |
| 252 | begin_index = i.* - 1; | |
| 318 | begin_index = i.*; | |
| 253 | 319 | }, |
| 254 | 320 | '.' => { |
| 255 | 321 | result.id = .Dot; |
| 256 | return result; | |
| 322 | state = .Done; | |
| 257 | 323 | }, |
| 258 | 324 | '<' => { |
| 259 | 325 | result.id = .Lt; |
| ... | ... | @@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 261 | 327 | }, |
| 262 | 328 | '(' => { |
| 263 | 329 | result.id = .LParen; |
| 264 | return result; | |
| 330 | state = .Done; | |
| 265 | 331 | }, |
| 266 | 332 | ')' => { |
| 267 | 333 | result.id = .RParen; |
| 268 | return result; | |
| 334 | state = .Done; | |
| 269 | 335 | }, |
| 270 | 336 | '*' => { |
| 271 | 337 | result.id = .Asterisk; |
| 272 | return result; | |
| 338 | state = .Done; | |
| 273 | 339 | }, |
| 274 | 340 | '-' => { |
| 341 | state = .Minus; | |
| 275 | 342 | result.id = .Minus; |
| 276 | return result; | |
| 277 | 343 | }, |
| 278 | 344 | '!' => { |
| 279 | 345 | result.id = .Bang; |
| 280 | return result; | |
| 346 | state = .Done; | |
| 281 | 347 | }, |
| 282 | 348 | '~' => { |
| 283 | 349 | result.id = .Tilde; |
| 284 | return result; | |
| 350 | state = .Done; | |
| 285 | 351 | }, |
| 286 | 352 | ',' => { |
| 287 | 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 | 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 | 383 | .GotLt => { |
| 294 | 384 | switch (c) { |
| 295 | 385 | '<' => { |
| 296 | 386 | result.id = .Shl; |
| 297 | return result; | |
| 387 | state = .Done; | |
| 298 | 388 | }, |
| 299 | 389 | else => { |
| 300 | 390 | return result; |
| ... | ... | @@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 310 | 400 | 'f', |
| 311 | 401 | 'F', |
| 312 | 402 | => { |
| 313 | i.* -= 1; | |
| 314 | 403 | result.num_lit_suffix = .F; |
| 315 | 404 | result.bytes = chars[begin_index..i.*]; |
| 316 | return result; | |
| 405 | state = .Done; | |
| 317 | 406 | }, |
| 318 | 407 | 'l', 'L' => { |
| 319 | i.* -= 1; | |
| 320 | 408 | result.num_lit_suffix = .L; |
| 321 | 409 | result.bytes = chars[begin_index..i.*]; |
| 322 | return result; | |
| 410 | state = .Done; | |
| 323 | 411 | }, |
| 324 | 412 | else => { |
| 325 | i.* -= 1; | |
| 326 | 413 | result.bytes = chars[begin_index..i.*]; |
| 327 | 414 | return result; |
| 328 | 415 | }, |
| ... | ... | @@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 352 | 439 | '0'...'9' => {}, |
| 353 | 440 | 'f', 'F' => { |
| 354 | 441 | result.num_lit_suffix = .F; |
| 355 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 356 | return result; | |
| 442 | result.bytes = chars[begin_index..i.*]; | |
| 443 | state = .Done; | |
| 357 | 444 | }, |
| 358 | 445 | 'l', 'L' => { |
| 359 | 446 | result.num_lit_suffix = .L; |
| 360 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 361 | return result; | |
| 447 | result.bytes = chars[begin_index..i.*]; | |
| 448 | state = .Done; | |
| 362 | 449 | }, |
| 363 | 450 | else => { |
| 364 | i.* -= 1; | |
| 365 | 451 | result.bytes = chars[begin_index..i.*]; |
| 366 | 452 | return result; |
| 367 | 453 | }, |
| ... | ... | @@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 374 | 460 | 'u', 'U' => { |
| 375 | 461 | state = .NumLitIntSuffixU; |
| 376 | 462 | result.num_lit_suffix = .U; |
| 377 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 463 | result.bytes = chars[begin_index..i.*]; | |
| 378 | 464 | }, |
| 379 | 465 | 'l', 'L' => { |
| 380 | 466 | state = .NumLitIntSuffixL; |
| 381 | 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 | 471 | result.id = .NumLitFloat; |
| 386 | 472 | state = .Float; |
| 387 | 473 | }, |
| 388 | 474 | else => { |
| 389 | i.* -= 1; | |
| 390 | 475 | result.bytes = chars[begin_index..i.*]; |
| 391 | 476 | return result; |
| 392 | 477 | }, |
| ... | ... | @@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 407 | 492 | 'u', 'U' => { |
| 408 | 493 | state = .NumLitIntSuffixU; |
| 409 | 494 | result.num_lit_suffix = .U; |
| 410 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 495 | result.bytes = chars[begin_index..i.*]; | |
| 411 | 496 | }, |
| 412 | 497 | 'l', 'L' => { |
| 413 | 498 | state = .NumLitIntSuffixL; |
| 414 | 499 | result.num_lit_suffix = .L; |
| 415 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 500 | result.bytes = chars[begin_index..i.*]; | |
| 416 | 501 | }, |
| 417 | 502 | else => { |
| 418 | 503 | i.* -= 1; |
| ... | ... | @@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 425 | 510 | '0'...'7' => {}, |
| 426 | 511 | '8', '9' => return error.TokenizingFailed, |
| 427 | 512 | else => { |
| 428 | i.* -= 1; | |
| 429 | 513 | result.bytes = chars[begin_index..i.*]; |
| 430 | 514 | return result; |
| 431 | 515 | }, |
| ... | ... | @@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 438 | 522 | // marks the number literal as unsigned |
| 439 | 523 | state = .NumLitIntSuffixU; |
| 440 | 524 | result.num_lit_suffix = .U; |
| 441 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 525 | result.bytes = chars[begin_index..i.*]; | |
| 442 | 526 | }, |
| 443 | 527 | 'l', 'L' => { |
| 444 | 528 | // marks the number literal as long |
| 445 | 529 | state = .NumLitIntSuffixL; |
| 446 | 530 | result.num_lit_suffix = .L; |
| 447 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 531 | result.bytes = chars[begin_index..i.*]; | |
| 448 | 532 | }, |
| 449 | 533 | else => { |
| 450 | i.* -= 1; | |
| 451 | 534 | result.bytes = chars[begin_index..i.*]; |
| 452 | 535 | return result; |
| 453 | 536 | }, |
| ... | ... | @@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 461 | 544 | // marks the number literal as unsigned |
| 462 | 545 | state = .NumLitIntSuffixU; |
| 463 | 546 | result.num_lit_suffix = .U; |
| 464 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 547 | result.bytes = chars[begin_index..i.*]; | |
| 465 | 548 | }, |
| 466 | 549 | 'l', 'L' => { |
| 467 | 550 | // marks the number literal as long |
| 468 | 551 | state = .NumLitIntSuffixL; |
| 469 | 552 | result.num_lit_suffix = .L; |
| 470 | result.bytes = chars[begin_index .. i.* - 1]; | |
| 553 | result.bytes = chars[begin_index..i.*]; | |
| 471 | 554 | }, |
| 472 | 555 | else => { |
| 473 | i.* -= 1; | |
| 474 | 556 | result.bytes = chars[begin_index..i.*]; |
| 475 | 557 | return result; |
| 476 | 558 | }, |
| ... | ... | @@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 483 | 565 | state = .NumLitIntSuffixUL; |
| 484 | 566 | }, |
| 485 | 567 | else => { |
| 486 | i.* -= 1; | |
| 487 | 568 | return result; |
| 488 | 569 | }, |
| 489 | 570 | } |
| ... | ... | @@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 496 | 577 | }, |
| 497 | 578 | 'u', 'U' => { |
| 498 | 579 | result.num_lit_suffix = .LU; |
| 499 | return result; | |
| 580 | state = .Done; | |
| 500 | 581 | }, |
| 501 | 582 | else => { |
| 502 | i.* -= 1; | |
| 503 | 583 | return result; |
| 504 | 584 | }, |
| 505 | 585 | } |
| ... | ... | @@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 508 | 588 | switch (c) { |
| 509 | 589 | 'u', 'U' => { |
| 510 | 590 | result.num_lit_suffix = .LLU; |
| 511 | return result; | |
| 591 | state = .Done; | |
| 512 | 592 | }, |
| 513 | 593 | else => { |
| 514 | i.* -= 1; | |
| 515 | 594 | return result; |
| 516 | 595 | }, |
| 517 | 596 | } |
| ... | ... | @@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 520 | 599 | switch (c) { |
| 521 | 600 | 'l', 'L' => { |
| 522 | 601 | result.num_lit_suffix = .LLU; |
| 523 | return result; | |
| 602 | state = .Done; | |
| 524 | 603 | }, |
| 525 | 604 | else => { |
| 526 | i.* -= 1; | |
| 527 | 605 | return result; |
| 528 | 606 | }, |
| 529 | 607 | } |
| ... | ... | @@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 532 | 610 | switch (c) { |
| 533 | 611 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, |
| 534 | 612 | else => { |
| 535 | i.* -= 1; | |
| 536 | 613 | result.bytes = chars[begin_index..i.*]; |
| 537 | 614 | return result; |
| 538 | 615 | }, |
| 539 | 616 | } |
| 540 | 617 | }, |
| 541 | .String => { // TODO char escapes | |
| 618 | .String => { | |
| 542 | 619 | switch (c) { |
| 543 | 620 | '\"' => { |
| 544 | result.bytes = chars[begin_index..i.*]; | |
| 545 | return result; | |
| 621 | result.bytes = chars[begin_index .. i.* + 1]; | |
| 622 | state = .Done; | |
| 546 | 623 | }, |
| 547 | 624 | else => {}, |
| 548 | 625 | } |
| ... | ... | @@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 550 | 627 | .CharLit => { |
| 551 | 628 | switch (c) { |
| 552 | 629 | '\'' => { |
| 553 | result.bytes = chars[begin_index..i.*]; | |
| 554 | return result; | |
| 630 | result.bytes = chars[begin_index .. i.* + 1]; | |
| 631 | state = .Done; | |
| 555 | 632 | }, |
| 556 | 633 | else => {}, |
| 557 | 634 | } |
| ... | ... | @@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 566 | 643 | }, |
| 567 | 644 | else => { |
| 568 | 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 | 675 | } |
| 599 | 676 | }, |
| 600 | 677 | } |
| 678 | i.* += 1; | |
| 601 | 679 | } |
| 602 | 680 | unreachable; |
| 603 | 681 | } |
| ... | ... | @@ -645,7 +723,7 @@ test "tokenize macro" { |
| 645 | 723 | expect(it.next() == null); |
| 646 | 724 | tl.shrink(0); |
| 647 | 725 | |
| 648 | const src5 = "FOO 0l"; | |
| 726 | const src5 = "FOO 0ull"; | |
| 649 | 727 | try tokenizeCMacro(&tl, src5); |
| 650 | 728 | it = tl.iterator(0); |
| 651 | 729 | expect(it.next().?.id == .Identifier); |
| ... | ... | @@ -654,3 +732,25 @@ test "tokenize macro" { |
| 654 | 732 | expect(it.next() == null); |
| 655 | 733 | tl.shrink(0); |
| 656 | 734 | } |
| 735 | ||
| 736 | test "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 | 76 | pub const struct_ZigClangPredefinedExpr = @OpaqueType(); |
| 77 | 77 | pub const struct_ZigClangInitListExpr = @OpaqueType(); |
| 78 | 78 | pub const ZigClangPreprocessingRecord = @OpaqueType(); |
| 79 | pub const ZigClangFloatingLiteral = @OpaqueType(); | |
| 80 | pub const ZigClangConstantExpr = @OpaqueType(); | |
| 81 | pub const ZigClangCharacterLiteral = @OpaqueType(); | |
| 82 | pub const ZigClangStmtExpr = @OpaqueType(); | |
| 79 | 83 | |
| 80 | 84 | pub const ZigClangBO = extern enum { |
| 81 | 85 | PtrMemD, |
| ... | ... | @@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum { |
| 710 | 714 | UTF32, |
| 711 | 715 | }; |
| 712 | 716 | |
| 717 | pub const ZigClangCharacterLiteral_CharacterKind = extern enum { | |
| 718 | Ascii, | |
| 719 | Wide, | |
| 720 | UTF8, | |
| 721 | UTF16, | |
| 722 | UTF32, | |
| 723 | }; | |
| 724 | ||
| 713 | 725 | pub const ZigClangRecordDecl_field_iterator = extern struct { |
| 714 | 726 | opaque: *c_void, |
| 715 | 727 | }; |
| ... | ... | @@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum { |
| 730 | 742 | InclusionDirectiveKind, |
| 731 | 743 | }; |
| 732 | 744 | |
| 745 | pub const ZigClangExpr_ConstExprUsage = extern enum { | |
| 746 | EvaluateForCodeGen, | |
| 747 | EvaluateForMangling, | |
| 748 | }; | |
| 749 | ||
| 733 | 750 | pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; |
| 734 | 751 | pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; |
| 735 | 752 | pub 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 | 761 | pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; |
| 745 | 762 | pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; |
| 746 | 763 | pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; |
| 764 | pub extern fn ZigClangFunctionDecl_getCanonicalDecl(self: ?*const struct_ZigClangFunctionDecl) ?*const struct_ZigClangFunctionDecl; | |
| 765 | pub extern fn ZigClangVarDecl_getCanonicalDecl(self: ?*const struct_ZigClangVarDecl) ?*const struct_ZigClangVarDecl; | |
| 747 | 766 | pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl; |
| 748 | 767 | pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl; |
| 749 | 768 | pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation; |
| ... | ... | @@ -791,16 +810,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList |
| 791 | 810 | pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr; |
| 792 | 811 | pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint; |
| 793 | 812 | pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind; |
| 794 | pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) ?*const struct_ZigClangAPSInt; | |
| 813 | pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) *const struct_ZigClangAPSInt; | |
| 795 | 814 | pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint; |
| 796 | 815 | pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint; |
| 797 | 816 | pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase; |
| 798 | pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool; | |
| 799 | pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool; | |
| 800 | pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt; | |
| 801 | pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void; | |
| 802 | pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64; | |
| 803 | pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint; | |
| 817 | pub extern fn ZigClangAPSInt_isSigned(self: *const struct_ZigClangAPSInt) bool; | |
| 818 | pub extern fn ZigClangAPSInt_isNegative(self: *const struct_ZigClangAPSInt) bool; | |
| 819 | pub extern fn ZigClangAPSInt_negate(self: *const struct_ZigClangAPSInt) *const struct_ZigClangAPSInt; | |
| 820 | pub extern fn ZigClangAPSInt_free(self: *const struct_ZigClangAPSInt) void; | |
| 821 | pub extern fn ZigClangAPSInt_getRawData(self: *const struct_ZigClangAPSInt) [*:0]const u64; | |
| 822 | pub extern fn ZigClangAPSInt_getNumWords(self: *const struct_ZigClangAPSInt) c_uint; | |
| 804 | 823 | |
| 805 | 824 | pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64; |
| 806 | 825 | pub 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 | 841 | pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool; |
| 823 | 842 | pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint; |
| 824 | 843 | pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType; |
| 844 | pub extern fn ZigClangFunctionProtoType_getReturnType(self: *const ZigClangFunctionProtoType) ZigClangQualType; | |
| 825 | 845 | |
| 826 | 846 | pub const ZigClangSourceLocation = struct_ZigClangSourceLocation; |
| 827 | 847 | pub const ZigClangQualType = struct_ZigClangQualType; |
| ... | ... | @@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple |
| 976 | 996 | pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType; |
| 977 | 997 | pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt; |
| 978 | 998 | pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl; |
| 999 | pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl; | |
| 979 | 1000 | |
| 980 | 1001 | pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; |
| 981 | 1002 | |
| ... | ... | @@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti |
| 1036 | 1057 | pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8; |
| 1037 | 1058 | pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; |
| 1038 | 1059 | pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; |
| 1060 | ||
| 1061 | pub extern fn ZigClangIfStmt_getThen(*const ZigClangIfStmt) *const ZigClangStmt; | |
| 1062 | pub extern fn ZigClangIfStmt_getElse(*const ZigClangIfStmt) ?*const ZigClangStmt; | |
| 1063 | pub extern fn ZigClangIfStmt_getCond(*const ZigClangIfStmt) *const ZigClangStmt; | |
| 1064 | ||
| 1065 | pub extern fn ZigClangWhileStmt_getCond(*const ZigClangWhileStmt) *const ZigClangExpr; | |
| 1066 | pub extern fn ZigClangWhileStmt_getBody(*const ZigClangWhileStmt) *const ZigClangStmt; | |
| 1067 | ||
| 1068 | pub extern fn ZigClangDoStmt_getCond(*const ZigClangDoStmt) *const ZigClangExpr; | |
| 1069 | pub extern fn ZigClangDoStmt_getBody(*const ZigClangDoStmt) *const ZigClangStmt; | |
| 1070 | ||
| 1071 | pub extern fn ZigClangForStmt_getInit(*const ZigClangForStmt) ?*const ZigClangStmt; | |
| 1072 | pub extern fn ZigClangForStmt_getCond(*const ZigClangForStmt) ?*const ZigClangExpr; | |
| 1073 | pub extern fn ZigClangForStmt_getInc(*const ZigClangForStmt) ?*const ZigClangExpr; | |
| 1074 | pub extern fn ZigClangForStmt_getBody(*const ZigClangForStmt) *const ZigClangStmt; | |
| 1075 | ||
| 1076 | pub extern fn ZigClangAPFloat_toString(self: *const ZigClangAPFloat, precision: c_uint, maxPadding: c_uint, truncateZero: bool) [*:0]const u8; | |
| 1077 | pub extern fn ZigClangAPFloat_getValueAsApproximateDouble(*const ZigClangFloatingLiteral) f64; | |
| 1078 | ||
| 1079 | pub extern fn ZigClangConditionalOperator_getCond(*const ZigClangConditionalOperator) *const ZigClangExpr; | |
| 1080 | pub extern fn ZigClangConditionalOperator_getTrueExpr(*const ZigClangConditionalOperator) *const ZigClangExpr; | |
| 1081 | pub extern fn ZigClangConditionalOperator_getFalseExpr(*const ZigClangConditionalOperator) *const ZigClangExpr; | |
| 1082 | ||
| 1083 | pub extern fn ZigClangSwitchStmt_getConditionVariableDeclStmt(*const ZigClangSwitchStmt) ?*const ZigClangDeclStmt; | |
| 1084 | pub extern fn ZigClangSwitchStmt_getCond(*const ZigClangSwitchStmt) *const ZigClangExpr; | |
| 1085 | pub extern fn ZigClangSwitchStmt_getBody(*const ZigClangSwitchStmt) *const ZigClangStmt; | |
| 1086 | pub extern fn ZigClangSwitchStmt_isAllEnumCasesCovered(*const ZigClangSwitchStmt) bool; | |
| 1087 | ||
| 1088 | pub extern fn ZigClangCaseStmt_getLHS(*const ZigClangCaseStmt) *const ZigClangExpr; | |
| 1089 | pub extern fn ZigClangCaseStmt_getRHS(*const ZigClangCaseStmt) ?*const ZigClangExpr; | |
| 1090 | pub extern fn ZigClangCaseStmt_getBeginLoc(*const ZigClangCaseStmt) ZigClangSourceLocation; | |
| 1091 | pub extern fn ZigClangCaseStmt_getSubStmt(*const ZigClangCaseStmt) *const ZigClangStmt; | |
| 1092 | ||
| 1093 | pub extern fn ZigClangDefaultStmt_getSubStmt(*const ZigClangDefaultStmt) *const ZigClangStmt; | |
| 1094 | ||
| 1095 | pub extern fn ZigClangExpr_EvaluateAsConstantExpr(*const ZigClangExpr, *ZigClangExprEvalResult, ZigClangExpr_ConstExprUsage, *const ZigClangASTContext) bool; | |
| 1096 | ||
| 1097 | pub extern fn ZigClangPredefinedExpr_getFunctionName(*const ZigClangPredefinedExpr) *const ZigClangStringLiteral; | |
| 1098 | ||
| 1099 | pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiteral) ZigClangSourceLocation; | |
| 1100 | pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; | |
| 1101 | pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; | |
| 1102 | ||
| 1103 | pub extern fn ZigClangStmtExpr_getSubStmt(*const ZigClangStmtExpr) *const ZigClangCompoundStmt; | |
| 1104 | ||
| 1105 | pub extern fn ZigClangMemberExpr_getBase(*const ZigClangMemberExpr) *const ZigClangExpr; | |
| 1106 | pub extern fn ZigClangMemberExpr_isArrow(*const ZigClangMemberExpr) bool; | |
| 1107 | pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const ZigClangValueDecl; | |
| 1108 | ||
| 1109 | pub extern fn ZigClangArraySubscriptExpr_getBase(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; | |
| 1110 | pub extern fn ZigClangArraySubscriptExpr_getIdx(*const ZigClangArraySubscriptExpr) *const ZigClangExpr; | |
| 1111 | ||
| 1112 | pub extern fn ZigClangCallExpr_getCallee(*const ZigClangCallExpr) *const ZigClangExpr; | |
| 1113 | pub extern fn ZigClangCallExpr_getNumArgs(*const ZigClangCallExpr) c_uint; | |
| 1114 | pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const ZigClangExpr; | |
| 1115 | ||
| 1116 | pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangQualType; | |
| 1117 | pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangSourceLocation; | |
| 1118 | ||
| 1119 | pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigClangUO; | |
| 1120 | pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType; | |
| 1121 | pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr; | |
| 1122 | pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation; | |
| 1123 | ||
| 1124 | pub extern fn ZigClangCompoundAssignOperator_getType(*const ZigClangCompoundAssignOperator) ZigClangQualType; | |
| 1125 | pub extern fn ZigClangCompoundAssignOperator_getComputationLHSType(*const ZigClangCompoundAssignOperator) ZigClangQualType; | |
| 1126 | pub extern fn ZigClangCompoundAssignOperator_getComputationResultType(*const ZigClangCompoundAssignOperator) ZigClangQualType; | |
| 1127 | pub extern fn ZigClangCompoundAssignOperator_getBeginLoc(*const ZigClangCompoundAssignOperator) ZigClangSourceLocation; | |
| 1128 | pub extern fn ZigClangCompoundAssignOperator_getOpcode(*const ZigClangCompoundAssignOperator) ZigClangBO; | |
| 1129 | pub extern fn ZigClangCompoundAssignOperator_getLHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr; | |
| 1130 | pub 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 | 8 | usingnamespace @import("clang.zig"); |
| 9 | 9 | const ctok = @import("c_tokenizer.zig"); |
| 10 | 10 | const CToken = ctok.CToken; |
| 11 | const mem = std.mem; | |
| 11 | 12 | |
| 12 | 13 | const CallingConvention = std.builtin.TypeInfo.CallingConvention; |
| 13 | 14 | |
| ... | ... | @@ -47,35 +48,34 @@ const Scope = struct { |
| 47 | 48 | Switch, |
| 48 | 49 | Block, |
| 49 | 50 | Root, |
| 50 | While, | |
| 51 | FnDef, | |
| 52 | Ref, | |
| 51 | Condition, | |
| 52 | Loop, | |
| 53 | 53 | }; |
| 54 | 54 | |
| 55 | 55 | const Switch = struct { |
| 56 | 56 | base: Scope, |
| 57 | }; | |
| 58 | ||
| 59 | /// used when getting a member `a.b` | |
| 60 | const Ref = struct { | |
| 61 | base: Scope, | |
| 57 | pending_block: *ast.Node.Block, | |
| 58 | cases: *ast.Node.Switch.CaseList, | |
| 59 | has_default: bool = false, | |
| 62 | 60 | }; |
| 63 | 61 | |
| 64 | 62 | const Block = struct { |
| 65 | 63 | base: Scope, |
| 66 | 64 | block_node: *ast.Node.Block, |
| 67 | 65 | variables: AliasList, |
| 66 | label: ?[]const u8, | |
| 68 | 67 | |
| 69 | /// Don't forget to set rbrace token later | |
| 70 | fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block { | |
| 68 | /// Don't forget to set rbrace token and block_node later | |
| 69 | fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block { | |
| 71 | 70 | const block = try c.a().create(Block); |
| 72 | 71 | block.* = .{ |
| 73 | 72 | .base = .{ |
| 74 | 73 | .id = .Block, |
| 75 | 74 | .parent = parent, |
| 76 | 75 | }, |
| 77 | .block_node = block_node, | |
| 76 | .block_node = undefined, | |
| 78 | 77 | .variables = AliasList.init(c.a()), |
| 78 | .label = label, | |
| 79 | 79 | }; |
| 80 | 80 | return block; |
| 81 | 81 | } |
| ... | ... | @@ -83,7 +83,7 @@ const Scope = struct { |
| 83 | 83 | fn getAlias(scope: *Block, name: []const u8) ?[]const u8 { |
| 84 | 84 | var it = scope.variables.iterator(0); |
| 85 | 85 | while (it.next()) |p| { |
| 86 | if (std.mem.eql(u8, p.name, name)) | |
| 86 | if (mem.eql(u8, p.name, name)) | |
| 87 | 87 | return p.alias; |
| 88 | 88 | } |
| 89 | 89 | return scope.base.parent.?.getAlias(name); |
| ... | ... | @@ -92,7 +92,7 @@ const Scope = struct { |
| 92 | 92 | fn contains(scope: *Block, name: []const u8) bool { |
| 93 | 93 | var it = scope.variables.iterator(0); |
| 94 | 94 | while (it.next()) |p| { |
| 95 | if (std.mem.eql(u8, p.name, name)) | |
| 95 | if (mem.eql(u8, p.name, name)) | |
| 96 | 96 | return true; |
| 97 | 97 | } |
| 98 | 98 | return scope.base.parent.?.contains(name); |
| ... | ... | @@ -120,52 +120,23 @@ const Scope = struct { |
| 120 | 120 | } |
| 121 | 121 | }; |
| 122 | 122 | |
| 123 | const While = struct { | |
| 124 | base: Scope, | |
| 125 | }; | |
| 126 | ||
| 127 | const FnDef = struct { | |
| 128 | base: Scope, | |
| 129 | params: AliasList, | |
| 130 | ||
| 131 | fn init(c: *Context) FnDef { | |
| 132 | return .{ | |
| 133 | .base = .{ | |
| 134 | .id = .FnDef, | |
| 135 | .parent = &c.global_scope.base, | |
| 123 | fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block { | |
| 124 | var scope = inner; | |
| 125 | while (true) { | |
| 126 | switch (scope.id) { | |
| 127 | .Root => unreachable, | |
| 128 | .Block => return @fieldParentPtr(Block, "base", scope), | |
| 129 | .Condition => { | |
| 130 | // comma operator used | |
| 131 | return try Block.init(c, scope, "blk"); | |
| 136 | 132 | }, |
| 137 | .params = AliasList.init(c.a()), | |
| 138 | }; | |
| 139 | } | |
| 140 | ||
| 141 | fn getAlias(scope: *FnDef, name: []const u8) ?[]const u8 { | |
| 142 | var it = scope.params.iterator(0); | |
| 143 | while (it.next()) |p| { | |
| 144 | if (std.mem.eql(u8, p.name, name)) | |
| 145 | return p.alias; | |
| 133 | else => scope = scope.parent.?, | |
| 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 | } |
| 166 | 137 | |
| 167 | 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 | 140 | return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }); |
| 170 | 141 | } |
| 171 | 142 | return null; |
| ... | ... | @@ -174,22 +145,41 @@ const Scope = struct { |
| 174 | 145 | fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { |
| 175 | 146 | return switch (scope.id) { |
| 176 | 147 | .Root => null, |
| 177 | .Ref => null, | |
| 178 | .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), | |
| 179 | 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 | } |
| 183 | 152 | |
| 184 | 153 | fn contains(scope: *Scope, name: []const u8) bool { |
| 185 | 154 | return switch (scope.id) { |
| 186 | .Ref => false, | |
| 187 | 155 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), |
| 188 | .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), | |
| 189 | 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 | }; |
| 194 | 184 | |
| 195 | 185 | const Context = struct { |
| ... | ... | @@ -200,7 +190,6 @@ const Context = struct { |
| 200 | 190 | decl_table: DeclTable, |
| 201 | 191 | alias_list: AliasList, |
| 202 | 192 | global_scope: *Scope.Root, |
| 203 | ptr_params: std.BufSet, | |
| 204 | 193 | clang_context: *ZigClangASTContext, |
| 205 | 194 | mangle_count: u64 = 0, |
| 206 | 195 | |
| ... | ... | @@ -209,13 +198,13 @@ const Context = struct { |
| 209 | 198 | return c.mangle_count; |
| 210 | 199 | } |
| 211 | 200 | |
| 212 | fn a(c: *Context) *std.mem.Allocator { | |
| 201 | fn a(c: *Context) *mem.Allocator { | |
| 213 | 202 | return &c.tree.arena_allocator.allocator; |
| 214 | 203 | } |
| 215 | 204 | |
| 216 | 205 | /// Convert a null-terminated C string to a slice allocated in the arena |
| 217 | 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 | } |
| 220 | 209 | |
| 221 | 210 | /// Convert a clang source location to a file:line:column string |
| ... | ... | @@ -231,7 +220,7 @@ const Context = struct { |
| 231 | 220 | }; |
| 232 | 221 | |
| 233 | 222 | pub fn translate( |
| 234 | backing_allocator: *std.mem.Allocator, | |
| 223 | backing_allocator: *mem.Allocator, | |
| 235 | 224 | args_begin: [*]?[*]const u8, |
| 236 | 225 | args_end: [*]?[*]const u8, |
| 237 | 226 | errors: *[]ClangErrMsg, |
| ... | ... | @@ -286,7 +275,6 @@ pub fn translate( |
| 286 | 275 | .decl_table = DeclTable.init(arena), |
| 287 | 276 | .alias_list = AliasList.init(arena), |
| 288 | 277 | .global_scope = try arena.create(Scope.Root), |
| 289 | .ptr_params = std.BufSet.init(arena), | |
| 290 | 278 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, |
| 291 | 279 | }; |
| 292 | 280 | context.global_scope.* = Scope.Root.init(&context); |
| ... | ... | @@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 333 | 321 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); |
| 334 | 322 | }, |
| 335 | 323 | .Typedef => { |
| 336 | return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); | |
| 324 | _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); | |
| 337 | 325 | }, |
| 338 | 326 | .Enum => { |
| 339 | 327 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); |
| 340 | 328 | }, |
| 341 | 329 | .Record => { |
| 342 | return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); | |
| 330 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); | |
| 343 | 331 | }, |
| 344 | 332 | .Var => { |
| 345 | 333 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); |
| ... | ... | @@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 352 | 340 | } |
| 353 | 341 | |
| 354 | 342 | fn 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 | 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 | 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 | 348 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); |
| 365 | 349 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); |
| 366 | 350 | const decl_ctx = FnDeclContext{ |
| 367 | 351 | .fn_name = fn_name, |
| 368 | 352 | .has_body = has_body, |
| 369 | 353 | .storage_class = storage_class, |
| 370 | .scope = &scope, | |
| 371 | 354 | .is_export = switch (storage_class) { |
| 372 | 355 | .None => has_body, |
| 373 | 356 | .Extern, .Static => false, |
| ... | ... | @@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 377 | 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 | 372 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 381 | 373 | .FunctionProto => blk: { |
| 382 | 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 | 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 | }; |
| 401 | 393 | |
| 402 | 394 | if (!decl_ctx.has_body) { |
| ... | ... | @@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 406 | 398 | |
| 407 | 399 | // actual function definition with body |
| 408 | 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 | 428 | error.OutOfMemory => |e| return e, |
| 411 | 429 | error.UnsupportedTranslation, |
| 412 | 430 | error.UnsupportedType, |
| 413 | 431 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), |
| 414 | 432 | }; |
| 415 | assert(body_node.id == .Block); | |
| 416 | proto_node.body_node = body_node; | |
| 417 | ||
| 433 | block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 434 | proto_node.body_node = &block_node.base; | |
| 418 | 435 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 419 | 436 | } |
| 420 | 437 | |
| 421 | 438 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 422 | if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice | |
| 439 | const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); | |
| 440 | if (c.global_scope.sym_table.contains(var_name)) | |
| 441 | return; // Avoid processing this decl twice | |
| 423 | 442 | const rp = makeRestorePoint(c); |
| 424 | 443 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 425 | 444 | |
| ... | ... | @@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 429 | 448 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 430 | 449 | |
| 431 | 450 | const scope = &c.global_scope.base; |
| 432 | const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); | |
| 433 | _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); | |
| 451 | ||
| 452 | // TODO https://github.com/ziglang/zig/issues/3756 | |
| 453 | // TODO https://github.com/ziglang/zig/issues/1802 | |
| 454 | const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "_{}", .{var_name}) else var_name; | |
| 434 | 455 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); |
| 435 | 456 | |
| 436 | 457 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| ... | ... | @@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 449 | 470 | else |
| 450 | 471 | try appendToken(c, .Keyword_var, "var"); |
| 451 | 472 | |
| 452 | const name_tok = try appendIdentifier(c, var_name); | |
| 473 | const name_tok = try appendIdentifier(c, checked_name); | |
| 453 | 474 | |
| 454 | 475 | _ = try appendToken(c, .Colon, ":"); |
| 455 | 476 | const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { |
| 456 | 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 | 480 | error.OutOfMemory => |e| return e, |
| 460 | 481 | }; |
| ... | ... | @@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 469 | 490 | error.UnsupportedTranslation, |
| 470 | 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 | 495 | error.OutOfMemory => |e| return e, |
| 475 | 496 | } |
| 476 | 497 | else |
| 477 | 498 | try transCreateNodeUndefinedLiteral(c); |
| 478 | 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 | } |
| 481 | 502 | |
| 482 | 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 | 517 | .init_node = init_node, |
| 497 | 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 | } |
| 501 | 522 | |
| 502 | fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { | |
| 503 | if (c.decl_table.contains( | |
| 504 | @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), | |
| 505 | )) return; // Avoid processing this decl twice | |
| 523 | fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, builtin_name: []const u8) !*ast.Node { | |
| 524 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), builtin_name); | |
| 525 | return transCreateNodeIdentifier(c, builtin_name); | |
| 526 | } | |
| 527 | ||
| 528 | fn 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 | 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"); | |
| 509 | 532 | |
| 510 | 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 | 560 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); |
| 512 | const name_tok = try appendIdentifier(c, typedef_name); | |
| 513 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 561 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 562 | const const_tok = try appendToken(c, .Keyword_const, "const"); | |
| 563 | const node = try transCreateNodeVarDecl(c, true, true, typedef_name); | |
| 564 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 514 | 565 | |
| 515 | 566 | const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); |
| 516 | 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 | 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 | 573 | error.OutOfMemory => |e| return e, |
| 522 | 574 | }; |
| 523 | ||
| 524 | const node = try c.a().create(ast.Node.VarDecl); | |
| 525 | node.* = ast.Node.VarDecl{ | |
| 526 | .doc_comments = null, | |
| 527 | .visib_token = visib_tok, | |
| 528 | .thread_local_token = null, | |
| 529 | .name_token = name_tok, | |
| 530 | .eq_token = eq_tok, | |
| 531 | .mut_token = const_tok, | |
| 532 | .comptime_token = null, | |
| 533 | .extern_export_token = null, | |
| 534 | .lib_name = null, | |
| 535 | .type_node = null, | |
| 536 | .align_node = null, | |
| 537 | .section_node = null, | |
| 538 | .init_node = type_node, | |
| 539 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | |
| 540 | }; | |
| 575 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 541 | 576 | try addTopLevelDecl(c, typedef_name, &node.base); |
| 577 | return transCreateNodeIdentifier(c, typedef_name); | |
| 542 | 578 | } |
| 543 | 579 | |
| 544 | fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { | |
| 545 | if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice | |
| 546 | const rp = makeRestorePoint(c); | |
| 547 | ||
| 548 | const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); | |
| 549 | ||
| 550 | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) | |
| 551 | "union" | |
| 552 | else if (ZigClangRecordDecl_isStruct(record_decl)) | |
| 553 | "struct" | |
| 554 | else | |
| 555 | return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); | |
| 580 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { | |
| 581 | if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| | |
| 582 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice | |
| 583 | const record_loc = ZigClangRecordDecl_getLocation(record_decl); | |
| 556 | 584 | |
| 557 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) | |
| 558 | return; | |
| 585 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); | |
| 586 | var is_unnamed = false; | |
| 587 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) { | |
| 588 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | |
| 589 | is_unnamed = true; | |
| 590 | } | |
| 559 | 591 | |
| 560 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 561 | const const_tok = try appendToken(c, .Keyword_const, "const"); | |
| 592 | var container_kind_name: []const u8 = undefined; | |
| 593 | var container_kind: std.zig.Token.Id = undefined; | |
| 594 | if (ZigClangRecordDecl_isUnion(record_decl)) { | |
| 595 | container_kind_name = "union"; | |
| 596 | container_kind = .Keyword_union; | |
| 597 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { | |
| 598 | container_kind_name = "struct"; | |
| 599 | container_kind = .Keyword_struct; | |
| 600 | } else { | |
| 601 | try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name}); | |
| 602 | return null; | |
| 603 | } | |
| 562 | 604 | |
| 563 | 605 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 564 | 606 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| 565 | const name_tok = try appendIdentifier(c, name); | |
| 566 | 607 | |
| 567 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 568 | const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { | |
| 569 | error.UnsupportedType => { | |
| 570 | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); | |
| 571 | }, | |
| 572 | error.OutOfMemory => |e| return e, | |
| 573 | }; | |
| 574 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 608 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | |
| 575 | 609 | |
| 576 | const node = try c.a().create(ast.Node.VarDecl); | |
| 577 | node.* = ast.Node.VarDecl{ | |
| 578 | .doc_comments = null, | |
| 579 | .visib_token = visib_tok, | |
| 580 | .thread_local_token = null, | |
| 581 | .name_token = name_tok, | |
| 582 | .eq_token = eq_tok, | |
| 583 | .mut_token = const_tok, | |
| 584 | .comptime_token = null, | |
| 585 | .extern_export_token = null, | |
| 586 | .lib_name = null, | |
| 587 | .type_node = null, | |
| 588 | .align_node = null, | |
| 589 | .section_node = null, | |
| 590 | .init_node = init_node, | |
| 591 | .semicolon_token = semicolon_token, | |
| 610 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 611 | ||
| 612 | var semicolon: ast.TokenIndex = undefined; | |
| 613 | node.init_node = blk: { | |
| 614 | const rp = makeRestorePoint(c); | |
| 615 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { | |
| 616 | const opaque = try transCreateNodeOpaqueType(c); | |
| 617 | semicolon = try appendToken(c, .Semicolon, ";"); | |
| 618 | break :blk opaque; | |
| 619 | }; | |
| 620 | ||
| 621 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | |
| 622 | const container_tok = try appendToken(c, container_kind, container_kind_name); | |
| 623 | const lbrace_token = try appendToken(c, .LBrace, "{"); | |
| 624 | ||
| 625 | const container_node = try c.a().create(ast.Node.ContainerDecl); | |
| 626 | container_node.* = .{ | |
| 627 | .layout_token = extern_tok, | |
| 628 | .kind_token = container_tok, | |
| 629 | .init_arg_expr = .None, | |
| 630 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | |
| 631 | .lbrace_token = lbrace_token, | |
| 632 | .rbrace_token = undefined, | |
| 633 | }; | |
| 634 | ||
| 635 | var it = ZigClangRecordDecl_field_begin(record_def); | |
| 636 | const end_it = ZigClangRecordDecl_field_end(record_def); | |
| 637 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { | |
| 638 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); | |
| 639 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); | |
| 640 | ||
| 641 | if (ZigClangFieldDecl_isBitField(field_decl)) { | |
| 642 | const opaque = try transCreateNodeOpaqueType(c); | |
| 643 | semicolon = try appendToken(c, .Semicolon, ";"); | |
| 644 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); | |
| 645 | break :blk opaque; | |
| 646 | } | |
| 647 | const raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); | |
| 648 | if (raw_name.len < 1) continue; // fix weird windows bug? | |
| 649 | const field_name = try appendIdentifier(c, raw_name); | |
| 650 | _ = try appendToken(c, .Colon, ":"); | |
| 651 | const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { | |
| 652 | error.UnsupportedType => { | |
| 653 | try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); | |
| 654 | return null; | |
| 655 | }, | |
| 656 | else => |e| return e, | |
| 657 | }; | |
| 658 | ||
| 659 | const field_node = try c.a().create(ast.Node.ContainerField); | |
| 660 | field_node.* = .{ | |
| 661 | .doc_comments = null, | |
| 662 | .comptime_token = null, | |
| 663 | .name_token = field_name, | |
| 664 | .type_expr = field_type, | |
| 665 | .value_expr = null, | |
| 666 | .align_expr = null, | |
| 667 | }; | |
| 668 | ||
| 669 | try container_node.fields_and_decls.push(&field_node.base); | |
| 670 | _ = try appendToken(c, .Comma, ","); | |
| 671 | } | |
| 672 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | |
| 673 | semicolon = try appendToken(c, .Semicolon, ";"); | |
| 674 | break :blk &container_node.base; | |
| 592 | 675 | }; |
| 676 | node.semicolon_token = semicolon; | |
| 593 | 677 | |
| 594 | 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 | } |
| 597 | 683 | |
| 598 | fn createAlias(c: *Context, alias: var) !void { | |
| 599 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 600 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 601 | const name_tok = try appendIdentifier(c, alias.alias); | |
| 684 | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { | |
| 685 | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| | |
| 686 | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice | |
| 687 | const rp = makeRestorePoint(c); | |
| 688 | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); | |
| 602 | 689 | |
| 603 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 604 | const init_node = try transCreateNodeIdentifier(c, alias.name); | |
| 690 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); | |
| 691 | var is_unnamed = false; | |
| 692 | if (bare_name.len == 0) { | |
| 693 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | |
| 694 | is_unnamed = true; | |
| 695 | } | |
| 605 | 696 | |
| 606 | const node = try c.a().create(ast.Node.VarDecl); | |
| 607 | node.* = ast.Node.VarDecl{ | |
| 608 | .doc_comments = null, | |
| 609 | .visib_token = visib_tok, | |
| 610 | .thread_local_token = null, | |
| 611 | .name_token = name_tok, | |
| 612 | .eq_token = eq_tok, | |
| 613 | .mut_token = mut_tok, | |
| 614 | .comptime_token = null, | |
| 615 | .extern_export_token = null, | |
| 616 | .lib_name = null, | |
| 617 | .type_node = null, | |
| 618 | .align_node = null, | |
| 619 | .section_node = null, | |
| 620 | .init_node = init_node, | |
| 621 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | |
| 622 | }; | |
| 623 | return addTopLevelDecl(c, alias.alias, &node.base); | |
| 624 | } | |
| 697 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); | |
| 698 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); | |
| 699 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | |
| 700 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 625 | 701 | |
| 626 | const ResultUsed = enum { | |
| 627 | used, | |
| 628 | unused, | |
| 629 | }; | |
| 702 | node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { | |
| 703 | var pure_enum = true; | |
| 704 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); | |
| 705 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); | |
| 706 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | |
| 707 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | |
| 708 | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { | |
| 709 | pure_enum = false; | |
| 710 | break; | |
| 711 | } | |
| 712 | } | |
| 630 | 713 | |
| 631 | const LRValue = enum { | |
| 632 | l_value, | |
| 633 | r_value, | |
| 634 | }; | |
| 714 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | |
| 715 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); | |
| 635 | 716 | |
| 636 | fn transStmt( | |
| 637 | rp: RestorePoint, | |
| 638 | scope: *Scope, | |
| 639 | stmt: *const ZigClangStmt, | |
| 640 | result_used: ResultUsed, | |
| 641 | lrvalue: LRValue, | |
| 642 | ) TransError!*ast.Node { | |
| 643 | const sc = ZigClangStmt_getStmtClass(stmt); | |
| 644 | switch (sc) { | |
| 645 | .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used), | |
| 646 | .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)), | |
| 647 | .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const ZigClangCStyleCastExpr, stmt), result_used, lrvalue), | |
| 648 | .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)), | |
| 649 | .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue), | |
| 650 | .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used), | |
| 651 | .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), | |
| 652 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), | |
| 653 | .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), | |
| 654 | .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue), | |
| 655 | .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), | |
| 656 | .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), | |
| 657 | else => { | |
| 658 | return revertAndWarn( | |
| 659 | rp, | |
| 660 | error.UnsupportedTranslation, | |
| 661 | ZigClangStmt_getBeginLoc(stmt), | |
| 662 | "TODO implement translation of stmt class {}", | |
| 663 | .{@tagName(sc)}, | |
| 664 | ); | |
| 665 | }, | |
| 666 | } | |
| 667 | } | |
| 717 | const container_node = try c.a().create(ast.Node.ContainerDecl); | |
| 718 | container_node.* = .{ | |
| 719 | .layout_token = extern_tok, | |
| 720 | .kind_token = container_tok, | |
| 721 | .init_arg_expr = .None, | |
| 722 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | |
| 723 | .lbrace_token = undefined, | |
| 724 | .rbrace_token = undefined, | |
| 725 | }; | |
| 668 | 726 | |
| 669 | fn transBinaryOperator( | |
| 670 | rp: RestorePoint, | |
| 671 | scope: *Scope, | |
| 672 | stmt: *const ZigClangBinaryOperator, | |
| 673 | result_used: ResultUsed, | |
| 674 | ) TransError!*ast.Node { | |
| 675 | const op = ZigClangBinaryOperator_getOpcode(stmt); | |
| 676 | const qt = ZigClangBinaryOperator_getType(stmt); | |
| 677 | switch (op) { | |
| 678 | .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn( | |
| 679 | rp, | |
| 680 | error.UnsupportedTranslation, | |
| 681 | ZigClangBinaryOperator_getBeginLoc(stmt), | |
| 682 | "TODO: handle more C binary operators: {}", | |
| 683 | .{op}, | |
| 684 | ), | |
| 685 | .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base, | |
| 686 | .Add => { | |
| 687 | const node = if (cIsUnsignedInteger(qt)) | |
| 688 | try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true) | |
| 727 | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); | |
| 728 | ||
| 729 | // TODO only emit this tag type if the enum tag type is not the default. | |
| 730 | // I don't know what the default is, need to figure out how clang is deciding. | |
| 731 | // it appears to at least be different across gcc/msvc | |
| 732 | if (!isCBuiltinType(int_type, .UInt) and | |
| 733 | !isCBuiltinType(int_type, .Int)) | |
| 734 | { | |
| 735 | _ = try appendToken(c, .LParen, "("); | |
| 736 | container_node.init_arg_expr = .{ | |
| 737 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { | |
| 738 | error.UnsupportedType => { | |
| 739 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); | |
| 740 | return null; | |
| 741 | }, | |
| 742 | else => |e| return e, | |
| 743 | }, | |
| 744 | }; | |
| 745 | _ = try appendToken(c, .RParen, ")"); | |
| 746 | } | |
| 747 | ||
| 748 | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); | |
| 749 | ||
| 750 | it = ZigClangEnumDecl_enumerator_begin(enum_def); | |
| 751 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); | |
| 752 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | |
| 753 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | |
| 754 | ||
| 755 | const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); | |
| 756 | ||
| 757 | const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name)) | |
| 758 | enum_val_name[bare_name.len..] | |
| 689 | 759 | else |
| 690 | try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true); | |
| 691 | return maybeSuppressResult(rp, scope, result_used, node); | |
| 760 | enum_val_name; | |
| 761 | ||
| 762 | const field_name_tok = try appendIdentifier(c, field_name); | |
| 763 | ||
| 764 | const int_node = if (!pure_enum) blk: { | |
| 765 | _ = try appendToken(c, .Colon, "="); | |
| 766 | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | |
| 767 | } else | |
| 768 | null; | |
| 769 | ||
| 770 | const field_node = try c.a().create(ast.Node.ContainerField); | |
| 771 | field_node.* = .{ | |
| 772 | .doc_comments = null, | |
| 773 | .comptime_token = null, | |
| 774 | .name_token = field_name_tok, | |
| 775 | .type_expr = null, | |
| 776 | .value_expr = int_node, | |
| 777 | .align_expr = null, | |
| 778 | }; | |
| 779 | ||
| 780 | try container_node.fields_and_decls.push(&field_node.base); | |
| 781 | _ = try appendToken(c, .Comma, ","); | |
| 782 | // In C each enum value is in the global namespace. So we put them there too. | |
| 783 | // At this point we can rely on the enum emitting successfully. | |
| 784 | const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); | |
| 785 | tld_node.eq_token = try appendToken(c, .Equal, "="); | |
| 786 | tld_node.init_node = try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | |
| 787 | tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 788 | try addTopLevelDecl(c, field_name, &tld_node.base); | |
| 789 | } | |
| 790 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | |
| 791 | ||
| 792 | break :blk &container_node.base; | |
| 793 | } else | |
| 794 | try transCreateNodeOpaqueType(c); | |
| 795 | ||
| 796 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 797 | ||
| 798 | try addTopLevelDecl(c, name, &node.base); | |
| 799 | if (!is_unnamed) | |
| 800 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | |
| 801 | return transCreateNodeIdentifier(c, name); | |
| 802 | } | |
| 803 | ||
| 804 | fn 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 | ||
| 812 | const ResultUsed = enum { | |
| 813 | used, | |
| 814 | unused, | |
| 815 | }; | |
| 816 | ||
| 817 | const LRValue = enum { | |
| 818 | l_value, | |
| 819 | r_value, | |
| 820 | }; | |
| 821 | ||
| 822 | fn 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 => { | |
| 694 | const node = if (cIsUnsignedInteger(qt)) | |
| 695 | try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true) | |
| 696 | else | |
| 697 | try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true); | |
| 698 | return maybeSuppressResult(rp, scope, result_used, node); | |
| 851 | .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), | |
| 852 | .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), | |
| 853 | .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)), | |
| 854 | .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), | |
| 855 | .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), | |
| 856 | .NullStmtClass => { | |
| 857 | const block = try transCreateNodeBlock(rp.c, null); | |
| 858 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 859 | return &block.base; | |
| 699 | 860 | }, |
| 700 | .Mul => { | |
| 701 | const node = if (cIsUnsignedInteger(qt)) | |
| 702 | try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true) | |
| 703 | else | |
| 704 | try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true); | |
| 705 | return maybeSuppressResult(rp, scope, result_used, node); | |
| 861 | .ContinueStmtClass => return try transCreateNodeContinue(rp.c), | |
| 862 | .BreakStmtClass => return transBreak(rp, scope), | |
| 863 | .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)), | |
| 864 | .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const ZigClangFloatingLiteral, stmt), result_used), | |
| 865 | .ConditionalOperatorClass => return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used), | |
| 866 | .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const ZigClangSwitchStmt, stmt)), | |
| 867 | .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const ZigClangCaseStmt, stmt)), | |
| 868 | .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)), | |
| 869 | .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), | |
| 870 | .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), | |
| 871 | .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), | |
| 872 | .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), | |
| 873 | .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), | |
| 874 | .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used), | |
| 875 | .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used), | |
| 876 | .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used), | |
| 877 | .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used), | |
| 878 | .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used), | |
| 879 | else => { | |
| 880 | return revertAndWarn( | |
| 881 | rp, | |
| 882 | error.UnsupportedTranslation, | |
| 883 | ZigClangStmt_getBeginLoc(stmt), | |
| 884 | "TODO implement translation of stmt class {}", | |
| 885 | .{@tagName(sc)}, | |
| 886 | ); | |
| 887 | }, | |
| 888 | } | |
| 889 | } | |
| 890 | ||
| 891 | fn 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 | 934 | .Div => { |
| 708 | 935 | if (!cIsUnsignedInteger(qt)) { |
| 709 | 936 | // signed integer division uses @divTrunc |
| 710 | 937 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); |
| 711 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | |
| 712 | try div_trunc_node.params.push(lhs); | |
| 938 | try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | |
| 713 | 939 | _ = try appendToken(rp.c, .Comma, ","); |
| 714 | 940 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 715 | 941 | try div_trunc_node.params.push(rhs); |
| 716 | 942 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 717 | 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 | 946 | .Rem => { |
| 725 | 947 | if (!cIsUnsignedInteger(qt)) { |
| 726 | 948 | // signed integer division uses @rem |
| 727 | 949 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); |
| 728 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | |
| 729 | try rem_node.params.push(lhs); | |
| 950 | try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | |
| 730 | 951 | _ = try appendToken(rp.c, .Comma, ","); |
| 731 | 952 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 732 | 953 | try rem_node.params.push(rhs); |
| 733 | 954 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 734 | 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 | 982 | } else { |
| 736 | // unsigned/float division uses the operator | |
| 737 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true); | |
| 738 | return maybeSuppressResult(rp, scope, result_used, node); | |
| 983 | op_token = try appendToken(rp.c, .Plus, "+"); | |
| 984 | op_id = .Add; | |
| 739 | 985 | } |
| 740 | 986 | }, |
| 741 | .Shl, | |
| 742 | .Shr, | |
| 743 | .LT, | |
| 744 | .GT, | |
| 745 | .LE, | |
| 746 | .GE, | |
| 747 | .EQ, | |
| 748 | .NE, | |
| 749 | .And, | |
| 750 | .Xor, | |
| 751 | .Or, | |
| 752 | .LAnd, | |
| 753 | .LOr, | |
| 754 | .Comma, | |
| 755 | => return revertAndWarn( | |
| 756 | rp, | |
| 757 | error.UnsupportedTranslation, | |
| 758 | ZigClangBinaryOperator_getBeginLoc(stmt), | |
| 759 | "TODO: handle more C binary operators: {}", | |
| 760 | .{op}, | |
| 761 | ), | |
| 987 | .Sub => { | |
| 988 | if (cIsUnsignedInteger(qt)) { | |
| 989 | op_token = try appendToken(rp.c, .MinusPercent, "-%"); | |
| 990 | op_id = .SubWrap; | |
| 991 | } else { | |
| 992 | op_token = try appendToken(rp.c, .Minus, "-"); | |
| 993 | op_id = .Sub; | |
| 994 | } | |
| 995 | }, | |
| 996 | .Mul => { | |
| 997 | if (cIsUnsignedInteger(qt)) { | |
| 998 | op_token = try appendToken(rp.c, .AsteriskPercent, "*%"); | |
| 999 | op_id = .MulWrap; | |
| 1000 | } else { | |
| 1001 | op_token = try appendToken(rp.c, .Asterisk, "*"); | |
| 1002 | op_id = .Mul; | |
| 1003 | } | |
| 1004 | }, | |
| 1005 | .Div => { | |
| 1006 | // unsigned/float division uses the operator | |
| 1007 | op_id = .Div; | |
| 1008 | op_token = try appendToken(rp.c, .Slash, "/"); | |
| 1009 | }, | |
| 1010 | .Rem => { | |
| 1011 | // unsigned/float division uses the operator | |
| 1012 | op_id = .Mod; | |
| 1013 | op_token = try appendToken(rp.c, .Percent, "%"); | |
| 1014 | }, | |
| 1015 | .LT => { | |
| 1016 | op_id = .LessThan; | |
| 1017 | op_token = try appendToken(rp.c, .AngleBracketLeft, "<"); | |
| 1018 | }, | |
| 1019 | .GT => { | |
| 1020 | op_id = .GreaterThan; | |
| 1021 | op_token = try appendToken(rp.c, .AngleBracketRight, ">"); | |
| 1022 | }, | |
| 1023 | .LE => { | |
| 1024 | op_id = .LessOrEqual; | |
| 1025 | op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<="); | |
| 1026 | }, | |
| 1027 | .GE => { | |
| 1028 | op_id = .GreaterOrEqual; | |
| 1029 | op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">="); | |
| 1030 | }, | |
| 1031 | .EQ => { | |
| 1032 | op_id = .EqualEqual; | |
| 1033 | op_token = try appendToken(rp.c, .EqualEqual, "=="); | |
| 1034 | }, | |
| 1035 | .NE => { | |
| 1036 | op_id = .BangEqual; | |
| 1037 | op_token = try appendToken(rp.c, .BangEqual, "!="); | |
| 1038 | }, | |
| 1039 | .And => { | |
| 1040 | op_id = .BitAnd; | |
| 1041 | op_token = try appendToken(rp.c, .Ampersand, "&"); | |
| 1042 | }, | |
| 1043 | .Xor => { | |
| 1044 | op_id = .BitXor; | |
| 1045 | op_token = try appendToken(rp.c, .Caret, "^"); | |
| 1046 | }, | |
| 1047 | .Or => { | |
| 1048 | op_id = .BitOr; | |
| 1049 | op_token = try appendToken(rp.c, .Pipe, "|"); | |
| 1050 | }, | |
| 1051 | .Assign, | |
| 762 | 1052 | .MulAssign, |
| 763 | 1053 | .DivAssign, |
| 764 | 1054 | .RemAssign, |
| ... | ... | @@ -772,6 +1062,9 @@ fn transBinaryOperator( |
| 772 | 1062 | => unreachable, |
| 773 | 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 | } |
| 776 | 1069 | |
| 777 | 1070 | fn transCompoundStmtInline( |
| ... | ... | @@ -790,11 +1083,11 @@ fn transCompoundStmtInline( |
| 790 | 1083 | } |
| 791 | 1084 | |
| 792 | 1085 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { |
| 793 | const block_node = try transCreateNodeBlock(rp.c, null); | |
| 794 | const block_scope = try Scope.Block.init(rp.c, scope, block_node); | |
| 795 | try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); | |
| 796 | block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 797 | return &block_node.base; | |
| 1086 | const block_scope = try Scope.Block.init(rp.c, scope, null); | |
| 1087 | block_scope.block_node = try transCreateNodeBlock(rp.c, null); | |
| 1088 | try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); | |
| 1089 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1090 | return &block_scope.block_node.base; | |
| 798 | 1091 | } |
| 799 | 1092 | |
| 800 | 1093 | fn transCStyleCastExprClass( |
| ... | ... | @@ -818,7 +1111,7 @@ fn transCStyleCastExprClass( |
| 818 | 1111 | |
| 819 | 1112 | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { |
| 820 | 1113 | const c = rp.c; |
| 821 | const block_scope = scope.findBlockScope(); | |
| 1114 | const block_scope = scope.findBlockScope(c) catch unreachable; | |
| 822 | 1115 | |
| 823 | 1116 | var it = ZigClangDeclStmt_decl_begin(stmt); |
| 824 | 1117 | const end_it = ZigClangDeclStmt_decl_end(stmt); |
| ... | ... | @@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) |
| 832 | 1125 | else |
| 833 | 1126 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 834 | 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 | 1128 | const name = try c.str(ZigClangDecl_getName_bytes_begin( |
| 840 | 1129 | @ptrCast(*const ZigClangDecl, var_decl), |
| 841 | 1130 | )); |
| ... | ... | @@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) |
| 843 | 1132 | try block_scope.variables.push(.{ .name = name, .alias = a }); |
| 844 | 1133 | break :blk a; |
| 845 | 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); | |
| 847 | 1136 | |
| 848 | const colon_token = try appendToken(c, .Colon, ":"); | |
| 1137 | _ = try appendToken(c, .Colon, ":"); | |
| 849 | 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); | |
| 851 | 1140 | |
| 852 | const eq_token = try appendToken(c, .Equal, "="); | |
| 853 | const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| | |
| 1141 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 1142 | var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| | |
| 854 | 1143 | try transExpr(rp, scope, expr, .used, .r_value) |
| 855 | 1144 | else |
| 856 | 1145 | try transCreateNodeUndefinedLiteral(c); |
| 857 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 858 | ||
| 859 | const node = try c.a().create(ast.Node.VarDecl); | |
| 860 | node.* = ast.Node.VarDecl{ | |
| 861 | .doc_comments = null, | |
| 862 | .visib_token = null, | |
| 863 | .thread_local_token = thread_local_token, | |
| 864 | .name_token = name_token, | |
| 865 | .eq_token = eq_token, | |
| 866 | .mut_token = mut_token, | |
| 867 | .comptime_token = null, | |
| 868 | .extern_export_token = null, | |
| 869 | .lib_name = null, | |
| 870 | .type_node = type_node, | |
| 871 | .align_node = null, // TODO ?*Node, | |
| 872 | .section_node = null, | |
| 873 | .init_node = init_node, | |
| 874 | .semicolon_token = semicolon_token, | |
| 875 | }; | |
| 1146 | if (isBoolRes(init_node)) { | |
| 1147 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | |
| 1148 | try builtin_node.params.push(init_node); | |
| 1149 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 1150 | init_node = &builtin_node.base; | |
| 1151 | } | |
| 1152 | node.init_node = init_node; | |
| 1153 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 876 | 1154 | try block_scope.block_node.statements.push(&node.base); |
| 877 | 1155 | }, |
| 878 | 1156 | else => |kind| return revertAndWarn( |
| ... | ... | @@ -896,7 +1174,6 @@ fn transDeclRefExpr( |
| 896 | 1174 | const value_decl = ZigClangDeclRefExpr_getDecl(expr); |
| 897 | 1175 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); |
| 898 | 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 | 1177 | return transCreateNodeIdentifier(rp.c, checked_name); |
| 901 | 1178 | } |
| 902 | 1179 | |
| ... | ... | @@ -909,25 +1186,58 @@ fn transImplicitCastExpr( |
| 909 | 1186 | const c = rp.c; |
| 910 | 1187 | const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); |
| 911 | 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 | 1191 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { |
| 913 | .BitCast => { | |
| 914 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); | |
| 915 | const src_type = getExprQualType(c, sub_expr); | |
| 1192 | .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => { | |
| 916 | 1193 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); |
| 917 | 1194 | }, |
| 918 | .IntegralCast => { | |
| 919 | const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr)); | |
| 920 | const src_type = ZigClangExpr_getType(sub_expr); | |
| 921 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); | |
| 922 | }, | |
| 923 | .FunctionToPointerDecay, .ArrayToPointerDecay => { | |
| 1195 | .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => { | |
| 924 | 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 | 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 | 1242 | else => |kind| return revertAndWarn( |
| 933 | 1243 | rp, |
| ... | ... | @@ -939,50 +1249,195 @@ fn transImplicitCastExpr( |
| 939 | 1249 | } |
| 940 | 1250 | } |
| 941 | 1251 | |
| 942 | fn transIntegerLiteral( | |
| 1252 | fn transBoolExpr( | |
| 943 | 1253 | rp: RestorePoint, |
| 944 | 1254 | scope: *Scope, |
| 945 | expr: *const ZigClangIntegerLiteral, | |
| 946 | result_used: ResultUsed, | |
| 1255 | expr: *const ZigClangExpr, | |
| 1256 | used: ResultUsed, | |
| 1257 | lrvalue: LRValue, | |
| 1258 | grouped: bool, | |
| 947 | 1259 | ) TransError!*ast.Node { |
| 948 | var eval_result: ZigClangExprEvalResult = undefined; | |
| 949 | if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) { | |
| 950 | const loc = ZigClangIntegerLiteral_getBeginLoc(expr); | |
| 951 | return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); | |
| 1260 | const lparen = if (grouped) | |
| 1261 | try appendToken(rp.c, .LParen, "(") | |
| 1262 | else | |
| 1263 | undefined; | |
| 1264 | var res = try transExpr(rp, scope, expr, used, lrvalue); | |
| 1265 | ||
| 1266 | if (isBoolRes(res)) { | |
| 1267 | if (!grouped and res.id == .GroupedExpression) { | |
| 1268 | const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res); | |
| 1269 | res = group.expr; | |
| 1270 | // get zig fmt to work properly | |
| 1271 | tokenSlice(rp.c, group.lparen)[0] = ')'; | |
| 1272 | } | |
| 1273 | return res; | |
| 1274 | } | |
| 1275 | ||
| 1276 | const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr)); | |
| 1277 | const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used); | |
| 1278 | ||
| 1279 | if (grouped) { | |
| 1280 | const rparen = try appendToken(rp.c, .RParen, ")"); | |
| 1281 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | |
| 1282 | grouped_expr.* = .{ | |
| 1283 | .lparen = lparen, | |
| 1284 | .expr = node, | |
| 1285 | .rparen = rparen, | |
| 1286 | }; | |
| 1287 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | |
| 1288 | } else { | |
| 1289 | return maybeSuppressResult(rp, scope, used, node); | |
| 952 | 1290 | } |
| 953 | const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); | |
| 954 | return maybeSuppressResult(rp, scope, result_used, node); | |
| 955 | 1291 | } |
| 956 | 1292 | |
| 957 | fn transReturnStmt( | |
| 958 | rp: RestorePoint, | |
| 959 | scope: *Scope, | |
| 960 | expr: *const ZigClangReturnStmt, | |
| 961 | ) TransError!*ast.Node { | |
| 962 | const node = try transCreateNodeReturnExpr(rp.c); | |
| 963 | if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { | |
| 964 | node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value); | |
| 1293 | fn isBoolRes(res: *ast.Node) bool { | |
| 1294 | switch (res.id) { | |
| 1295 | .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) { | |
| 1296 | .BoolOr, | |
| 1297 | .BoolAnd, | |
| 1298 | .EqualEqual, | |
| 1299 | .BangEqual, | |
| 1300 | .LessThan, | |
| 1301 | .GreaterThan, | |
| 1302 | .LessOrEqual, | |
| 1303 | .GreaterOrEqual, | |
| 1304 | => return true, | |
| 1305 | ||
| 1306 | else => {}, | |
| 1307 | }, | |
| 1308 | .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) { | |
| 1309 | .BoolNot => return true, | |
| 1310 | ||
| 1311 | else => {}, | |
| 1312 | }, | |
| 1313 | .BoolLiteral => return true, | |
| 1314 | .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr), | |
| 1315 | else => {}, | |
| 965 | 1316 | } |
| 966 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 967 | return &node.base; | |
| 1317 | return false; | |
| 968 | 1318 | } |
| 969 | 1319 | |
| 970 | fn transStringLiteral( | |
| 1320 | fn finishBoolExpr( | |
| 971 | 1321 | rp: RestorePoint, |
| 972 | 1322 | scope: *Scope, |
| 973 | stmt: *const ZigClangStringLiteral, | |
| 974 | result_used: ResultUsed, | |
| 1323 | loc: ZigClangSourceLocation, | |
| 1324 | ty: *const ZigClangType, | |
| 1325 | node: *ast.Node, | |
| 1326 | used: ResultUsed, | |
| 975 | 1327 | ) TransError!*ast.Node { |
| 976 | const kind = ZigClangStringLiteral_getKind(stmt); | |
| 977 | switch (kind) { | |
| 978 | .Ascii, .UTF8 => { | |
| 979 | var len: usize = undefined; | |
| 980 | const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len); | |
| 981 | const str = bytes_ptr[0..len]; | |
| 982 | ||
| 983 | var char_buf: [4]u8 = undefined; | |
| 984 | len = 0; | |
| 985 | for (str) |c| len += escapeChar(c, &char_buf).len; | |
| 1328 | switch (ZigClangType_getTypeClass(ty)) { | |
| 1329 | .Builtin => { | |
| 1330 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); | |
| 1331 | ||
| 1332 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { | |
| 1333 | .Bool => return node, | |
| 1334 | .Char_U, | |
| 1335 | .UChar, | |
| 1336 | .Char_S, | |
| 1337 | .SChar, | |
| 1338 | .UShort, | |
| 1339 | .UInt, | |
| 1340 | .ULong, | |
| 1341 | .ULongLong, | |
| 1342 | .Short, | |
| 1343 | .Int, | |
| 1344 | .Long, | |
| 1345 | .LongLong, | |
| 1346 | .UInt128, | |
| 1347 | .Int128, | |
| 1348 | .Float, | |
| 1349 | .Double, | |
| 1350 | .Float128, | |
| 1351 | .LongDouble, | |
| 1352 | .WChar_U, | |
| 1353 | .Char8, | |
| 1354 | .Char16, | |
| 1355 | .Char32, | |
| 1356 | .WChar_S, | |
| 1357 | .Float16, | |
| 1358 | => { | |
| 1359 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | |
| 1360 | const rhs_node = try transCreateNodeInt(rp.c, 0); | |
| 1361 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | |
| 1362 | }, | |
| 1363 | .NullPtr => { | |
| 1364 | const op_token = try appendToken(rp.c, .EqualEqual, "=="); | |
| 1365 | const rhs_node = try transCreateNodeNullLiteral(rp.c); | |
| 1366 | return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false); | |
| 1367 | }, | |
| 1368 | else => {}, | |
| 1369 | } | |
| 1370 | }, | |
| 1371 | .Pointer => { | |
| 1372 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | |
| 1373 | const rhs_node = try transCreateNodeNullLiteral(rp.c); | |
| 1374 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | |
| 1375 | }, | |
| 1376 | .Typedef => { | |
| 1377 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); | |
| 1378 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); | |
| 1379 | const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); | |
| 1380 | return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used); | |
| 1381 | }, | |
| 1382 | .Enum => { | |
| 1383 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | |
| 1384 | const rhs_node = try transCreateNodeInt(rp.c, 0); | |
| 1385 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | |
| 1386 | }, | |
| 1387 | .Elaborated => { | |
| 1388 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); | |
| 1389 | const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty); | |
| 1390 | return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used); | |
| 1391 | }, | |
| 1392 | else => {}, | |
| 1393 | } | |
| 1394 | return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{}); | |
| 1395 | } | |
| 1396 | ||
| 1397 | fn 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 | ||
| 1412 | fn 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 | ||
| 1425 | fn 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; | |
| 986 | 1441 | |
| 987 | 1442 | const buf = try rp.c.a().alloc(u8, len + "\"\"".len); |
| 988 | 1443 | buf[0] = '"'; |
| ... | ... | @@ -991,7 +1446,7 @@ fn transStringLiteral( |
| 991 | 1446 | |
| 992 | 1447 | const token = try appendToken(rp.c, .StringLiteral, buf); |
| 993 | 1448 | const node = try rp.c.a().create(ast.Node.StringLiteral); |
| 994 | node.* = ast.Node.StringLiteral{ | |
| 1449 | node.* = .{ | |
| 995 | 1450 | .token = token, |
| 996 | 1451 | }; |
| 997 | 1452 | return maybeSuppressResult(rp, scope, result_used, &node.base); |
| ... | ... | @@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { |
| 1019 | 1474 | var i: usize = 0; |
| 1020 | 1475 | for (s) |c| { |
| 1021 | 1476 | const escaped = escapeChar(c, &char_buf); |
| 1022 | std.mem.copy(u8, buf[i..], escaped); | |
| 1477 | mem.copy(u8, buf[i..], escaped); | |
| 1023 | 1478 | i += escaped.len; |
| 1024 | 1479 | } |
| 1025 | 1480 | } |
| 1026 | 1481 | |
| 1027 | 1482 | // Returns either a string literal or a slice of `buf`. |
| 1028 | 1483 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { |
| 1029 | // TODO: https://github.com/ziglang/zig/issues/2749 | |
| 1030 | const escaped = switch (c) { | |
| 1031 | // Printable ASCII except for ' " \ | |
| 1032 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..], | |
| 1033 | '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..], | |
| 1034 | '\n' => return "\\n"[0..], | |
| 1035 | '\r' => return "\\r"[0..], | |
| 1036 | '\t' => return "\\t"[0..], | |
| 1037 | else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable, | |
| 1484 | return switch (c) { | |
| 1485 | '\"' => "\\\""[0..], | |
| 1486 | '\'' => "\\'"[0..], | |
| 1487 | '\\' => "\\\\"[0..], | |
| 1488 | '\n' => "\\n"[0..], | |
| 1489 | '\r' => "\\r"[0..], | |
| 1490 | '\t' => "\\t"[0..], | |
| 1491 | else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable, | |
| 1038 | 1492 | }; |
| 1039 | std.mem.copy(u8, char_buf, escaped); | |
| 1040 | return char_buf[0..escaped.len]; | |
| 1041 | 1493 | } |
| 1042 | 1494 | |
| 1043 | 1495 | fn transCCast( |
| ... | ... | @@ -1071,6 +1523,55 @@ fn transCCast( |
| 1071 | 1523 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1072 | 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 | 1575 | // TODO: maybe widen to increase size |
| 1075 | 1576 | // TODO: maybe bitcast to change sign |
| 1076 | 1577 | // TODO: maybe truncate to reduce size |
| ... | ... | @@ -1124,7 +1625,7 @@ fn transInitListExpr( |
| 1124 | 1625 | var cat_tok: ast.TokenIndex = undefined; |
| 1125 | 1626 | if (init_count != 0) { |
| 1126 | 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 | 1629 | var i: c_uint = 0; |
| 1129 | 1630 | while (i < init_count) : (i += 1) { |
| 1130 | 1631 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); |
| ... | ... | @@ -1139,7 +1640,7 @@ fn transInitListExpr( |
| 1139 | 1640 | } |
| 1140 | 1641 | |
| 1141 | 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 | 1644 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); |
| 1144 | 1645 | try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value)); |
| 1145 | 1646 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| ... | ... | @@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr( |
| 1185 | 1686 | .Builtin => blk: { |
| 1186 | 1687 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 1187 | 1688 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 1188 | .Bool => return transCreateNodeBoolLiteral(rp.c, false), | |
| 1689 | .Bool => return try transCreateNodeBoolLiteral(rp.c, false), | |
| 1189 | 1690 | .Char_U, |
| 1190 | 1691 | .UChar, |
| 1191 | 1692 | .Char_S, |
| ... | ... | @@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr( |
| 1215 | 1716 | }; |
| 1216 | 1717 | } |
| 1217 | 1718 | |
| 1218 | fn transCPtrCast( | |
| 1719 | fn transIfStmt( | |
| 1219 | 1720 | rp: RestorePoint, |
| 1220 | loc: ZigClangSourceLocation, | |
| 1221 | dst_type: ZigClangQualType, | |
| 1222 | src_type: ZigClangQualType, | |
| 1223 | expr: *ast.Node, | |
| 1224 | ) !*ast.Node { | |
| 1225 | const ty = ZigClangQualType_getTypePtr(dst_type); | |
| 1226 | const child_type = ZigClangType_getPointeeType(ty); | |
| 1721 | scope: *Scope, | |
| 1722 | stmt: *const ZigClangIfStmt, | |
| 1723 | ) TransError!*ast.Node { | |
| 1724 | // if (c) t | |
| 1725 | // if (c) t else e | |
| 1726 | const if_node = try transCreateNodeIf(rp.c); | |
| 1227 | 1727 | |
| 1228 | // Implicit downcasting from higher to lower alignment values is forbidden, | |
| 1229 | // use @alignCast to side-step this problem | |
| 1230 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); | |
| 1231 | const dst_type_node = try transType(rp, ty, loc); | |
| 1232 | try ptrcast_node.params.push(dst_type_node); | |
| 1233 | _ = try appendToken(rp.c, .Comma, ","); | |
| 1728 | var cond_scope = Scope{ | |
| 1729 | .parent = scope, | |
| 1730 | .id = .Condition, | |
| 1731 | }; | |
| 1732 | if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); | |
| 1733 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1234 | 1734 | |
| 1235 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { | |
| 1236 | // void has 1-byte alignment, so @alignCast is not needed | |
| 1237 | try ptrcast_node.params.push(expr); | |
| 1238 | } else { | |
| 1239 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); | |
| 1240 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); | |
| 1241 | const child_type_node = try transQualType(rp, child_type, loc); | |
| 1242 | try alignof_node.params.push(child_type_node); | |
| 1243 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 1244 | try aligncast_node.params.push(&alignof_node.base); | |
| 1245 | _ = try appendToken(rp.c, .Comma, ","); | |
| 1246 | try aligncast_node.params.push(expr); | |
| 1247 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 1248 | try ptrcast_node.params.push(&aligncast_node.base); | |
| 1249 | } | |
| 1250 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 1735 | if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); | |
| 1251 | 1736 | |
| 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 | } |
| 1254 | 1744 | |
| 1255 | fn maybeSuppressResult( | |
| 1745 | fn transWhileLoop( | |
| 1256 | 1746 | rp: RestorePoint, |
| 1257 | 1747 | scope: *Scope, |
| 1258 | used: ResultUsed, | |
| 1259 | result: *ast.Node, | |
| 1748 | stmt: *const ZigClangWhileStmt, | |
| 1260 | 1749 | ) TransError!*ast.Node { |
| 1261 | if (used == .used) return result; | |
| 1262 | // NOTE: This is backwards, but the semicolon must immediately follow the node. | |
| 1263 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1264 | const lhs = try transCreateNodeIdentifier(rp.c, "_"); | |
| 1265 | const op_token = try appendToken(rp.c, .Equal, "="); | |
| 1266 | const op_node = try rp.c.a().create(ast.Node.InfixOp); | |
| 1267 | op_node.* = ast.Node.InfixOp{ | |
| 1268 | .op_token = op_token, | |
| 1269 | .lhs = lhs, | |
| 1270 | .op = .Assign, | |
| 1271 | .rhs = result, | |
| 1750 | const while_node = try transCreateNodeWhile(rp.c); | |
| 1751 | ||
| 1752 | var cond_scope = Scope{ | |
| 1753 | .parent = scope, | |
| 1754 | .id = .Condition, | |
| 1272 | 1755 | }; |
| 1273 | return &op_node.base; | |
| 1274 | } | |
| 1756 | while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); | |
| 1757 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1275 | 1758 | |
| 1276 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { | |
| 1277 | try c.tree.root_node.decls.push(decl_node); | |
| 1278 | _ = try c.global_scope.sym_table.put(name, decl_node); | |
| 1759 | var loop_scope = Scope{ | |
| 1760 | .parent = scope, | |
| 1761 | .id = .Loop, | |
| 1762 | }; | |
| 1763 | while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value); | |
| 1764 | return &while_node.base; | |
| 1279 | 1765 | } |
| 1280 | 1766 | |
| 1281 | fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { | |
| 1282 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); | |
| 1283 | } | |
| 1767 | fn transDoWhileLoop( | |
| 1768 | rp: RestorePoint, | |
| 1769 | scope: *Scope, | |
| 1770 | stmt: *const ZigClangDoStmt, | |
| 1771 | ) TransError!*ast.Node { | |
| 1772 | const while_node = try transCreateNodeWhile(rp.c); | |
| 1773 | ||
| 1774 | while_node.condition = try transCreateNodeBoolLiteral(rp.c, true); | |
| 1775 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1776 | var new = false; | |
| 1777 | var loop_scope = Scope{ | |
| 1778 | .parent = scope, | |
| 1779 | .id = .Loop, | |
| 1780 | }; | |
| 1284 | 1781 | |
| 1285 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node { | |
| 1286 | const rp = makeRestorePoint(c); | |
| 1782 | const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: { | |
| 1783 | // there's already a block in C, so we'll append our condition to it. | |
| 1784 | // c: do { | |
| 1785 | // c: a; | |
| 1786 | // c: b; | |
| 1787 | // c: } while(c); | |
| 1788 | // zig: while (true) { | |
| 1789 | // zig: a; | |
| 1790 | // zig: b; | |
| 1791 | // zig: if (!cond) break; | |
| 1792 | // zig: } | |
| 1793 | break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; | |
| 1794 | } else blk: { | |
| 1795 | // the C statement is without a block, so we need to create a block to contain it. | |
| 1796 | // c: do | |
| 1797 | // c: a; | |
| 1798 | // c: while(c); | |
| 1799 | // zig: while (true) { | |
| 1800 | // zig: a; | |
| 1801 | // zig: if (!cond) break; | |
| 1802 | // zig: } | |
| 1803 | new = true; | |
| 1804 | const block = try transCreateNodeBlock(rp.c, null); | |
| 1805 | try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); | |
| 1806 | break :blk block; | |
| 1807 | }; | |
| 1287 | 1808 | |
| 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, ";"); | |
| 1289 | 1821 | |
| 1290 | var container_kind_name: []const u8 = undefined; | |
| 1291 | var container_kind: std.zig.Token.Id = undefined; | |
| 1822 | try body_node.statements.push(&if_node.base); | |
| 1823 | if (new) | |
| 1824 | body_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1825 | while_node.body = &body_node.base; | |
| 1826 | return &while_node.base; | |
| 1827 | } | |
| 1292 | 1828 | |
| 1293 | if (ZigClangRecordDecl_isUnion(record_decl)) { | |
| 1294 | container_kind_name = "union"; | |
| 1295 | container_kind = .Keyword_union; | |
| 1296 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { | |
| 1297 | container_kind_name = "struct"; | |
| 1298 | container_kind = .Keyword_struct; | |
| 1299 | } else { | |
| 1300 | return revertAndWarn( | |
| 1301 | rp, | |
| 1302 | error.UnsupportedType, | |
| 1303 | record_loc, | |
| 1304 | "unsupported record type", | |
| 1305 | .{}, | |
| 1306 | ); | |
| 1829 | fn transForLoop( | |
| 1830 | rp: RestorePoint, | |
| 1831 | scope: *Scope, | |
| 1832 | stmt: *const ZigClangForStmt, | |
| 1833 | ) TransError!*ast.Node { | |
| 1834 | var loop_scope = Scope{ | |
| 1835 | .parent = scope, | |
| 1836 | .id = .Loop, | |
| 1837 | }; | |
| 1838 | var block = false; | |
| 1839 | var block_scope: ?*Scope.Block = null; | |
| 1840 | if (ZigClangForStmt_getInit(stmt)) |init| { | |
| 1841 | block_scope = try Scope.Block.init(rp.c, scope, null); | |
| 1842 | block_scope.?.block_node = try transCreateNodeBlock(rp.c, null); | |
| 1843 | loop_scope.parent = &block_scope.?.base; | |
| 1844 | _ = try transStmt(rp, &loop_scope, init, .unused, .r_value); | |
| 1307 | 1845 | } |
| 1308 | ||
| 1309 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { | |
| 1310 | return transCreateNodeOpaqueType(c); | |
| 1846 | var cond_scope = Scope{ | |
| 1847 | .parent = scope, | |
| 1848 | .id = .Condition, | |
| 1311 | 1849 | }; |
| 1312 | 1850 | |
| 1313 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | |
| 1314 | const container_tok = try appendToken(c, container_kind, container_kind_name); | |
| 1315 | const lbrace_token = try appendToken(c, .LBrace, "{"); | |
| 1851 | const while_node = try transCreateNodeWhile(rp.c); | |
| 1852 | while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| | |
| 1853 | try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false) | |
| 1854 | else | |
| 1855 | try transCreateNodeBoolLiteral(rp.c, true); | |
| 1856 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1857 | ||
| 1858 | if (ZigClangForStmt_getInc(stmt)) |incr| { | |
| 1859 | _ = try appendToken(rp.c, .Colon, ":"); | |
| 1860 | _ = try appendToken(rp.c, .LParen, "("); | |
| 1861 | while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value); | |
| 1862 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1863 | } | |
| 1864 | ||
| 1865 | while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); | |
| 1866 | if (block_scope != null) { | |
| 1867 | try block_scope.?.block_node.statements.push(&while_node.base); | |
| 1868 | block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1869 | return &block_scope.?.block_node.base; | |
| 1870 | } else | |
| 1871 | return &while_node.base; | |
| 1872 | } | |
| 1316 | 1873 | |
| 1317 | const container_node = try c.a().create(ast.Node.ContainerDecl); | |
| 1318 | container_node.* = .{ | |
| 1319 | .layout_token = extern_tok, | |
| 1320 | .kind_token = container_tok, | |
| 1321 | .init_arg_expr = .None, | |
| 1322 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | |
| 1323 | .lbrace_token = lbrace_token, | |
| 1324 | .rbrace_token = undefined, | |
| 1874 | fn transSwitch( | |
| 1875 | rp: RestorePoint, | |
| 1876 | scope: *Scope, | |
| 1877 | stmt: *const ZigClangSwitchStmt, | |
| 1878 | ) TransError!*ast.Node { | |
| 1879 | const switch_node = try transCreateNodeSwitch(rp.c); | |
| 1880 | var switch_scope = Scope.Switch{ | |
| 1881 | .base = .{ | |
| 1882 | .id = .Switch, | |
| 1883 | .parent = scope, | |
| 1884 | }, | |
| 1885 | .cases = &switch_node.cases, | |
| 1886 | .pending_block = undefined, | |
| 1325 | 1887 | }; |
| 1326 | 1888 | |
| 1327 | var it = ZigClangRecordDecl_field_begin(record_def); | |
| 1328 | const end_it = ZigClangRecordDecl_field_end(record_def); | |
| 1329 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { | |
| 1330 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); | |
| 1331 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); | |
| 1889 | var cond_scope = Scope{ | |
| 1890 | .parent = scope, | |
| 1891 | .id = .Condition, | |
| 1892 | }; | |
| 1893 | switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); | |
| 1894 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 1895 | _ = try appendToken(rp.c, .LBrace, "{"); | |
| 1896 | switch_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1332 | 1897 | |
| 1333 | if (ZigClangFieldDecl_isBitField(field_decl)) { | |
| 1334 | rp.activate(); | |
| 1335 | const node = try transCreateNodeOpaqueType(c); | |
| 1336 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); | |
| 1337 | return node; | |
| 1338 | } | |
| 1898 | const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); | |
| 1899 | // tmp block that all statements will go before being picked up by a case or default | |
| 1900 | const block = try transCreateNodeBlock(rp.c, null); | |
| 1901 | block_scope.block_node = block; | |
| 1339 | 1902 | |
| 1340 | const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); | |
| 1341 | _ = try appendToken(c, .Colon, ":"); | |
| 1342 | const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); | |
| 1903 | const switch_block = try transCreateNodeBlock(rp.c, null); | |
| 1904 | try switch_block.statements.push(&switch_node.base); | |
| 1905 | switch_scope.pending_block = switch_block; | |
| 1343 | 1906 | |
| 1344 | const field_node = try c.a().create(ast.Node.ContainerField); | |
| 1345 | field_node.* = .{ | |
| 1346 | .doc_comments = null, | |
| 1347 | .comptime_token = null, | |
| 1348 | .name_token = field_name, | |
| 1349 | .type_expr = field_type, | |
| 1350 | .value_expr = null, | |
| 1351 | .align_expr = null, | |
| 1352 | }; | |
| 1907 | const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); | |
| 1908 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1353 | 1909 | |
| 1354 | try container_node.fields_and_decls.push(&field_node.base); | |
| 1355 | _ = try appendToken(c, .Comma, ","); | |
| 1910 | // take all pending statements | |
| 1911 | var it = last.cast(ast.Node.Block).?.statements.iterator(0); | |
| 1912 | while (it.next()) |n| { | |
| 1913 | try switch_scope.pending_block.statements.push(n.*); | |
| 1356 | 1914 | } |
| 1357 | 1915 | |
| 1358 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | |
| 1359 | return &container_node.base; | |
| 1916 | switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); | |
| 1917 | _ = try appendToken(rp.c, .Colon, ":"); | |
| 1918 | if (!switch_scope.has_default) { | |
| 1919 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | |
| 1920 | else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base; | |
| 1921 | _ = try appendToken(rp.c, .Comma, ","); | |
| 1922 | try switch_node.cases.push(&else_prong.base); | |
| 1923 | } | |
| 1924 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1925 | return &switch_scope.pending_block.base; | |
| 1360 | 1926 | } |
| 1361 | 1927 | |
| 1362 | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { | |
| 1363 | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| | |
| 1364 | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice | |
| 1365 | const rp = makeRestorePoint(c); | |
| 1366 | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); | |
| 1928 | fn transCase( | |
| 1929 | rp: RestorePoint, | |
| 1930 | scope: *Scope, | |
| 1931 | stmt: *const ZigClangCaseStmt, | |
| 1932 | ) TransError!*ast.Node { | |
| 1933 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | |
| 1934 | const switch_scope = scope.getSwitch(); | |
| 1935 | const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)}); | |
| 1936 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1367 | 1937 | |
| 1368 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 1369 | const const_tok = try appendToken(c, .Keyword_const, "const"); | |
| 1938 | const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: { | |
| 1939 | const lhs_node = try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value); | |
| 1940 | const ellips = try appendToken(rp.c, .Ellipsis3, "..."); | |
| 1941 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | |
| 1370 | 1942 | |
| 1371 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); | |
| 1372 | var is_unnamed = false; | |
| 1373 | if (bare_name.len == 0) { | |
| 1374 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | |
| 1375 | is_unnamed = true; | |
| 1943 | const node = try rp.c.a().create(ast.Node.InfixOp); | |
| 1944 | node.* = .{ | |
| 1945 | .op_token = ellips, | |
| 1946 | .lhs = lhs_node, | |
| 1947 | .op = .Range, | |
| 1948 | .rhs = rhs_node, | |
| 1949 | }; | |
| 1950 | break :blk &node.base; | |
| 1951 | } else | |
| 1952 | try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value); | |
| 1953 | ||
| 1954 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); | |
| 1955 | switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; | |
| 1956 | _ = try appendToken(rp.c, .Comma, ","); | |
| 1957 | try switch_scope.cases.push(&switch_prong.base); | |
| 1958 | ||
| 1959 | const block = try transCreateNodeBlock(rp.c, null); | |
| 1960 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | |
| 1961 | _ = try appendToken(rp.c, .Colon, ":"); | |
| 1962 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1963 | try block.statements.push(&switch_scope.pending_block.base); | |
| 1964 | ||
| 1965 | // take all pending statements | |
| 1966 | var it = block_scope.block_node.statements.iterator(0); | |
| 1967 | while (it.next()) |n| { | |
| 1968 | try switch_scope.pending_block.statements.push(n.*); | |
| 1376 | 1969 | } |
| 1970 | block_scope.block_node.statements.shrink(0); | |
| 1377 | 1971 | |
| 1378 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); | |
| 1379 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); | |
| 1380 | const name_tok = try appendIdentifier(c, name); | |
| 1381 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 1972 | switch_scope.pending_block = block; | |
| 1382 | 1973 | |
| 1383 | const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { | |
| 1384 | var pure_enum = true; | |
| 1385 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); | |
| 1386 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); | |
| 1387 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | |
| 1388 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | |
| 1389 | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { | |
| 1390 | pure_enum = false; | |
| 1391 | break; | |
| 1392 | } | |
| 1393 | } | |
| 1974 | return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value); | |
| 1975 | } | |
| 1394 | 1976 | |
| 1395 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | |
| 1396 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); | |
| 1977 | fn transDefault( | |
| 1978 | rp: RestorePoint, | |
| 1979 | scope: *Scope, | |
| 1980 | stmt: *const ZigClangDefaultStmt, | |
| 1981 | ) TransError!*ast.Node { | |
| 1982 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | |
| 1983 | const switch_scope = scope.getSwitch(); | |
| 1984 | const label = "__default"; | |
| 1985 | switch_scope.has_default = true; | |
| 1986 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1397 | 1987 | |
| 1398 | const container_node = try c.a().create(ast.Node.ContainerDecl); | |
| 1399 | container_node.* = .{ | |
| 1400 | .layout_token = extern_tok, | |
| 1401 | .kind_token = container_tok, | |
| 1402 | .init_arg_expr = .None, | |
| 1403 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | |
| 1404 | .lbrace_token = undefined, | |
| 1405 | .rbrace_token = undefined, | |
| 1406 | }; | |
| 1988 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | |
| 1989 | else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; | |
| 1990 | _ = try appendToken(rp.c, .Comma, ","); | |
| 1991 | try switch_scope.cases.push(&else_prong.base); | |
| 1992 | ||
| 1993 | const block = try transCreateNodeBlock(rp.c, null); | |
| 1994 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | |
| 1995 | _ = try appendToken(rp.c, .Colon, ":"); | |
| 1996 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 1997 | try block.statements.push(&switch_scope.pending_block.base); | |
| 1998 | ||
| 1999 | // take all pending statements | |
| 2000 | var it = block_scope.block_node.statements.iterator(0); | |
| 2001 | while (it.next()) |n| { | |
| 2002 | try switch_scope.pending_block.statements.push(n.*); | |
| 2003 | } | |
| 2004 | block_scope.block_node.statements.shrink(0); | |
| 1407 | 2005 | |
| 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 | } | |
| 1409 | 2009 | |
| 1410 | // TODO only emit this tag type if the enum tag type is not the default. | |
| 1411 | // I don't know what the default is, need to figure out how clang is deciding. | |
| 1412 | // it appears to at least be different across gcc/msvc | |
| 1413 | if (!isCBuiltinType(int_type, .UInt) and | |
| 1414 | !isCBuiltinType(int_type, .Int)) | |
| 1415 | { | |
| 1416 | _ = try appendToken(c, .LParen, "("); | |
| 1417 | container_node.init_arg_expr = .{ | |
| 1418 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { | |
| 1419 | error.UnsupportedType => { | |
| 1420 | if (is_unnamed) { | |
| 1421 | try emitWarning(c, enum_loc, "unable to translate enum tag type", .{}); | |
| 1422 | } else { | |
| 1423 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); | |
| 1424 | } | |
| 1425 | return null; | |
| 1426 | }, | |
| 1427 | else => |e| return e, | |
| 1428 | }, | |
| 2010 | fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, used: ResultUsed) TransError!*ast.Node { | |
| 2011 | var result: ZigClangExprEvalResult = undefined; | |
| 2012 | if (!ZigClangExpr_EvaluateAsConstantExpr(expr, &result, .EvaluateForCodeGen, rp.c.clang_context)) | |
| 2013 | return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangExpr_getBeginLoc(expr), "invalid constant expression", .{}); | |
| 2014 | return maybeSuppressResult(rp, scope, used, try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val))); | |
| 2015 | } | |
| 2016 | ||
| 2017 | fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPredefinedExpr, used: ResultUsed) TransError!*ast.Node { | |
| 2018 | return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used); | |
| 2019 | } | |
| 2020 | ||
| 2021 | fn transCharLiteral( | |
| 2022 | rp: RestorePoint, | |
| 2023 | scope: *Scope, | |
| 2024 | stmt: *const ZigClangCharacterLiteral, | |
| 2025 | result_used: ResultUsed, | |
| 2026 | ) TransError!*ast.Node { | |
| 2027 | const kind = ZigClangCharacterLiteral_getKind(stmt); | |
| 2028 | switch (kind) { | |
| 2029 | .Ascii, .UTF8 => { | |
| 2030 | const val = ZigClangCharacterLiteral_getValue(stmt); | |
| 2031 | if (kind == .Ascii) { | |
| 2032 | // C has a somewhat obscure feature called multi-character character | |
| 2033 | // constant | |
| 2034 | if (val > 255) | |
| 2035 | return transCreateNodeInt(rp.c, val); | |
| 2036 | } | |
| 2037 | var char_buf: [4]u8 = undefined; | |
| 2038 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); | |
| 2039 | const node = try rp.c.a().create(ast.Node.CharLiteral); | |
| 2040 | node.* = .{ | |
| 2041 | .token = token, | |
| 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 | ||
| 2056 | fn 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 | ||
| 2088 | fn 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 | ||
| 2100 | fn 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 | ||
| 2108 | fn 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); | |
| 1432 | 2134 | |
| 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, ")"); | |
| 1434 | 2146 | |
| 1435 | it = ZigClangEnumDecl_enumerator_begin(enum_def); | |
| 1436 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); | |
| 1437 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | |
| 1438 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | |
| 2147 | if (fn_ty) |ty| { | |
| 2148 | const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty)); | |
| 2149 | const ret_ty = ZigClangQualType_getTypePtr(canon); | |
| 2150 | if (ZigClangType_isVoidType(ret_ty)) { | |
| 2151 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2152 | return &node.base; | |
| 2153 | } | |
| 2154 | } | |
| 1439 | 2155 | |
| 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 | } | |
| 1441 | 2158 | |
| 1442 | const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) | |
| 1443 | enum_val_name[bare_name.len..] | |
| 1444 | else | |
| 1445 | enum_val_name; | |
| 2159 | fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType { | |
| 2160 | const canon = ZigClangQualType_getCanonicalType(qt); | |
| 2161 | var ty = ZigClangQualType_getTypePtr(canon); | |
| 2162 | is_ptr.* = false; | |
| 1446 | 2163 | |
| 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 | } | |
| 1448 | 2174 | |
| 1449 | const int_node = if (!pure_enum) blk: { | |
| 1450 | _ = try appendToken(c, .Colon, "="); | |
| 1451 | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | |
| 2175 | fn transUnaryExprOrTypeTraitExpr( | |
| 2176 | rp: RestorePoint, | |
| 2177 | scope: *Scope, | |
| 2178 | stmt: *const ZigClangUnaryExprOrTypeTraitExpr, | |
| 2179 | result_used: ResultUsed, | |
| 2180 | ) TransError!*ast.Node { | |
| 2181 | const type_node = try transQualType( | |
| 2182 | rp, | |
| 2183 | ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(stmt), | |
| 2184 | ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt), | |
| 2185 | ); | |
| 2186 | ||
| 2187 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf"); | |
| 2188 | try builtin_node.params.push(type_node); | |
| 2189 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2190 | return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); | |
| 2191 | } | |
| 2192 | ||
| 2193 | fn 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 | ||
| 2203 | fn 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 | 2248 | } 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 | } | |
| 1454 | 2267 | |
| 1455 | const field_node = try c.a().create(ast.Node.ContainerField); | |
| 1456 | field_node.* = .{ | |
| 1457 | .doc_comments = null, | |
| 1458 | .comptime_token = null, | |
| 1459 | .name_token = field_name_tok, | |
| 1460 | .type_expr = null, | |
| 1461 | .value_expr = int_node, | |
| 1462 | .align_expr = null, | |
| 1463 | }; | |
| 2268 | fn transCreatePreCrement( | |
| 2269 | rp: RestorePoint, | |
| 2270 | scope: *Scope, | |
| 2271 | stmt: *const ZigClangUnaryOperator, | |
| 2272 | op: ast.Node.InfixOp.Op, | |
| 2273 | op_tok_id: std.zig.Token.Id, | |
| 2274 | bytes: []const u8, | |
| 2275 | used: ResultUsed, | |
| 2276 | ) TransError!*ast.Node { | |
| 2277 | const op_expr = ZigClangUnaryOperator_getSubExpr(stmt); | |
| 2278 | ||
| 2279 | if (used == .unused) { | |
| 2280 | // common case | |
| 2281 | // c: ++expr | |
| 2282 | // zig: expr += 1 | |
| 2283 | const expr = try transExpr(rp, scope, op_expr, .used, .r_value); | |
| 2284 | const token = try appendToken(rp.c, op_tok_id, bytes); | |
| 2285 | const one = try transCreateNodeInt(rp.c, 1); | |
| 2286 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2287 | return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false); | |
| 2288 | } | |
| 2289 | // worst case | |
| 2290 | // c: ++expr | |
| 2291 | // zig: (blk: { | |
| 2292 | // zig: const _ref = &expr; | |
| 2293 | // zig: _ref.* += 1; | |
| 2294 | // zig: break :blk _ref.* | |
| 2295 | // zig: }) | |
| 2296 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | |
| 2297 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | |
| 2298 | const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); | |
| 2299 | ||
| 2300 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | |
| 2301 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 2302 | const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 2303 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | |
| 2304 | node.init_node = &rhs_node.base; | |
| 2305 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 2306 | try block_scope.block_node.statements.push(&node.base); | |
| 2307 | ||
| 2308 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | |
| 2309 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | |
| 2310 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2311 | const token = try appendToken(rp.c, op_tok_id, bytes); | |
| 2312 | const one = try transCreateNodeInt(rp.c, 1); | |
| 2313 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2314 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | |
| 2315 | try block_scope.block_node.statements.push(assign); | |
| 2316 | ||
| 2317 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | |
| 2318 | break_node.rhs = ref_node; | |
| 2319 | try block_scope.block_node.statements.push(&break_node.base); | |
| 2320 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 2321 | // semicolon must immediately follow rbrace because it is the last token in a block | |
| 2322 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2323 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | |
| 2324 | grouped_expr.* = .{ | |
| 2325 | .lparen = try appendToken(rp.c, .LParen, "("), | |
| 2326 | .expr = &block_scope.block_node.base, | |
| 2327 | .rparen = try appendToken(rp.c, .RParen, ")"), | |
| 2328 | }; | |
| 2329 | return &grouped_expr.base; | |
| 2330 | } | |
| 1464 | 2331 | |
| 1465 | try container_node.fields_and_decls.push(&field_node.base); | |
| 1466 | _ = try appendToken(c, .Comma, ","); | |
| 1467 | // In C each enum value is in the global namespace. So we put them there too. | |
| 1468 | // At this point we can rely on the enum emitting successfully. | |
| 1469 | try addEnumTopLevel(c, name, field_name, enum_val_name); | |
| 2332 | fn transCreatePostCrement( | |
| 2333 | rp: RestorePoint, | |
| 2334 | scope: *Scope, | |
| 2335 | stmt: *const ZigClangUnaryOperator, | |
| 2336 | op: ast.Node.InfixOp.Op, | |
| 2337 | op_tok_id: std.zig.Token.Id, | |
| 2338 | bytes: []const u8, | |
| 2339 | used: ResultUsed, | |
| 2340 | ) TransError!*ast.Node { | |
| 2341 | const op_expr = ZigClangUnaryOperator_getSubExpr(stmt); | |
| 2342 | ||
| 2343 | if (used == .unused) { | |
| 2344 | // common case | |
| 2345 | // c: ++expr | |
| 2346 | // zig: expr += 1 | |
| 2347 | const expr = try transExpr(rp, scope, op_expr, .used, .r_value); | |
| 2348 | const token = try appendToken(rp.c, op_tok_id, bytes); | |
| 2349 | const one = try transCreateNodeInt(rp.c, 1); | |
| 2350 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2351 | return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false); | |
| 2352 | } | |
| 2353 | // worst case | |
| 2354 | // c: expr++ | |
| 2355 | // zig: (blk: { | |
| 2356 | // zig: const _ref = &expr; | |
| 2357 | // zig: const _tmp = _ref.*; | |
| 2358 | // zig: _ref.* += 1; | |
| 2359 | // zig: break :blk _tmp | |
| 2360 | // zig: }) | |
| 2361 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | |
| 2362 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | |
| 2363 | const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); | |
| 2364 | ||
| 2365 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | |
| 2366 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 2367 | const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | |
| 2368 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | |
| 2369 | node.init_node = &rhs_node.base; | |
| 2370 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 2371 | try block_scope.block_node.statements.push(&node.base); | |
| 2372 | ||
| 2373 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | |
| 2374 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | |
| 2375 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2376 | ||
| 2377 | const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); | |
| 2378 | const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | |
| 2379 | tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 2380 | tmp_node.init_node = ref_node; | |
| 2381 | tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 2382 | try block_scope.block_node.statements.push(&tmp_node.base); | |
| 2383 | ||
| 2384 | const token = try appendToken(rp.c, op_tok_id, bytes); | |
| 2385 | const one = try transCreateNodeInt(rp.c, 1); | |
| 2386 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2387 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | |
| 2388 | try block_scope.block_node.statements.push(assign); | |
| 2389 | ||
| 2390 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | |
| 2391 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | |
| 2392 | try block_scope.block_node.statements.push(&break_node.base); | |
| 2393 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2394 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 2395 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | |
| 2396 | grouped_expr.* = .{ | |
| 2397 | .lparen = try appendToken(rp.c, .LParen, "("), | |
| 2398 | .expr = &block_scope.block_node.base, | |
| 2399 | .rparen = try appendToken(rp.c, .RParen, ")"), | |
| 2400 | }; | |
| 2401 | return &grouped_expr.base; | |
| 2402 | } | |
| 2403 | ||
| 2404 | fn 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 | ||
| 2433 | fn 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); | |
| 1472 | 2504 | |
| 1473 | break :blk &container_node.base; | |
| 1474 | } else | |
| 1475 | try transCreateNodeOpaqueType(c); | |
| 2505 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1476 | 2506 | |
| 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); | |
| 1478 | 2510 | |
| 1479 | const node = try c.a().create(ast.Node.VarDecl); | |
| 1480 | node.* = ast.Node.VarDecl{ | |
| 1481 | .visib_token = visib_tok, | |
| 1482 | .mut_token = const_tok, | |
| 1483 | .name_token = name_tok, | |
| 1484 | .eq_token = eq_tok, | |
| 1485 | .init_node = init_node, | |
| 1486 | .semicolon_token = semicolon_token, | |
| 1487 | .doc_comments = null, | |
| 1488 | .comptime_token = null, | |
| 1489 | .extern_export_token = null, | |
| 1490 | .thread_local_token = null, | |
| 1491 | .lib_name = null, | |
| 1492 | .type_node = null, | |
| 1493 | .align_node = null, | |
| 1494 | .section_node = null, | |
| 2511 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | |
| 2512 | break_node.rhs = ref_node; | |
| 2513 | try block_scope.block_node.statements.push(&break_node.base); | |
| 2514 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 2515 | // semicolon must immediately follow rbrace because it is the last token in a block | |
| 2516 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2517 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | |
| 2518 | grouped_expr.* = .{ | |
| 2519 | .lparen = try appendToken(rp.c, .LParen, "("), | |
| 2520 | .expr = &block_scope.block_node.base, | |
| 2521 | .rparen = try appendToken(rp.c, .RParen, ")"), | |
| 1495 | 2522 | }; |
| 2523 | return &grouped_expr.base; | |
| 2524 | } | |
| 1496 | 2525 | |
| 1497 | try addTopLevelDecl(c, name, &node.base); | |
| 1498 | if (!is_unnamed) | |
| 1499 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | |
| 1500 | return transCreateNodeIdentifier(c, name); | |
| 2526 | fn transCPtrCast( | |
| 2527 | rp: RestorePoint, | |
| 2528 | loc: ZigClangSourceLocation, | |
| 2529 | dst_type: ZigClangQualType, | |
| 2530 | src_type: ZigClangQualType, | |
| 2531 | expr: *ast.Node, | |
| 2532 | ) !*ast.Node { | |
| 2533 | const ty = ZigClangQualType_getTypePtr(dst_type); | |
| 2534 | const child_type = ZigClangType_getPointeeType(ty); | |
| 2535 | ||
| 2536 | // Implicit downcasting from higher to lower alignment values is forbidden, | |
| 2537 | // use @alignCast to side-step this problem | |
| 2538 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); | |
| 2539 | const dst_type_node = try transType(rp, ty, loc); | |
| 2540 | try ptrcast_node.params.push(dst_type_node); | |
| 2541 | _ = try appendToken(rp.c, .Comma, ","); | |
| 2542 | ||
| 2543 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { | |
| 2544 | // void has 1-byte alignment, so @alignCast is not needed | |
| 2545 | try ptrcast_node.params.push(expr); | |
| 2546 | } else { | |
| 2547 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); | |
| 2548 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); | |
| 2549 | const child_type_node = try transQualType(rp, child_type, loc); | |
| 2550 | try alignof_node.params.push(child_type_node); | |
| 2551 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2552 | try aligncast_node.params.push(&alignof_node.base); | |
| 2553 | _ = try appendToken(rp.c, .Comma, ","); | |
| 2554 | try aligncast_node.params.push(expr); | |
| 2555 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2556 | try ptrcast_node.params.push(&aligncast_node.base); | |
| 2557 | } | |
| 2558 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2559 | ||
| 2560 | return &ptrcast_node.base; | |
| 1501 | 2561 | } |
| 1502 | 2562 | |
| 1503 | fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { | |
| 1504 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 1505 | const const_tok = try appendToken(c, .Keyword_const, "const"); | |
| 1506 | const name_tok = try appendIdentifier(c, enum_val_name); | |
| 1507 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 2563 | fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { | |
| 2564 | const break_scope = scope.getBreakableScope(); | |
| 2565 | const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch) | |
| 2566 | "__switch" | |
| 2567 | else | |
| 2568 | null); | |
| 2569 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2570 | return &br.base; | |
| 2571 | } | |
| 1508 | 2572 | |
| 1509 | const enum_ident = try transCreateNodeIdentifier(c, enum_name); | |
| 1510 | const period_tok = try appendToken(c, .Period, "."); | |
| 1511 | const field_ident = try transCreateNodeIdentifier(c, field_name); | |
| 2573 | fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node { | |
| 2574 | // TODO use something more accurate | |
| 2575 | const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt); | |
| 2576 | const node = try rp.c.a().create(ast.Node.FloatLiteral); | |
| 2577 | node.* = .{ | |
| 2578 | .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}), | |
| 2579 | }; | |
| 2580 | return maybeSuppressResult(rp, scope, used, &node.base); | |
| 2581 | } | |
| 1512 | 2582 | |
| 1513 | const field_access_node = try c.a().create(ast.Node.InfixOp); | |
| 1514 | field_access_node.* = .{ | |
| 1515 | .op_token = period_tok, | |
| 1516 | .lhs = enum_ident, | |
| 1517 | .op = .Period, | |
| 1518 | .rhs = field_ident, | |
| 2583 | fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node { | |
| 2584 | const grouped = scope.id == .Condition; | |
| 2585 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; | |
| 2586 | const if_node = try transCreateNodeIf(rp.c); | |
| 2587 | var cond_scope = Scope{ | |
| 2588 | .parent = scope, | |
| 2589 | .id = .Condition, | |
| 1519 | 2590 | }; |
| 1520 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 1521 | 2591 | |
| 1522 | const node = try c.a().create(ast.Node.VarDecl); | |
| 1523 | node.* = ast.Node.VarDecl{ | |
| 1524 | .visib_token = visib_tok, | |
| 1525 | .mut_token = const_tok, | |
| 1526 | .name_token = name_tok, | |
| 1527 | .eq_token = eq_tok, | |
| 1528 | .init_node = &field_access_node.base, | |
| 1529 | .semicolon_token = semicolon_token, | |
| 1530 | .thread_local_token = null, | |
| 1531 | .doc_comments = null, | |
| 1532 | .comptime_token = null, | |
| 1533 | .extern_export_token = null, | |
| 1534 | .lib_name = null, | |
| 1535 | .type_node = null, | |
| 1536 | .align_node = null, | |
| 1537 | .section_node = null, | |
| 2592 | const cond_expr = ZigClangConditionalOperator_getCond(stmt); | |
| 2593 | const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt); | |
| 2594 | const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt); | |
| 2595 | ||
| 2596 | if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); | |
| 2597 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 2598 | ||
| 2599 | if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); | |
| 2600 | ||
| 2601 | if_node.@"else" = try transCreateNodeElse(rp.c); | |
| 2602 | if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value); | |
| 2603 | ||
| 2604 | if (grouped) { | |
| 2605 | const rparen = try appendToken(rp.c, .RParen, ")"); | |
| 2606 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | |
| 2607 | grouped_expr.* = .{ | |
| 2608 | .lparen = lparen, | |
| 2609 | .expr = &if_node.base, | |
| 2610 | .rparen = rparen, | |
| 2611 | }; | |
| 2612 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | |
| 2613 | } else { | |
| 2614 | return maybeSuppressResult(rp, scope, used, &if_node.base); | |
| 2615 | } | |
| 2616 | } | |
| 2617 | ||
| 2618 | fn 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 | } | |
| 1539 | 2646 | |
| 1540 | try addTopLevelDecl(c, field_name, &node.base); | |
| 2647 | fn 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 | ||
| 2652 | fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { | |
| 2653 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); | |
| 1541 | 2654 | } |
| 1542 | 2655 | |
| 1543 | 2656 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { |
| ... | ... | @@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool { |
| 1552 | 2665 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; |
| 1553 | 2666 | } |
| 1554 | 2667 | |
| 2668 | fn 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 | ||
| 2712 | fn 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 | ||
| 1555 | 2757 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { |
| 1556 | 2758 | const ty = ZigClangQualType_getTypePtr(qt); |
| 1557 | 2759 | |
| ... | ... | @@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { |
| 1601 | 2803 | return ZigClangExpr_getType(expr); |
| 1602 | 2804 | } |
| 1603 | 2805 | |
| 2806 | fn 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 | ||
| 1604 | 2814 | fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { |
| 1605 | 2815 | switch (ZigClangType_getTypeClass(ty)) { |
| 1606 | 2816 | .Builtin => { |
| ... | ... | @@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool { |
| 1657 | 2867 | }; |
| 1658 | 2868 | } |
| 1659 | 2869 | |
| 2870 | fn 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 | ||
| 2887 | fn 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 | ||
| 1660 | 2901 | fn transCreateNodeAssign( |
| 1661 | 2902 | rp: RestorePoint, |
| 1662 | 2903 | scope: *Scope, |
| 1663 | 2904 | result_used: ResultUsed, |
| 1664 | 2905 | lhs: *const ZigClangExpr, |
| 1665 | 2906 | rhs: *const ZigClangExpr, |
| 1666 | ) !*ast.Node.InfixOp { | |
| 2907 | ) !*ast.Node { | |
| 1667 | 2908 | // common case |
| 1668 | 2909 | // c: lhs = rhs |
| 1669 | 2910 | // zig: lhs = rhs |
| 1670 | 2911 | if (result_used == .unused) { |
| 1671 | 2912 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 1672 | 2913 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 1673 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | |
| 1674 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 1675 | ||
| 1676 | const node = try rp.c.a().create(ast.Node.InfixOp); | |
| 1677 | node.* = .{ | |
| 1678 | .op_token = eq_token, | |
| 1679 | .lhs = lhs_node, | |
| 1680 | .op = .Assign, | |
| 1681 | .rhs = rhs_node, | |
| 1682 | }; | |
| 1683 | return node; | |
| 2914 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | |
| 2915 | if (isBoolRes(rhs_node)) { | |
| 2916 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | |
| 2917 | try builtin_node.params.push(rhs_node); | |
| 2918 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2919 | rhs_node = &builtin_node.base; | |
| 2920 | } | |
| 2921 | if (scope.id != .Condition) | |
| 2922 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2923 | return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false); | |
| 1684 | 2924 | } |
| 1685 | 2925 | |
| 1686 | 2926 | // worst case |
| 1687 | 2927 | // c: lhs = rhs |
| 1688 | // zig: (x: { | |
| 2928 | // zig: (blk: { | |
| 1689 | 2929 | // zig: const _tmp = rhs; |
| 1690 | 2930 | // zig: lhs = _tmp; |
| 1691 | // zig: break :x _tmp | |
| 2931 | // zig: break :blk _tmp | |
| 1692 | 2932 | // zig: }) |
| 1693 | return revertAndWarn( | |
| 1694 | rp, | |
| 1695 | error.UnsupportedTranslation, | |
| 1696 | ZigClangExpr_getBeginLoc(lhs), | |
| 1697 | "TODO: worst case assign op expr", | |
| 1698 | .{}, | |
| 1699 | ); | |
| 2933 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | |
| 2934 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | |
| 2935 | const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); | |
| 2936 | ||
| 2937 | const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | |
| 2938 | node.eq_token = try appendToken(rp.c, .Equal, "="); | |
| 2939 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | |
| 2940 | if (isBoolRes(rhs_node)) { | |
| 2941 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | |
| 2942 | try builtin_node.params.push(rhs_node); | |
| 2943 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | |
| 2944 | rhs_node = &builtin_node.base; | |
| 2945 | } | |
| 2946 | node.init_node = rhs_node; | |
| 2947 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | |
| 2948 | try block_scope.block_node.statements.push(&node.base); | |
| 2949 | ||
| 2950 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | |
| 2951 | const eq_token = try appendToken(rp.c, .Equal, "="); | |
| 2952 | const ident = try transCreateNodeIdentifier(rp.c, tmp); | |
| 2953 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2954 | ||
| 2955 | const assign = try transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, ident, .used, false); | |
| 2956 | try block_scope.block_node.statements.push(assign); | |
| 2957 | ||
| 2958 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | |
| 2959 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | |
| 2960 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2961 | try block_scope.block_node.statements.push(&break_node.base); | |
| 2962 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | |
| 2963 | // semicolon must immediately follow rbrace because it is the last token in a block | |
| 2964 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2965 | return &block_scope.block_node.base; | |
| 1700 | 2966 | } |
| 1701 | 2967 | |
| 1702 | 2968 | fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { |
| 1703 | 2969 | const builtin_token = try appendToken(c, .Builtin, name); |
| 1704 | 2970 | _ = try appendToken(c, .LParen, "("); |
| 1705 | 2971 | const node = try c.a().create(ast.Node.BuiltinCall); |
| 1706 | node.* = ast.Node.BuiltinCall{ | |
| 2972 | node.* = .{ | |
| 1707 | 2973 | .builtin_token = builtin_token, |
| 1708 | 2974 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), |
| 1709 | 2975 | .rparen_token = undefined, // set after appending args |
| ... | ... | @@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti |
| 1714 | 2980 | fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1715 | 2981 | _ = try appendToken(c, .LParen, "("); |
| 1716 | 2982 | const node = try c.a().create(ast.Node.SuffixOp); |
| 1717 | node.* = ast.Node.SuffixOp{ | |
| 2983 | node.* = .{ | |
| 1718 | 2984 | .lhs = .{ .node = fn_expr }, |
| 1719 | .op = ast.Node.SuffixOp.Op{ | |
| 1720 | .Call = ast.Node.SuffixOp.Op.Call{ | |
| 2985 | .op = .{ | |
| 2986 | .Call = .{ | |
| 1721 | 2987 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), |
| 1722 | 2988 | .async_token = null, |
| 1723 | 2989 | }, |
| ... | ... | @@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1727 | 2993 | return node; |
| 1728 | 2994 | } |
| 1729 | 2995 | |
| 2996 | fn 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 | ||
| 1730 | 3007 | fn transCreateNodePrefixOp( |
| 1731 | 3008 | c: *Context, |
| 1732 | 3009 | op: ast.Node.PrefixOp.Op, |
| ... | ... | @@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp( |
| 1745 | 3022 | fn transCreateNodeInfixOp( |
| 1746 | 3023 | rp: RestorePoint, |
| 1747 | 3024 | scope: *Scope, |
| 1748 | stmt: *const ZigClangBinaryOperator, | |
| 3025 | lhs_node: *ast.Node, | |
| 1749 | 3026 | op: ast.Node.InfixOp.Op, |
| 1750 | op_tok_id: std.zig.Token.Id, | |
| 1751 | bytes: []const u8, | |
| 3027 | op_token: ast.TokenIndex, | |
| 3028 | rhs_node: *ast.Node, | |
| 3029 | used: ResultUsed, | |
| 1752 | 3030 | grouped: bool, |
| 1753 | 3031 | ) !*ast.Node { |
| 1754 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; | |
| 1755 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | |
| 1756 | const op_token = try appendToken(rp.c, op_tok_id, bytes); | |
| 1757 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | |
| 3032 | var lparen = if (grouped) | |
| 3033 | try appendToken(rp.c, .LParen, "(") | |
| 3034 | else | |
| 3035 | null; | |
| 1758 | 3036 | const node = try rp.c.a().create(ast.Node.InfixOp); |
| 1759 | node.* = ast.Node.InfixOp{ | |
| 3037 | node.* = .{ | |
| 1760 | 3038 | .op_token = op_token, |
| 1761 | .lhs = lhs, | |
| 3039 | .lhs = lhs_node, | |
| 1762 | 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 | 3044 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1767 | 3045 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 1768 | grouped_expr.* = ast.Node.GroupedExpression{ | |
| 1769 | .lparen = lparen, | |
| 3046 | grouped_expr.* = .{ | |
| 3047 | .lparen = lparen.?, | |
| 1770 | 3048 | .expr = &node.base, |
| 1771 | 3049 | .rparen = rparen, |
| 1772 | 3050 | }; |
| 1773 | return &grouped_expr.base; | |
| 3051 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | |
| 3052 | } | |
| 3053 | ||
| 3054 | fn 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 | } |
| 1775 | 3082 | |
| 1776 | 3083 | fn transCreateNodePtrType( |
| ... | ... | @@ -1797,9 +3104,9 @@ fn transCreateNodePtrType( |
| 1797 | 3104 | .Asterisk => try appendToken(c, .Asterisk, "*"), |
| 1798 | 3105 | else => unreachable, |
| 1799 | 3106 | }; |
| 1800 | node.* = ast.Node.PrefixOp{ | |
| 3107 | node.* = .{ | |
| 1801 | 3108 | .op_token = op_token, |
| 1802 | .op = ast.Node.PrefixOp.Op{ | |
| 3109 | .op = .{ | |
| 1803 | 3110 | .PtrType = .{ |
| 1804 | 3111 | .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, |
| 1805 | 3112 | .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, |
| ... | ... | @@ -1810,11 +3117,17 @@ fn transCreateNodePtrType( |
| 1810 | 3117 | return node; |
| 1811 | 3118 | } |
| 1812 | 3119 | |
| 1813 | fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { | |
| 1814 | const num_limbs = ZigClangAPSInt_getNumWords(int.?); | |
| 3120 | fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { | |
| 3121 | const num_limbs = ZigClangAPSInt_getNumWords(int); | |
| 3122 | var aps_int = int; | |
| 3123 | const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int); | |
| 3124 | if (is_negative) | |
| 3125 | aps_int = ZigClangAPSInt_negate(aps_int); | |
| 1815 | 3126 | var big = try std.math.big.Int.initCapacity(c.a(), num_limbs); |
| 3127 | if (is_negative) | |
| 3128 | big.negate(); | |
| 1816 | 3129 | defer big.deinit(); |
| 1817 | const data = ZigClangAPSInt_getRawData(int.?); | |
| 3130 | const data = ZigClangAPSInt_getRawData(aps_int); | |
| 1818 | 3131 | var i: @TypeOf(num_limbs) = 0; |
| 1819 | 3132 | while (i < num_limbs) : (i += 1) big.limbs[i] = data[i]; |
| 1820 | 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 | 3136 | }; |
| 1824 | 3137 | const token = try appendToken(c, .IntegerLiteral, str); |
| 1825 | 3138 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| 1826 | node.* = ast.Node.IntegerLiteral{ | |
| 3139 | node.* = .{ | |
| 1827 | 3140 | .token = token, |
| 1828 | 3141 | }; |
| 3142 | if (is_negative) | |
| 3143 | ZigClangAPSInt_free(aps_int); | |
| 1829 | 3144 | return &node.base; |
| 1830 | 3145 | } |
| 1831 | 3146 | |
| 1832 | 3147 | fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 1833 | 3148 | const ltoken = try appendToken(c, .Keyword_return, "return"); |
| 1834 | 3149 | const node = try c.a().create(ast.Node.ControlFlowExpression); |
| 1835 | node.* = ast.Node.ControlFlowExpression{ | |
| 3150 | node.* = .{ | |
| 1836 | 3151 | .ltoken = ltoken, |
| 1837 | 3152 | .kind = .Return, |
| 1838 | 3153 | .rhs = null, |
| ... | ... | @@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 1843 | 3158 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 1844 | 3159 | const token = try appendToken(c, .Keyword_undefined, "undefined"); |
| 1845 | 3160 | const node = try c.a().create(ast.Node.UndefinedLiteral); |
| 1846 | node.* = ast.Node.UndefinedLiteral{ | |
| 3161 | node.* = .{ | |
| 1847 | 3162 | .token = token, |
| 1848 | 3163 | }; |
| 1849 | 3164 | return &node.base; |
| ... | ... | @@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 1852 | 3167 | fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { |
| 1853 | 3168 | const token = try appendToken(c, .Keyword_null, "null"); |
| 1854 | 3169 | const node = try c.a().create(ast.Node.NullLiteral); |
| 1855 | node.* = ast.Node.NullLiteral{ | |
| 3170 | node.* = .{ | |
| 1856 | 3171 | .token = token, |
| 1857 | 3172 | }; |
| 1858 | 3173 | return &node.base; |
| ... | ... | @@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { |
| 1864 | 3179 | else |
| 1865 | 3180 | try appendToken(c, .Keyword_false, "false"); |
| 1866 | 3181 | const node = try c.a().create(ast.Node.BoolLiteral); |
| 1867 | node.* = ast.Node.BoolLiteral{ | |
| 3182 | node.* = .{ | |
| 1868 | 3183 | .token = token, |
| 1869 | 3184 | }; |
| 1870 | 3185 | return &node.base; |
| 1871 | 3186 | } |
| 1872 | 3187 | |
| 1873 | fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp { | |
| 3188 | fn transCreateNodeContainerInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp { | |
| 1874 | 3189 | _ = try appendToken(c, .LBrace, "{"); |
| 1875 | 3190 | const node = try c.a().create(ast.Node.SuffixOp); |
| 1876 | 3191 | node.* = ast.Node.SuffixOp{ |
| ... | ... | @@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N |
| 1886 | 3201 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 1887 | 3202 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); |
| 1888 | 3203 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| 1889 | node.* = ast.Node.IntegerLiteral{ | |
| 3204 | node.* = .{ | |
| 1890 | 3205 | .token = token, |
| 1891 | 3206 | }; |
| 1892 | 3207 | return &node.base; |
| ... | ... | @@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { |
| 1907 | 3222 | return &call_node.base; |
| 1908 | 3223 | } |
| 1909 | 3224 | |
| 1910 | fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias_node: *ast.Node) !*ast.Node { | |
| 3225 | fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node { | |
| 1911 | 3226 | const scope = &c.global_scope.base; |
| 1912 | 3227 | |
| 1913 | 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 | 3231 | const name_tok = try appendIdentifier(c, name); |
| 1917 | 3232 | _ = try appendToken(c, .LParen, "("); |
| 1918 | 3233 | |
| 1919 | const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?; | |
| 1920 | ||
| 1921 | 3234 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); |
| 1922 | 3235 | var it = proto_alias.params.iterator(0); |
| 1923 | 3236 | while (it.next()) |pn| { |
| ... | ... | @@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { |
| 2046 | 3359 | return block_node; |
| 2047 | 3360 | } |
| 2048 | 3361 | |
| 3362 | fn 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 | ||
| 3377 | fn 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 | ||
| 3402 | fn 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 | ||
| 3420 | fn 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 | ||
| 3432 | fn 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 | ||
| 3446 | fn 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 | ||
| 3460 | fn 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 | ||
| 3468 | fn 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 | ||
| 3505 | fn 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 | ||
| 3515 | fn 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 | ||
| 2049 | 3528 | const RestorePoint = struct { |
| 2050 | 3529 | c: *Context, |
| 2051 | 3530 | token_index: ast.TokenIndex, |
| ... | ... | @@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2092 | 3571 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2093 | 3572 | }); |
| 2094 | 3573 | }, |
| 2095 | .FunctionProto => { | |
| 3574 | .FunctionProto, .FunctionNoProto => { | |
| 2096 | 3575 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 2097 | 3576 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); |
| 2098 | 3577 | return &fn_proto.base; |
| ... | ... | @@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2167 | 3646 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 2168 | 3647 | |
| 2169 | 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))); | |
| 2171 | return transCreateNodeIdentifier(rp.c, typedef_name); | |
| 3649 | return (try transTypeDef(rp.c, typedef_decl)) orelse | |
| 3650 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); | |
| 2172 | 3651 | }, |
| 2173 | 3652 | .Record => { |
| 2174 | 3653 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| 2175 | 3654 | |
| 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 | 3655 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 2184 | if (try getContainerName(rp, record_decl)) |name| | |
| 2185 | return transCreateNodeIdentifier(rp.c, name) | |
| 2186 | else | |
| 2187 | return transRecordDecl(rp.c, record_decl); | |
| 3656 | return (try transRecordDecl(rp.c, record_decl)) orelse | |
| 3657 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); | |
| 2188 | 3658 | }, |
| 2189 | 3659 | .Enum => { |
| 2190 | 3660 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); |
| ... | ... | @@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2205 | 3675 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); |
| 2206 | 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 | 3682 | else => { |
| 2209 | 3683 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 2210 | 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 | 3686 | } |
| 2213 | 3687 | } |
| 2214 | 3688 | |
| 2215 | fn 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 | ||
| 2231 | 3689 | fn isCVoid(qt: ZigClangQualType) bool { |
| 2232 | 3690 | const ty = ZigClangQualType_getTypePtr(qt); |
| 2233 | 3691 | if (ZigClangType_getTypeClass(ty) == .Builtin) { |
| ... | ... | @@ -2241,7 +3699,6 @@ const FnDeclContext = struct { |
| 2241 | 3699 | fn_name: []const u8, |
| 2242 | 3700 | has_body: bool, |
| 2243 | 3701 | storage_class: ZigClangStorageClass, |
| 2244 | scope: **Scope, | |
| 2245 | 3702 | is_export: bool, |
| 2246 | 3703 | }; |
| 2247 | 3704 | |
| ... | ... | @@ -2307,9 +3764,6 @@ fn finishTransFnProto( |
| 2307 | 3764 | // TODO check for always_inline attribute |
| 2308 | 3765 | // TODO check for align attribute |
| 2309 | 3766 | |
| 2310 | var fndef_scope = Scope.FnDef.init(rp.c); | |
| 2311 | const scope = &fndef_scope.base; | |
| 2312 | ||
| 2313 | 3767 | // pub extern fn name(...) T |
| 2314 | 3768 | const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; |
| 2315 | 3769 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; |
| ... | ... | @@ -2335,15 +3789,11 @@ fn finishTransFnProto( |
| 2335 | 3789 | const param_name_tok: ?ast.TokenIndex = blk: { |
| 2336 | 3790 | if (fn_decl != null) { |
| 2337 | 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 | 3793 | if (param_name.len < 1) |
| 2340 | param_name = "arg"[0..]; | |
| 2341 | const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: { | |
| 2342 | try fndef_scope.params.push(.{ .name = param_name, .alias = a }); | |
| 2343 | break :blk a; | |
| 2344 | } else param_name; | |
| 3794 | break :blk null; | |
| 2345 | 3795 | |
| 2346 | const result = try appendIdentifier(rp.c, checked_param_name); | |
| 3796 | const result = try appendIdentifier(rp.c, param_name); | |
| 2347 | 3797 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2348 | 3798 | break :blk result; |
| 2349 | 3799 | } |
| ... | ... | @@ -2410,14 +3860,13 @@ fn finishTransFnProto( |
| 2410 | 3860 | }; |
| 2411 | 3861 | |
| 2412 | 3862 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); |
| 2413 | fn_proto.* = ast.Node.FnProto{ | |
| 2414 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | |
| 3863 | fn_proto.* = .{ | |
| 2415 | 3864 | .doc_comments = null, |
| 2416 | 3865 | .visib_token = pub_tok, |
| 2417 | 3866 | .fn_token = fn_tok, |
| 2418 | 3867 | .name_token = name_tok, |
| 2419 | 3868 | .params = fn_params, |
| 2420 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, | |
| 3869 | .return_type = .{ .Explicit = return_type_node }, | |
| 2421 | 3870 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 2422 | 3871 | .extern_export_inline_token = extern_export_inline_tok, |
| 2423 | 3872 | .cc_token = cc_tok, |
| ... | ... | @@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, |
| 2523 | 3972 | return token_index; |
| 2524 | 3973 | } |
| 2525 | 3974 | |
| 3975 | // TODO hook up with codegen | |
| 3976 | fn 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 | ||
| 2526 | 4010 | fn isValidZigIdentifier(name: []const u8) bool { |
| 2527 | 4011 | for (name) |c, i| { |
| 2528 | 4012 | switch (c) { |
| ... | ... | @@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2573 | 4057 | const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); |
| 2574 | 4058 | |
| 2575 | 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 | 4065 | continue; |
| 2578 | 4066 | } |
| 2579 | 4067 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); |
| 2580 | 4068 | ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { |
| 2581 | 4069 | error.OutOfMemory => |e| return e, |
| 2582 | 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 | 4072 | continue; |
| 2585 | 4073 | }, |
| 2586 | 4074 | }; |
| 2587 | 4075 | |
| 2588 | 4076 | var tok_it = tok_list.iterator(0); |
| 2589 | 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 | 4079 | const next = tok_it.peek().?; |
| 2592 | 4080 | switch (next.id) { |
| 2593 | 4081 | .Identifier => { |
| 2594 | 4082 | // if it equals itself, ignore. for example, from stdio.h: |
| 2595 | 4083 | // #define stdin stdin |
| 2596 | if (std.mem.eql(u8, name, next.bytes)) { | |
| 4084 | if (mem.eql(u8, checked_name, next.bytes)) { | |
| 2597 | 4085 | continue; |
| 2598 | 4086 | } |
| 2599 | 4087 | }, |
| ... | ... | @@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2610 | 4098 | } else false; |
| 2611 | 4099 | |
| 2612 | 4100 | (if (macro_fn) |
| 2613 | transMacroFnDefine(c, &tok_it, name, begin_loc) | |
| 4101 | transMacroFnDefine(c, &tok_it, checked_name, begin_loc) | |
| 2614 | 4102 | 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 | 4104 | error.UnsupportedTranslation, |
| 2617 | 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 | 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 | 4116 | const rp = makeRestorePoint(c); |
| 2629 | 4117 | const scope = &c.global_scope.base; |
| 2630 | 4118 | |
| 2631 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | |
| 2632 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | |
| 2633 | const name_tok = try appendIdentifier(c, name); | |
| 2634 | const eq_tok = try appendToken(c, .Equal, "="); | |
| 4119 | const node = try transCreateNodeVarDecl(c, true, true, name); | |
| 4120 | node.eq_token = try appendToken(c, .Equal, "="); | |
| 2635 | 4121 | |
| 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 | ); | |
| 2637 | 4132 | |
| 2638 | const node = try c.a().create(ast.Node.VarDecl); | |
| 2639 | node.* = ast.Node.VarDecl{ | |
| 2640 | .doc_comments = null, | |
| 2641 | .visib_token = visib_tok, | |
| 2642 | .thread_local_token = null, | |
| 2643 | .name_token = name_tok, | |
| 2644 | .eq_token = eq_tok, | |
| 2645 | .mut_token = mut_tok, | |
| 2646 | .comptime_token = null, | |
| 2647 | .extern_export_token = null, | |
| 2648 | .lib_name = null, | |
| 2649 | .type_node = null, | |
| 2650 | .align_node = null, | |
| 2651 | .section_node = null, | |
| 2652 | .init_node = init_node, | |
| 2653 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | |
| 2654 | }; | |
| 4133 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 2655 | 4134 | _ = try c.global_scope.macro_table.put(name, &node.base); |
| 2656 | 4135 | } |
| 2657 | 4136 | |
| 2658 | 4137 | fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 2659 | 4138 | const rp = makeRestorePoint(c); |
| 2660 | var fndef_scope = Scope.FnDef.init(c); | |
| 2661 | const scope = &fndef_scope.base; | |
| 4139 | const block_scope = try Scope.Block.init(c, &c.global_scope.base, null); | |
| 4140 | const scope = &block_scope.base; | |
| 2662 | 4141 | |
| 2663 | 4142 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 2664 | 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 | 4155 | return error.ParseError; |
| 2677 | 4156 | |
| 2678 | 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 | 4159 | break :blk alias; |
| 2681 | 4160 | } else param_tok.bytes; |
| 2682 | 4161 | |
| ... | ... | @@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u |
| 2737 | 4216 | |
| 2738 | 4217 | const return_expr = try transCreateNodeReturnExpr(c); |
| 2739 | 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 | 4228 | _ = try appendToken(c, .Semicolon, ";"); |
| 2741 | 4229 | try type_of.params.push(expr); |
| 2742 | 4230 | return_expr.rhs = expr; |
| ... | ... | @@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: |
| 2838 | 4326 | |
| 2839 | 4327 | if (it.peek().?.id == .RParen) { |
| 2840 | 4328 | _ = it.next(); |
| 2841 | return inner_node; | |
| 4329 | if (it.peek().?.id != .LParen) { | |
| 4330 | return inner_node; | |
| 4331 | } | |
| 4332 | _ = it.next(); | |
| 2842 | 4333 | } |
| 2843 | 4334 | |
| 2844 | 4335 | // 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 | 4421 | rp, |
| 2931 | 4422 | error.UnsupportedTranslation, |
| 2932 | 4423 | source_loc, |
| 2933 | "unable to translate C expr", | |
| 2934 | .{}, | |
| 4424 | "unable to translate C expr, unexpected token: {}", | |
| 4425 | .{tok.id}, | |
| 2935 | 4426 | ), |
| 2936 | 4427 | } |
| 2937 | 4428 | } |
| ... | ... | @@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2944 | 4435 | .Dot => { |
| 2945 | 4436 | const name_tok = it.next().?; |
| 2946 | 4437 | if (name_tok.id != .Identifier) |
| 2947 | return revertAndWarn( | |
| 2948 | rp, | |
| 2949 | error.ParseError, | |
| 2950 | source_loc, | |
| 2951 | "unable to translate C expr", | |
| 2952 | .{}, | |
| 2953 | ); | |
| 2954 | ||
| 2955 | const op_token = try appendToken(rp.c, .Period, "."); | |
| 2956 | const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); | |
| 2957 | const access_node = try rp.c.a().create(ast.Node.InfixOp); | |
| 2958 | access_node.* = .{ | |
| 2959 | .op_token = op_token, | |
| 2960 | .lhs = node, | |
| 2961 | .op = .Period, | |
| 2962 | .rhs = rhs, | |
| 2963 | }; | |
| 2964 | node = &access_node.base; | |
| 4438 | return error.ParseError; | |
| 4439 | ||
| 4440 | node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes); | |
| 4441 | }, | |
| 4442 | .Arrow => { | |
| 4443 | const name_tok = it.next().?; | |
| 4444 | if (name_tok.id != .Identifier) | |
| 4445 | return error.ParseError; | |
| 4446 | ||
| 4447 | const deref = try transCreateNodePtrDeref(rp.c, node); | |
| 4448 | node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes); | |
| 2965 | 4449 | }, |
| 2966 | 4450 | .Asterisk => { |
| 2967 | 4451 | if (it.peek().?.id == .RParen) { |
| ... | ... | @@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2977 | 4461 | // expr * expr |
| 2978 | 4462 | const op_token = try appendToken(rp.c, .Asterisk, "*"); |
| 2979 | 4463 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); |
| 2980 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); | |
| 2981 | bitshift_node.* = .{ | |
| 4464 | const mul_node = try rp.c.a().create(ast.Node.InfixOp); | |
| 4465 | mul_node.* = .{ | |
| 2982 | 4466 | .op_token = op_token, |
| 2983 | 4467 | .lhs = node, |
| 2984 | 4468 | .op = .BitShiftLeft, |
| 2985 | 4469 | .rhs = rhs, |
| 2986 | 4470 | }; |
| 2987 | node = &bitshift_node.base; | |
| 4471 | node = &mul_node.base; | |
| 2988 | 4472 | } |
| 2989 | 4473 | }, |
| 2990 | 4474 | .Shl => { |
| 2991 | 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 | 4477 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); |
| 2994 | 4478 | bitshift_node.* = .{ |
| 2995 | 4479 | .op_token = op_token, |
| ... | ... | @@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2999 | 4483 | }; |
| 3000 | 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 | 4522 | else => { |
| 3003 | 4523 | _ = it.prev(); |
| 3004 | 4524 | return node; |
| ... | ... | @@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3028 | 4548 | }, |
| 3029 | 4549 | .Asterisk => { |
| 3030 | 4550 | const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); |
| 3031 | const node = try rp.c.a().create(ast.Node.SuffixOp); | |
| 3032 | node.* = .{ | |
| 3033 | .lhs = .{ .node = prefix_op_expr }, | |
| 3034 | .op = .Deref, | |
| 3035 | .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"), | |
| 3036 | }; | |
| 3037 | return &node.base; | |
| 4551 | return try transCreateNodePtrDeref(rp.c, prefix_op_expr); | |
| 3038 | 4552 | }, |
| 3039 | 4553 | else => { |
| 3040 | 4554 | _ = it.prev(); |
| ... | ... | @@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3043 | 4557 | } |
| 3044 | 4558 | } |
| 3045 | 4559 | |
| 3046 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { | |
| 4560 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { | |
| 3047 | 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 | } |
| 3050 | 4564 | |
| 3051 | fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { | |
| 3052 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; | |
| 3053 | const name = if (init.cast(ast.Node.Identifier)) |id| | |
| 3054 | tokenSlice(c, id.token) | |
| 3055 | else | |
| 3056 | return null; | |
| 3057 | // TODO a.b.c | |
| 3058 | if (c.global_scope.sym_table.get(name)) |kv| { | |
| 3059 | if (kv.value.cast(ast.Node.VarDecl)) |val| { | |
| 3060 | if (val.type_node) |type_node| { | |
| 3061 | if (type_node.cast(ast.Node.PrefixOp)) |casted| { | |
| 3062 | if (casted.rhs.id == .FnProto) { | |
| 3063 | return casted.rhs; | |
| 4565 | fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { | |
| 4566 | if (node.id == .ContainerDecl) { | |
| 4567 | return node; | |
| 4568 | } else if (node.id == .PrefixOp) { | |
| 4569 | return node; | |
| 4570 | } else if (node.cast(ast.Node.Identifier)) |ident| { | |
| 4571 | if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| { | |
| 4572 | if (kv.value.cast(ast.Node.VarDecl)) |var_decl| | |
| 4573 | return getContainer(c, var_decl.init_node.?); | |
| 4574 | } | |
| 4575 | } else if (node.cast(ast.Node.InfixOp)) |infix| { | |
| 4576 | if (infix.op != .Period) | |
| 4577 | return null; | |
| 4578 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { | |
| 4579 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { | |
| 4580 | var it = container.fields_and_decls.iterator(0); | |
| 4581 | while (it.next()) |field_ref| { | |
| 4582 | const field = field_ref.*.cast(ast.Node.ContainerField).?; | |
| 4583 | const ident = infix.rhs.cast(ast.Node.Identifier).?; | |
| 4584 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { | |
| 4585 | return getContainer(c, field.type_expr.?); | |
| 4586 | } | |
| 4587 | } | |
| 4588 | } | |
| 4589 | } | |
| 4590 | } | |
| 4591 | return null; | |
| 4592 | } | |
| 4593 | ||
| 4594 | fn 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 | ||
| 4622 | fn 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 | 4636 | fn addMacros(c: *Context) !void { |
| 3073 | 4637 | var macro_it = c.global_scope.macro_table.iterator(); |
| 3074 | 4638 | while (macro_it.next()) |kv| { |
| 3075 | if (getFnDecl(c, kv.value)) |proto_node| { | |
| 4639 | if (getFnProto(c, kv.value)) |proto_node| { | |
| 3076 | 4640 | // If a macro aliases a global variable which is a function pointer, we conclude that |
| 3077 | 4641 | // the macro is intended to represent a function that assumes the function pointer |
| 3078 | 4642 | // variable is non-null and calls it. |
src/zig_clang.cpp+15| ... | ... | @@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi |
| 1571 | 1571 | return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl); |
| 1572 | 1572 | } |
| 1573 | 1573 | |
| 1574 | const 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 | ||
| 1579 | const 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 | ||
| 1574 | 1584 | const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) { |
| 1575 | 1585 | const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); |
| 1576 | 1586 | const clang::RecordDecl *definition = record_decl->getDefinition(); |
| ... | ... | @@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D |
| 2161 | 2171 | return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM); |
| 2162 | 2172 | } |
| 2163 | 2173 | |
| 2174 | double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self) { | |
| 2175 | auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self); | |
| 2176 | return casted->getValueAsApproximateDouble(); | |
| 2177 | } | |
| 2178 | ||
| 2164 | 2179 | enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { |
| 2165 | 2180 | auto casted = reinterpret_cast<const clang::StringLiteral *>(self); |
| 2166 | 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 | 856 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl); |
| 857 | 857 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *); |
| 858 | 858 | ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *); |
| 859 | ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self); | |
| 860 | ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self); | |
| 859 | 861 | |
| 860 | 862 | ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *); |
| 861 | 863 | ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *); |
| ... | ... | @@ -985,6 +987,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st |
| 985 | 987 | |
| 986 | 988 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, |
| 987 | 989 | unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); |
| 990 | ZIG_EXTERN_C double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); | |
| 988 | 991 | |
| 989 | 992 | ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); |
| 990 | 993 | ZIG_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 | 127 | }); |
| 128 | 128 | |
| 129 | 129 | cases.addC_both("add, sub, mul, div, rem", |
| 130 | \\int s(int a, int b) { | |
| 131 | \\ int c; | |
| 130 | \\int s() { | |
| 131 | \\ int a, b, c; | |
| 132 | 132 | \\ c = a + b; |
| 133 | 133 | \\ c = a - b; |
| 134 | 134 | \\ c = a * b; |
| 135 | 135 | \\ c = a / b; |
| 136 | 136 | \\ c = a % b; |
| 137 | 137 | \\} |
| 138 | \\unsigned u(unsigned a, unsigned b) { | |
| 139 | \\ unsigned c; | |
| 138 | \\unsigned u() { | |
| 139 | \\ unsigned a, b, c; | |
| 140 | 140 | \\ c = a + b; |
| 141 | 141 | \\ c = a - b; |
| 142 | 142 | \\ c = a * b; |
| ... | ... | @@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 144 | 144 | \\ c = a % b; |
| 145 | 145 | \\} |
| 146 | 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 | 150 | \\ var c: c_int = undefined; |
| 149 | 151 | \\ c = (a + b); |
| 150 | 152 | \\ c = (a - b); |
| ... | ... | @@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 152 | 154 | \\ c = @divTrunc(a, b); |
| 153 | 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 | 160 | \\ var c: c_uint = undefined; |
| 157 | 161 | \\ c = (a +% b); |
| 158 | 162 | \\ c = (a -% b); |
| ... | ... | @@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 162 | 166 | \\} |
| 163 | 167 | }); |
| 164 | 168 | |
| 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 | 169 | cases.add_both("typedef of function in struct field", |
| 210 | 170 | \\typedef void lws_callback_function(void); |
| 211 | 171 | \\struct Foo { |
| ... | ... | @@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 228 | 188 | \\ struct Foo *foo; |
| 229 | 189 | \\}; |
| 230 | 190 | , &[_][]const u8{ |
| 231 | \\pub const struct_Foo = @OpaqueType() | |
| 191 | \\pub const struct_Foo = @OpaqueType(); | |
| 232 | 192 | , |
| 233 | 193 | \\pub const struct_Bar = extern struct { |
| 234 | 194 | \\ foo: ?*struct_Foo, |
| ... | ... | @@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 426 | 386 | }, |
| 427 | 387 | ); |
| 428 | 388 | |
| 429 | /////////////// Cases that pass for only stage2 //////////////// | |
| 430 | ||
| 431 | cases.add_2("Parameterless function prototypes", | |
| 432 | \\void a() {} | |
| 433 | \\void b(void) {} | |
| 434 | \\void c(); | |
| 435 | \\void d(void); | |
| 389 | cases.addC_both("null statements", | |
| 390 | \\void foo(void) { | |
| 391 | \\ ;;;;; | |
| 392 | \\} | |
| 436 | 393 | , &[_][]const u8{ |
| 437 | \\pub export fn a() void {} | |
| 438 | \\pub export fn b() void {} | |
| 439 | \\pub extern fn c(...) void; | |
| 440 | \\pub extern fn d() void; | |
| 394 | \\pub export fn foo() void { | |
| 395 | \\ {} | |
| 396 | \\ {} | |
| 397 | \\ {} | |
| 398 | \\ {} | |
| 399 | \\ {} | |
| 400 | \\} | |
| 441 | 401 | }); |
| 442 | 402 | |
| 443 | cases.add_2("variable declarations", | |
| 444 | \\extern char arr0[] = "hello"; | |
| 445 | \\static char arr1[] = "hello"; | |
| 446 | \\char arr2[] = "hello"; | |
| 447 | , &[_][]const u8{ | |
| 448 | \\pub extern var arr0: [*c]u8 = "hello"; | |
| 449 | \\pub var arr1: [*c]u8 = "hello"; | |
| 450 | \\pub export var arr2: [*c]u8 = "hello"; | |
| 451 | }); | |
| 403 | if (builtin.os != builtin.Os.windows) { | |
| 404 | // Windows treats this as an enum with type c_int | |
| 405 | cases.add_both("big negative enum init values when C ABI supports long long enums", | |
| 406 | \\enum EnumWithInits { | |
| 407 | \\ VAL01 = 0, | |
| 408 | \\ VAL02 = 1, | |
| 409 | \\ VAL03 = 2, | |
| 410 | \\ VAL04 = 3, | |
| 411 | \\ VAL05 = -1, | |
| 412 | \\ VAL06 = -2, | |
| 413 | \\ VAL07 = -3, | |
| 414 | \\ VAL08 = -4, | |
| 415 | \\ VAL09 = VAL02 + VAL08, | |
| 416 | \\ VAL10 = -1000012000, | |
| 417 | \\ VAL11 = -1000161000, | |
| 418 | \\ VAL12 = -1000174001, | |
| 419 | \\ VAL13 = VAL09, | |
| 420 | \\ VAL14 = VAL10, | |
| 421 | \\ VAL15 = VAL11, | |
| 422 | \\ VAL16 = VAL13, | |
| 423 | \\ VAL17 = (VAL16 - VAL10 + 1), | |
| 424 | \\ VAL18 = 0x1000000000000000L, | |
| 425 | \\ VAL19 = VAL18 + VAL18 + VAL18 - 1, | |
| 426 | \\ VAL20 = VAL19 + VAL19, | |
| 427 | \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF, | |
| 428 | \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1, | |
| 429 | \\ VAL23 = 0xFFFFFFFFFFFFFFFF, | |
| 430 | \\}; | |
| 431 | , &[_][]const u8{ | |
| 432 | \\pub const enum_EnumWithInits = extern enum(c_longlong) { | |
| 433 | \\ VAL01 = 0, | |
| 434 | \\ VAL02 = 1, | |
| 435 | \\ VAL03 = 2, | |
| 436 | \\ VAL04 = 3, | |
| 437 | \\ VAL05 = -1, | |
| 438 | \\ VAL06 = -2, | |
| 439 | \\ VAL07 = -3, | |
| 440 | \\ VAL08 = -4, | |
| 441 | \\ VAL09 = -3, | |
| 442 | \\ VAL10 = -1000012000, | |
| 443 | \\ VAL11 = -1000161000, | |
| 444 | \\ VAL12 = -1000174001, | |
| 445 | \\ VAL13 = -3, | |
| 446 | \\ VAL14 = -1000012000, | |
| 447 | \\ VAL15 = -1000161000, | |
| 448 | \\ VAL16 = -3, | |
| 449 | \\ VAL17 = 1000011998, | |
| 450 | \\ VAL18 = 1152921504606846976, | |
| 451 | \\ VAL19 = 3458764513820540927, | |
| 452 | \\ VAL20 = 6917529027641081854, | |
| 453 | \\ VAL21 = 6917529027641081853, | |
| 454 | \\ VAL22 = 0, | |
| 455 | \\ VAL23 = -1, | |
| 456 | \\}; | |
| 457 | }); | |
| 458 | } | |
| 452 | 459 | |
| 453 | cases.add_2("array initializer expr", | |
| 454 | \\static void foo(void){ | |
| 455 | \\ char arr[10] ={1}; | |
| 456 | \\ char *arr1[10] ={0}; | |
| 460 | cases.addC_both("predefined expressions", | |
| 461 | \\void foo(void) { | |
| 462 | \\ __func__; | |
| 463 | \\ __FUNCTION__; | |
| 464 | \\ __PRETTY_FUNCTION__; | |
| 457 | 465 | \\} |
| 458 | 466 | , &[_][]const u8{ |
| 459 | \\pub fn foo() void { | |
| 460 | \\ var arr: [10]u8 = .{ | |
| 461 | \\ @as(u8, 1), | |
| 462 | \\ } ++ .{0} ** 9; | |
| 463 | \\ var arr1: [10][*c]u8 = .{ | |
| 464 | \\ null, | |
| 465 | \\ } ++ .{null} ** 9; | |
| 467 | \\pub export fn foo() void { | |
| 468 | \\ _ = "foo"; | |
| 469 | \\ _ = "foo"; | |
| 470 | \\ _ = "void foo(void)"; | |
| 466 | 471 | \\} |
| 467 | 472 | }); |
| 468 | 473 | |
| 469 | cases.add_2("enums", | |
| 470 | \\typedef enum { | |
| 471 | \\ a, | |
| 472 | \\ b, | |
| 473 | \\ c, | |
| 474 | \\} d; | |
| 475 | \\enum { | |
| 476 | \\ e, | |
| 477 | \\ f = 4, | |
| 478 | \\ g, | |
| 479 | \\} h = e; | |
| 480 | \\struct Baz { | |
| 481 | \\ enum { | |
| 482 | \\ i, | |
| 483 | \\ j, | |
| 484 | \\ k, | |
| 485 | \\ } l; | |
| 486 | \\ d m; | |
| 487 | \\}; | |
| 488 | \\enum i { | |
| 489 | \\ n, | |
| 490 | \\ o, | |
| 491 | \\ p, | |
| 492 | \\}; | |
| 474 | cases.addC_both("ignore result, no function arguments", | |
| 475 | \\void foo() { | |
| 476 | \\ int a; | |
| 477 | \\ 1; | |
| 478 | \\ "hey"; | |
| 479 | \\ 1 + 1; | |
| 480 | \\ 1 - 1; | |
| 481 | \\ a = 1; | |
| 482 | \\} | |
| 493 | 483 | , &[_][]const u8{ |
| 494 | \\pub const a = enum_unnamed_1.a; | |
| 495 | \\pub const b = enum_unnamed_1.b; | |
| 496 | \\pub const c = enum_unnamed_1.c; | |
| 497 | \\pub const enum_unnamed_1 = extern enum { | |
| 498 | \\ a, | |
| 499 | \\ b, | |
| 500 | \\ c, | |
| 501 | \\}; | |
| 502 | \\pub const d = enum_unnamed_1; | |
| 503 | \\pub const e = enum_unnamed_2.e; | |
| 504 | \\pub const f = enum_unnamed_2.f; | |
| 505 | \\pub const g = enum_unnamed_2.g; | |
| 506 | \\pub const enum_unnamed_2 = extern enum { | |
| 507 | \\ e = 0, | |
| 508 | \\ f = 4, | |
| 509 | \\ g = 5, | |
| 510 | \\}; | |
| 511 | \\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e); | |
| 512 | \\pub const i = enum_unnamed_3.i; | |
| 513 | \\pub const j = enum_unnamed_3.j; | |
| 514 | \\pub const k = enum_unnamed_3.k; | |
| 515 | \\pub const enum_unnamed_3 = extern enum { | |
| 516 | \\ i, | |
| 517 | \\ j, | |
| 518 | \\ k, | |
| 519 | \\}; | |
| 520 | \\pub const struct_Baz = extern struct { | |
| 521 | \\ l: enum_unnamed_3, | |
| 522 | \\ m: d, | |
| 523 | \\}; | |
| 524 | \\pub const n = enum_i.n; | |
| 525 | \\pub const o = enum_i.o; | |
| 526 | \\pub const p = enum_i.p; | |
| 527 | \\pub const enum_i = extern enum { | |
| 528 | \\ n, | |
| 529 | \\ o, | |
| 530 | \\ p, | |
| 531 | \\}; | |
| 532 | , | |
| 533 | \\pub const Baz = struct_Baz; | |
| 484 | \\pub export fn foo() void { | |
| 485 | \\ var a: c_int = undefined; | |
| 486 | \\ _ = 1; | |
| 487 | \\ _ = "hey"; | |
| 488 | \\ _ = (1 + 1); | |
| 489 | \\ _ = (1 - 1); | |
| 490 | \\ a = 1; | |
| 491 | \\} | |
| 534 | 492 | }); |
| 535 | 493 | |
| 536 | cases.add_2("#define a char literal", | |
| 537 | \\#define A_CHAR 'a' | |
| 494 | cases.add_both("constant size array", | |
| 495 | \\void func(int array[20]); | |
| 538 | 496 | , &[_][]const u8{ |
| 539 | \\pub const A_CHAR = 'a'; | |
| 497 | \\pub extern fn func(array: [*c]c_int) void; | |
| 540 | 498 | }); |
| 541 | 499 | |
| 542 | cases.add_2("comment after integer literal", | |
| 543 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 500 | cases.add_both("__cdecl doesn't mess up function pointers", | |
| 501 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 544 | 502 | , &[_][]const u8{ |
| 545 | \\pub const SDL_INIT_VIDEO = 0x00000020; | |
| 503 | \\pub extern fn foo(fn_ptr: ?extern fn () void) void; | |
| 546 | 504 | }); |
| 547 | 505 | |
| 548 | cases.add_2("u integer suffix after hex literal", | |
| 549 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 506 | cases.addC_both("void cast", | |
| 507 | \\void foo() { | |
| 508 | \\ int a; | |
| 509 | \\ (void) a; | |
| 510 | \\} | |
| 550 | 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 | }); |
| 553 | 517 | |
| 554 | cases.add_2("l integer suffix after hex literal", | |
| 555 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 518 | cases.addC_both("implicit cast to void *", | |
| 519 | \\void *foo() { | |
| 520 | \\ unsigned short *x; | |
| 521 | \\ return x; | |
| 522 | \\} | |
| 556 | 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 | }); |
| 559 | 529 | |
| 560 | cases.add_2("ul integer suffix after hex literal", | |
| 561 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 530 | cases.addC_both("null pointer implicit cast", | |
| 531 | \\int* foo(void) { | |
| 532 | \\ return 0; | |
| 533 | \\} | |
| 562 | 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 | }); |
| 565 | 539 | |
| 566 | cases.add_2("lu integer suffix after hex literal", | |
| 567 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 540 | cases.add_both("simple union", | |
| 541 | \\union Foo { | |
| 542 | \\ int x; | |
| 543 | \\ double y; | |
| 544 | \\}; | |
| 568 | 545 | , &[_][]const u8{ |
| 569 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); | |
| 570 | }); | |
| 571 | ||
| 572 | cases.add_2("ll integer suffix after hex literal", | |
| 573 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 574 | , &[_][]const u8{ | |
| 575 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); | |
| 576 | }); | |
| 577 | ||
| 578 | cases.add_2("ull integer suffix after hex literal", | |
| 579 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 580 | , &[_][]const u8{ | |
| 581 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | |
| 582 | }); | |
| 583 | ||
| 584 | cases.add_2("llu integer suffix after hex literal", | |
| 585 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 586 | , &[_][]const u8{ | |
| 587 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | |
| 588 | }); | |
| 589 | ||
| 590 | cases.add_2("generate inline func for #define global extern fn", | |
| 591 | \\extern void (*fn_ptr)(void); | |
| 592 | \\#define foo fn_ptr | |
| 593 | \\ | |
| 594 | \\extern char (*fn_ptr2)(int, float); | |
| 595 | \\#define bar fn_ptr2 | |
| 596 | , &[_][]const u8{ | |
| 597 | \\pub extern var fn_ptr: ?extern fn () void; | |
| 598 | , | |
| 599 | \\pub inline fn foo() void { | |
| 600 | \\ return fn_ptr.?(); | |
| 601 | \\} | |
| 602 | , | |
| 603 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | |
| 604 | , | |
| 605 | \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { | |
| 606 | \\ return fn_ptr2.?(arg_1, arg_2); | |
| 607 | \\} | |
| 608 | }); | |
| 609 | ||
| 610 | cases.add_2("macros with field targets", | |
| 611 | \\typedef unsigned int GLbitfield; | |
| 612 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | |
| 613 | \\typedef void(*OpenGLProc)(void); | |
| 614 | \\union OpenGLProcs { | |
| 615 | \\ OpenGLProc ptr[1]; | |
| 616 | \\ struct { | |
| 617 | \\ PFNGLCLEARPROC Clear; | |
| 618 | \\ } gl; | |
| 619 | \\}; | |
| 620 | \\extern union OpenGLProcs glProcs; | |
| 621 | \\#define glClearUnion glProcs.gl.Clear | |
| 622 | \\#define glClearPFN PFNGLCLEARPROC | |
| 623 | , &[_][]const u8{ | |
| 624 | \\pub const GLbitfield = c_uint; | |
| 625 | , | |
| 626 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | |
| 627 | , | |
| 628 | \\pub const OpenGLProc = ?extern fn () void; | |
| 629 | , | |
| 630 | \\pub const union_OpenGLProcs = extern union { | |
| 631 | \\ ptr: [1]OpenGLProc, | |
| 632 | \\ gl: extern struct { | |
| 633 | \\ Clear: PFNGLCLEARPROC, | |
| 634 | \\ }, | |
| 546 | \\pub const union_Foo = extern union { | |
| 547 | \\ x: c_int, | |
| 548 | \\ y: f64, | |
| 635 | 549 | \\}; |
| 636 | 550 | , |
| 637 | \\pub extern var glProcs: union_OpenGLProcs; | |
| 638 | , | |
| 639 | \\pub const glClearPFN = PFNGLCLEARPROC; | |
| 640 | // , // TODO | |
| 641 | // \\pub inline fn glClearUnion(arg_1: GLbitfield) void { | |
| 642 | // \\ return glProcs.gl.Clear.?(arg_1); | |
| 643 | // \\} | |
| 644 | , | |
| 645 | \\pub const OpenGLProcs = union_OpenGLProcs; | |
| 646 | }); | |
| 647 | ||
| 648 | cases.add_2("macro pointer cast", | |
| 649 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | |
| 650 | , &[_][]const u8{ | |
| 651 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | |
| 652 | }); | |
| 653 | ||
| 654 | cases.add_2("basic macro function", | |
| 655 | \\extern int c; | |
| 656 | \\#define BASIC(c) (c*2) | |
| 657 | , &[_][]const u8{ | |
| 658 | \\pub extern var c: c_int; | |
| 659 | , | |
| 660 | \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) { | |
| 661 | \\ return c_1 * 2; | |
| 662 | \\} | |
| 663 | }); | |
| 664 | ||
| 665 | cases.add_2("macro escape sequences", | |
| 666 | \\#define FOO "aoeu\xab derp" | |
| 667 | \\#define FOO2 "aoeu\a derp" | |
| 668 | , &[_][]const u8{ | |
| 669 | \\pub const FOO = "aoeu\xab derp"; | |
| 670 | , | |
| 671 | \\pub const FOO2 = "aoeu\x07 derp"; | |
| 551 | \\pub const Foo = union_Foo; | |
| 672 | 552 | }); |
| 673 | 553 | |
| 674 | cases.add_2("variable aliasing", | |
| 675 | \\static long a = 2; | |
| 676 | \\static long b = 2; | |
| 677 | \\static int c = 4; | |
| 678 | \\void foo(char c) { | |
| 679 | \\ int a; | |
| 680 | \\ char b = 123; | |
| 681 | \\ b = (char) a; | |
| 682 | \\ { | |
| 683 | \\ int d = 5; | |
| 684 | \\ } | |
| 685 | \\ unsigned d = 440; | |
| 554 | cases.addC_both("string literal", | |
| 555 | \\const char *foo(void) { | |
| 556 | \\ return "bar"; | |
| 686 | 557 | \\} |
| 687 | 558 | , &[_][]const u8{ |
| 688 | \\pub var a: c_long = @as(c_long, 2); | |
| 689 | \\pub var b: c_long = @as(c_long, 2); | |
| 690 | \\pub var c: c_int = 4; | |
| 691 | \\pub export fn foo(c_1: u8) void { | |
| 692 | \\ var a_2: c_int = undefined; | |
| 693 | \\ var b_3: u8 = @as(u8, 123); | |
| 694 | \\ b_3 = @as(u8, a_2); | |
| 695 | \\ { | |
| 696 | \\ var d: c_int = 5; | |
| 697 | \\ } | |
| 698 | \\ var d: c_uint = @as(c_uint, 440); | |
| 559 | \\pub export fn foo() [*c]const u8 { | |
| 560 | \\ return "bar"; | |
| 699 | 561 | \\} |
| 700 | 562 | }); |
| 701 | 563 | |
| 702 | /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// | |
| 703 | ||
| 704 | if (builtin.os != builtin.Os.windows) { | |
| 705 | // Windows treats this as an enum with type c_int | |
| 706 | cases.add("big negative enum init values when C ABI supports long long enums", | |
| 707 | \\enum EnumWithInits { | |
| 708 | \\ VAL01 = 0, | |
| 709 | \\ VAL02 = 1, | |
| 710 | \\ VAL03 = 2, | |
| 711 | \\ VAL04 = 3, | |
| 712 | \\ VAL05 = -1, | |
| 713 | \\ VAL06 = -2, | |
| 714 | \\ VAL07 = -3, | |
| 715 | \\ VAL08 = -4, | |
| 716 | \\ VAL09 = VAL02 + VAL08, | |
| 717 | \\ VAL10 = -1000012000, | |
| 718 | \\ VAL11 = -1000161000, | |
| 719 | \\ VAL12 = -1000174001, | |
| 720 | \\ VAL13 = VAL09, | |
| 721 | \\ VAL14 = VAL10, | |
| 722 | \\ VAL15 = VAL11, | |
| 723 | \\ VAL16 = VAL13, | |
| 724 | \\ VAL17 = (VAL16 - VAL10 + 1), | |
| 725 | \\ VAL18 = 0x1000000000000000L, | |
| 726 | \\ VAL19 = VAL18 + VAL18 + VAL18 - 1, | |
| 727 | \\ VAL20 = VAL19 + VAL19, | |
| 728 | \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF, | |
| 729 | \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1, | |
| 730 | \\ VAL23 = 0xFFFFFFFFFFFFFFFF, | |
| 731 | \\}; | |
| 732 | , &[_][]const u8{ | |
| 733 | \\pub const enum_EnumWithInits = extern enum(c_longlong) { | |
| 734 | \\ VAL01 = 0, | |
| 735 | \\ VAL02 = 1, | |
| 736 | \\ VAL03 = 2, | |
| 737 | \\ VAL04 = 3, | |
| 738 | \\ VAL05 = -1, | |
| 739 | \\ VAL06 = -2, | |
| 740 | \\ VAL07 = -3, | |
| 741 | \\ VAL08 = -4, | |
| 742 | \\ VAL09 = -3, | |
| 743 | \\ VAL10 = -1000012000, | |
| 744 | \\ VAL11 = -1000161000, | |
| 745 | \\ VAL12 = -1000174001, | |
| 746 | \\ VAL13 = -3, | |
| 747 | \\ VAL14 = -1000012000, | |
| 748 | \\ VAL15 = -1000161000, | |
| 749 | \\ VAL16 = -3, | |
| 750 | \\ VAL17 = 1000011998, | |
| 751 | \\ VAL18 = 1152921504606846976, | |
| 752 | \\ VAL19 = 3458764513820540927, | |
| 753 | \\ VAL20 = 6917529027641081854, | |
| 754 | \\ VAL21 = 6917529027641081853, | |
| 755 | \\ VAL22 = 0, | |
| 756 | \\ VAL23 = -1, | |
| 757 | \\}; | |
| 758 | }); | |
| 759 | } | |
| 760 | ||
| 761 | cases.add("predefined expressions", | |
| 564 | cases.addC_both("return void", | |
| 762 | 565 | \\void foo(void) { |
| 763 | \\ __func__; | |
| 764 | \\ __FUNCTION__; | |
| 765 | \\ __PRETTY_FUNCTION__; | |
| 566 | \\ return; | |
| 766 | 567 | \\} |
| 767 | 568 | , &[_][]const u8{ |
| 768 | \\pub fn foo() void { | |
| 769 | \\ _ = "foo"; | |
| 770 | \\ _ = "foo"; | |
| 771 | \\ _ = "void foo(void)"; | |
| 569 | \\pub export fn foo() void { | |
| 570 | \\ return; | |
| 772 | 571 | \\} |
| 773 | 572 | }); |
| 774 | 573 | |
| 775 | cases.add("ignore result, no function arguments", | |
| 776 | \\void foo() { | |
| 777 | \\ int a; | |
| 778 | \\ 1; | |
| 779 | \\ "hey"; | |
| 780 | \\ 1 + 1; | |
| 781 | \\ 1 - 1; | |
| 782 | \\ a = 1; | |
| 574 | cases.addC_both("for loop", | |
| 575 | \\void foo(void) { | |
| 576 | \\ for (int i = 0; i; i = i + 1) { } | |
| 783 | 577 | \\} |
| 784 | 578 | , &[_][]const u8{ |
| 785 | \\pub fn foo() void { | |
| 786 | \\ var a: c_int = undefined; | |
| 787 | \\ _ = 1; | |
| 788 | \\ _ = "hey"; | |
| 789 | \\ _ = (1 + 1); | |
| 790 | \\ _ = (1 - 1); | |
| 791 | \\ a = 1; | |
| 579 | \\pub export fn foo() void { | |
| 580 | \\ { | |
| 581 | \\ var i: c_int = 0; | |
| 582 | \\ while (i != 0) : (i = (i + 1)) {} | |
| 583 | \\ } | |
| 792 | 584 | \\} |
| 793 | 585 | }); |
| 794 | 586 | |
| 795 | cases.add("for loop with var init but empty body", | |
| 587 | cases.addC_both("empty for loop", | |
| 796 | 588 | \\void foo(void) { |
| 797 | \\ for (int x = 0; x < 10; x++); | |
| 589 | \\ for (;;) { } | |
| 798 | 590 | \\} |
| 799 | 591 | , &[_][]const u8{ |
| 800 | \\pub fn foo() void { | |
| 801 | \\ { | |
| 802 | \\ var x: c_int = 0; | |
| 803 | \\ while (x < 10) : (x += 1) {} | |
| 804 | \\ } | |
| 592 | \\pub export fn foo() void { | |
| 593 | \\ while (true) {} | |
| 805 | 594 | \\} |
| 806 | 595 | }); |
| 807 | 596 | |
| 808 | cases.add("do while with empty body", | |
| 597 | cases.addC_both("break statement", | |
| 809 | 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) break | |
| 813 | \\pub fn foo() void { | |
| 603 | , &[_][]const u8{ | |
| 604 | \\pub export fn foo() void { | |
| 814 | 605 | \\ while (true) { |
| 815 | \\ {} | |
| 816 | \\ if (!1) break; | |
| 606 | \\ break; | |
| 817 | 607 | \\ } |
| 818 | 608 | \\} |
| 819 | 609 | }); |
| 820 | 610 | |
| 821 | cases.add("for with empty body", | |
| 611 | cases.addC_both("continue statement", | |
| 822 | 612 | \\void foo(void) { |
| 823 | \\ for (;;); | |
| 613 | \\ for (;;) { | |
| 614 | \\ continue; | |
| 615 | \\ } | |
| 824 | 616 | \\} |
| 825 | 617 | , &[_][]const u8{ |
| 826 | \\pub fn foo() void { | |
| 827 | \\ while (true) {} | |
| 618 | \\pub export fn foo() void { | |
| 619 | \\ while (true) { | |
| 620 | \\ continue; | |
| 621 | \\ } | |
| 828 | 622 | \\} |
| 829 | 623 | }); |
| 830 | 624 | |
| 831 | cases.add("while with empty body", | |
| 832 | \\void foo(void) { | |
| 833 | \\ while (1); | |
| 625 | cases.addC_both("pointer casting", | |
| 626 | \\float *ptrcast() { | |
| 627 | \\ int *a; | |
| 628 | \\ return (float *)a; | |
| 834 | 629 | \\} |
| 835 | 630 | , &[_][]const u8{ |
| 836 | \\pub fn foo() void { | |
| 837 | \\ while (1 != 0) {} | |
| 631 | \\pub export fn ptrcast() [*c]f32 { | |
| 632 | \\ var a: [*c]c_int = undefined; | |
| 633 | \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); | |
| 838 | 634 | \\} |
| 839 | 635 | }); |
| 840 | 636 | |
| 841 | cases.addAllowWarnings("simple data types", | |
| 842 | \\#include <stdint.h> | |
| 843 | \\int foo(char a, unsigned char b, signed char c); | |
| 844 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 845 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 846 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 847 | , &[_][]const u8{ | |
| 848 | \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; | |
| 849 | , | |
| 850 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; | |
| 851 | , | |
| 852 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; | |
| 853 | }); | |
| 854 | ||
| 855 | cases.addC("simple function", | |
| 856 | \\int abs(int a) { | |
| 857 | \\ return a < 0 ? -a : a; | |
| 637 | cases.addC_both("pointer conversion with different alignment", | |
| 638 | \\void test_ptr_cast() { | |
| 639 | \\ void *p; | |
| 640 | \\ { | |
| 641 | \\ char *to_char = (char *)p; | |
| 642 | \\ short *to_short = (short *)p; | |
| 643 | \\ int *to_int = (int *)p; | |
| 644 | \\ long long *to_longlong = (long long *)p; | |
| 645 | \\ } | |
| 646 | \\ { | |
| 647 | \\ char *to_char = p; | |
| 648 | \\ short *to_short = p; | |
| 649 | \\ int *to_int = p; | |
| 650 | \\ long long *to_longlong = p; | |
| 651 | \\ } | |
| 858 | 652 | \\} |
| 859 | 653 | , &[_][]const u8{ |
| 860 | \\export fn abs(a: c_int) c_int { | |
| 861 | \\ return if (a < 0) -a else a; | |
| 654 | \\pub export fn test_ptr_cast() void { | |
| 655 | \\ var p: ?*c_void = undefined; | |
| 656 | \\ { | |
| 657 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | |
| 658 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | |
| 659 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | |
| 660 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | |
| 661 | \\ } | |
| 662 | \\ { | |
| 663 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | |
| 664 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | |
| 665 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | |
| 666 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | |
| 667 | \\ } | |
| 862 | 668 | \\} |
| 863 | 669 | }); |
| 864 | 670 | |
| 865 | cases.add("restrict -> noalias", | |
| 866 | \\void foo(void *restrict bar, void *restrict); | |
| 867 | , &[_][]const u8{ | |
| 868 | \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; | |
| 869 | }); | |
| 870 | ||
| 871 | cases.add("qualified struct and enum", | |
| 872 | \\struct Foo { | |
| 873 | \\ int x; | |
| 874 | \\ int y; | |
| 875 | \\}; | |
| 876 | \\enum Bar { | |
| 877 | \\ BarA, | |
| 878 | \\ BarB, | |
| 879 | \\}; | |
| 880 | \\void func(struct Foo *a, enum Bar **b); | |
| 881 | , &[_][]const u8{ | |
| 882 | \\pub const struct_Foo = extern struct { | |
| 883 | \\ x: c_int, | |
| 884 | \\ y: c_int, | |
| 885 | \\}; | |
| 886 | , | |
| 887 | \\pub const enum_Bar = extern enum { | |
| 888 | \\ A, | |
| 889 | \\ B, | |
| 890 | \\}; | |
| 891 | , | |
| 892 | \\pub const BarA = enum_Bar.A; | |
| 893 | , | |
| 894 | \\pub const BarB = enum_Bar.B; | |
| 895 | , | |
| 896 | \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void; | |
| 897 | , | |
| 898 | \\pub const Foo = struct_Foo; | |
| 899 | , | |
| 900 | \\pub const Bar = enum_Bar; | |
| 901 | }); | |
| 902 | ||
| 903 | cases.add("constant size array", | |
| 904 | \\void func(int array[20]); | |
| 905 | , &[_][]const u8{ | |
| 906 | \\pub extern fn func(array: [*c]c_int) void; | |
| 907 | }); | |
| 908 | ||
| 909 | cases.add("__cdecl doesn't mess up function pointers", | |
| 910 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 911 | , &[_][]const u8{ | |
| 912 | \\pub extern fn foo(fn_ptr: ?extern fn () void) void; | |
| 913 | }); | |
| 914 | ||
| 915 | cases.add("macro defines string literal with hex", | |
| 916 | \\#define FOO "aoeu\xab derp" | |
| 917 | \\#define FOO2 "aoeu\x0007a derp" | |
| 918 | \\#define FOO_CHAR '\xfF' | |
| 919 | , &[_][]const u8{ | |
| 920 | \\pub const FOO = "aoeu\xab derp"; | |
| 921 | , | |
| 922 | \\pub const FOO2 = "aoeuz derp"; | |
| 923 | , | |
| 924 | \\pub const FOO_CHAR = 255; | |
| 925 | }); | |
| 926 | ||
| 927 | cases.add("macro defines string literal with octal", | |
| 928 | \\#define FOO "aoeu\023 derp" | |
| 929 | \\#define FOO2 "aoeu\0234 derp" | |
| 930 | \\#define FOO_CHAR '\077' | |
| 671 | cases.addC_both("while on non-bool", | |
| 672 | \\int while_none_bool() { | |
| 673 | \\ int a; | |
| 674 | \\ float b; | |
| 675 | \\ void *c; | |
| 676 | \\ while (a) return 0; | |
| 677 | \\ while (b) return 1; | |
| 678 | \\ while (c) return 2; | |
| 679 | \\ return 3; | |
| 680 | \\} | |
| 931 | 681 | , &[_][]const u8{ |
| 932 | \\pub const FOO = "aoeu\x13 derp"; | |
| 933 | , | |
| 934 | \\pub const FOO2 = "aoeu\x134 derp"; | |
| 935 | , | |
| 936 | \\pub const FOO_CHAR = 63; | |
| 682 | \\pub export fn while_none_bool() c_int { | |
| 683 | \\ var a: c_int = undefined; | |
| 684 | \\ var b: f32 = undefined; | |
| 685 | \\ var c: ?*c_void = undefined; | |
| 686 | \\ while (a != 0) return 0; | |
| 687 | \\ while (b != 0) return 1; | |
| 688 | \\ while (c != null) return 2; | |
| 689 | \\ return 3; | |
| 690 | \\} | |
| 937 | 691 | }); |
| 938 | 692 | |
| 939 | cases.addC("post increment", | |
| 940 | \\unsigned foo1(unsigned a) { | |
| 941 | \\ a++; | |
| 942 | \\ return a; | |
| 943 | \\} | |
| 944 | \\int foo2(int a) { | |
| 945 | \\ a++; | |
| 946 | \\ return a; | |
| 693 | cases.addC_both("for on non-bool", | |
| 694 | \\int for_none_bool() { | |
| 695 | \\ int a; | |
| 696 | \\ float b; | |
| 697 | \\ void *c; | |
| 698 | \\ for (;a;) return 0; | |
| 699 | \\ for (;b;) return 1; | |
| 700 | \\ for (;c;) return 2; | |
| 701 | \\ return 3; | |
| 947 | 702 | \\} |
| 948 | 703 | , &[_][]const u8{ |
| 949 | \\pub export fn foo1(_arg_a: c_uint) c_uint { | |
| 950 | \\ var a = _arg_a; | |
| 951 | \\ a +%= 1; | |
| 952 | \\ return a; | |
| 953 | \\} | |
| 954 | \\pub export fn foo2(_arg_a: c_int) c_int { | |
| 955 | \\ var a = _arg_a; | |
| 956 | \\ a += 1; | |
| 957 | \\ return a; | |
| 704 | \\pub export fn for_none_bool() c_int { | |
| 705 | \\ var a: c_int = undefined; | |
| 706 | \\ var b: f32 = undefined; | |
| 707 | \\ var c: ?*c_void = undefined; | |
| 708 | \\ while (a != 0) return 0; | |
| 709 | \\ while (b != 0) return 1; | |
| 710 | \\ while (c != null) return 2; | |
| 711 | \\ return 3; | |
| 958 | 712 | \\} |
| 959 | 713 | }); |
| 960 | 714 | |
| 961 | cases.addC("shift right assign", | |
| 962 | \\int log2(unsigned a) { | |
| 963 | \\ int i = 0; | |
| 964 | \\ while (a > 0) { | |
| 965 | \\ a >>= 1; | |
| 966 | \\ } | |
| 967 | \\ return i; | |
| 715 | cases.addC_both("bitshift", | |
| 716 | \\int foo(void) { | |
| 717 | \\ return (1 << 2) >> 1; | |
| 968 | 718 | \\} |
| 969 | 719 | , &[_][]const u8{ |
| 970 | \\pub export fn log2(_arg_a: c_uint) c_int { | |
| 971 | \\ var a = _arg_a; | |
| 972 | \\ var i: c_int = 0; | |
| 973 | \\ while (a > @as(c_uint, 0)) { | |
| 974 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1); | |
| 975 | \\ } | |
| 976 | \\ return i; | |
| 720 | \\pub export fn foo() c_int { | |
| 721 | \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1); | |
| 977 | 722 | \\} |
| 978 | 723 | }); |
| 979 | 724 | |
| 980 | cases.addC("if statement", | |
| 981 | \\int max(int a, int b) { | |
| 982 | \\ if (a < b) | |
| 983 | \\ return b; | |
| 984 | \\ | |
| 985 | \\ if (a < b) | |
| 986 | \\ return b; | |
| 987 | \\ else | |
| 988 | \\ return a; | |
| 989 | \\ | |
| 990 | \\ if (a < b) ; else ; | |
| 725 | cases.addC_both("sizeof", | |
| 726 | \\#include <stddef.h> | |
| 727 | \\size_t size_of(void) { | |
| 728 | \\ return sizeof(int); | |
| 991 | 729 | \\} |
| 992 | 730 | , &[_][]const u8{ |
| 993 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 994 | \\ if (a < b) return b; | |
| 995 | \\ if (a < b) return b else return a; | |
| 996 | \\ if (a < b) {} else {} | |
| 731 | \\pub export fn size_of() usize { | |
| 732 | \\ return @sizeOf(c_int); | |
| 997 | 733 | \\} |
| 998 | 734 | }); |
| 999 | 735 | |
| 1000 | cases.addC("==, !=", | |
| 1001 | \\int max(int a, int b) { | |
| 1002 | \\ if (a == b) | |
| 1003 | \\ return a; | |
| 1004 | \\ if (a != b) | |
| 1005 | \\ return b; | |
| 1006 | \\ return a; | |
| 736 | cases.addC_both("normal deref", | |
| 737 | \\void foo() { | |
| 738 | \\ int *x; | |
| 739 | \\ *x = 1; | |
| 1007 | 740 | \\} |
| 1008 | 741 | , &[_][]const u8{ |
| 1009 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 1010 | \\ if (a == b) return a; | |
| 1011 | \\ if (a != b) return b; | |
| 1012 | \\ return a; | |
| 742 | \\pub export fn foo() void { | |
| 743 | \\ var x: [*c]c_int = undefined; | |
| 744 | \\ x.?.* = 1; | |
| 1013 | 745 | \\} |
| 1014 | 746 | }); |
| 1015 | 747 | |
| 1016 | cases.addC("bitwise binary operators", | |
| 1017 | \\int max(int a, int b) { | |
| 1018 | \\ return (a & b) ^ (a | b); | |
| 748 | cases.addC_both("address of operator", | |
| 749 | \\int foo(void) { | |
| 750 | \\ int x = 1234; | |
| 751 | \\ int *ptr = &x; | |
| 752 | \\ return *ptr; | |
| 1019 | 753 | \\} |
| 1020 | 754 | , &[_][]const u8{ |
| 1021 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 1022 | \\ return (a & b) ^ (a | b); | |
| 755 | \\pub export fn foo() c_int { | |
| 756 | \\ var x: c_int = 1234; | |
| 757 | \\ var ptr: [*c]c_int = &x; | |
| 758 | \\ return ptr.?.*; | |
| 1023 | 759 | \\} |
| 1024 | 760 | }); |
| 1025 | 761 | |
| 1026 | cases.addC("logical and, logical or", | |
| 1027 | \\int max(int a, int b) { | |
| 1028 | \\ if (a < b || a == b) | |
| 1029 | \\ return b; | |
| 1030 | \\ if (a >= b && a == b) | |
| 1031 | \\ return a; | |
| 1032 | \\ return a; | |
| 762 | cases.addC_both("bin not", | |
| 763 | \\int foo() { | |
| 764 | \\ int x; | |
| 765 | \\ return ~x; | |
| 1033 | 766 | \\} |
| 1034 | 767 | , &[_][]const u8{ |
| 1035 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 1036 | \\ if ((a < b) or (a == b)) return b; | |
| 1037 | \\ if ((a >= b) and (a == b)) return a; | |
| 1038 | \\ return a; | |
| 768 | \\pub export fn foo() c_int { | |
| 769 | \\ var x: c_int = undefined; | |
| 770 | \\ return ~x; | |
| 1039 | 771 | \\} |
| 1040 | 772 | }); |
| 1041 | 773 | |
| 1042 | cases.addC("logical and, logical or on none bool values", | |
| 1043 | \\int and_or_none_bool(int a, float b, void *c) { | |
| 1044 | \\ if (a && b) return 0; | |
| 1045 | \\ if (b && c) return 1; | |
| 1046 | \\ if (a && c) return 2; | |
| 1047 | \\ if (a || b) return 3; | |
| 1048 | \\ if (b || c) return 4; | |
| 1049 | \\ if (a || c) return 5; | |
| 1050 | \\ return 6; | |
| 774 | cases.addC_both("bool not", | |
| 775 | \\int foo() { | |
| 776 | \\ int a; | |
| 777 | \\ float b; | |
| 778 | \\ void *c; | |
| 779 | \\ return !(a == 0); | |
| 780 | \\ return !a; | |
| 781 | \\ return !b; | |
| 782 | \\ return !c; | |
| 1051 | 783 | \\} |
| 1052 | 784 | , &[_][]const u8{ |
| 1053 | \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | |
| 1054 | \\ if ((a != 0) and (b != 0)) return 0; | |
| 1055 | \\ if ((b != 0) and (c != null)) return 1; | |
| 1056 | \\ if ((a != 0) and (c != null)) return 2; | |
| 1057 | \\ if ((a != 0) or (b != 0)) return 3; | |
| 1058 | \\ if ((b != 0) or (c != null)) return 4; | |
| 1059 | \\ if ((a != 0) or (c != null)) return 5; | |
| 1060 | \\ return 6; | |
| 785 | \\pub export fn foo() c_int { | |
| 786 | \\ var a: c_int = undefined; | |
| 787 | \\ var b: f32 = undefined; | |
| 788 | \\ var c: ?*c_void = undefined; | |
| 789 | \\ return !(a == 0); | |
| 790 | \\ return !(a != 0); | |
| 791 | \\ return !(b != 0); | |
| 792 | \\ return !(c != null); | |
| 1061 | 793 | \\} |
| 1062 | 794 | }); |
| 1063 | 795 | |
| 1064 | cases.addC("assign", | |
| 1065 | \\int max(int a) { | |
| 1066 | \\ int tmp; | |
| 1067 | \\ tmp = a; | |
| 1068 | \\ a = tmp; | |
| 796 | cases.addC("__extension__ cast", | |
| 797 | \\int foo(void) { | |
| 798 | \\ return __extension__ 1; | |
| 1069 | 799 | \\} |
| 1070 | 800 | , &[_][]const u8{ |
| 1071 | \\pub export fn max(_arg_a: c_int) c_int { | |
| 1072 | \\ var a = _arg_a; | |
| 1073 | \\ var tmp: c_int = undefined; | |
| 1074 | \\ tmp = a; | |
| 1075 | \\ a = tmp; | |
| 801 | \\pub export fn foo() c_int { | |
| 802 | \\ return 1; | |
| 1076 | 803 | \\} |
| 1077 | 804 | }); |
| 1078 | 805 | |
| 1079 | cases.addC("chaining assign", | |
| 1080 | \\void max(int a) { | |
| 1081 | \\ int b, c; | |
| 1082 | \\ c = b = a; | |
| 1083 | \\} | |
| 1084 | , &[_][]const u8{ | |
| 1085 | \\pub export fn max(a: c_int) void { | |
| 1086 | \\ var b: c_int = undefined; | |
| 1087 | \\ var c: c_int = undefined; | |
| 1088 | \\ c = (x: { | |
| 1089 | \\ const _tmp = a; | |
| 1090 | \\ b = _tmp; | |
| 1091 | \\ break :x _tmp; | |
| 1092 | \\ }); | |
| 1093 | \\} | |
| 1094 | }); | |
| 806 | if (builtin.os != builtin.Os.windows) { | |
| 807 | // sysv_abi not currently supported on windows | |
| 808 | cases.add_both("Macro qualified functions", | |
| 809 | \\void __attribute__((sysv_abi)) foo(void); | |
| 810 | , &[_][]const u8{ | |
| 811 | \\pub extern fn foo() void; | |
| 812 | }); | |
| 813 | } | |
| 1095 | 814 | |
| 1096 | cases.addC("shift right assign with a fixed size type", | |
| 1097 | \\#include <stdint.h> | |
| 1098 | \\int log2(uint32_t a) { | |
| 1099 | \\ int i = 0; | |
| 1100 | \\ while (a > 0) { | |
| 1101 | \\ a >>= 1; | |
| 1102 | \\ } | |
| 1103 | \\ return i; | |
| 1104 | \\} | |
| 815 | /////////////// Cases that pass for only stage2 //////////////// | |
| 816 | ||
| 817 | cases.add_2("Parameterless function prototypes", | |
| 818 | \\void a() {} | |
| 819 | \\void b(void) {} | |
| 820 | \\void c(); | |
| 821 | \\void d(void); | |
| 1105 | 822 | , &[_][]const u8{ |
| 1106 | \\pub export fn log2(_arg_a: u32) c_int { | |
| 1107 | \\ var a = _arg_a; | |
| 1108 | \\ var i: c_int = 0; | |
| 1109 | \\ while (a > @as(c_uint, 0)) { | |
| 1110 | \\ a >>= @as(u5, 1); | |
| 1111 | \\ } | |
| 1112 | \\ return i; | |
| 1113 | \\} | |
| 823 | \\pub export fn a() void {} | |
| 824 | \\pub export fn b() void {} | |
| 825 | \\pub extern fn c(...) void; | |
| 826 | \\pub extern fn d() void; | |
| 1114 | 827 | }); |
| 1115 | 828 | |
| 1116 | cases.add("anonymous enum", | |
| 1117 | \\enum { | |
| 1118 | \\ One, | |
| 1119 | \\ Two, | |
| 1120 | \\}; | |
| 829 | cases.add_2("variable declarations", | |
| 830 | \\extern char arr0[] = "hello"; | |
| 831 | \\static char arr1[] = "hello"; | |
| 832 | \\char arr2[] = "hello"; | |
| 1121 | 833 | , &[_][]const u8{ |
| 1122 | \\pub const One = 0; | |
| 1123 | \\pub const Two = 1; | |
| 834 | \\pub extern var arr0: [*c]u8 = "hello"; | |
| 835 | \\pub var arr1: [*c]u8 = "hello"; | |
| 836 | \\pub export var arr2: [*c]u8 = "hello"; | |
| 1124 | 837 | }); |
| 1125 | 838 | |
| 1126 | cases.addC("function call", | |
| 1127 | \\static void bar(void) { } | |
| 1128 | \\static int baz(void) { return 0; } | |
| 1129 | \\void foo(void) { | |
| 1130 | \\ bar(); | |
| 1131 | \\ baz(); | |
| 839 | cases.add_2("array initializer expr", | |
| 840 | \\static void foo(void){ | |
| 841 | \\ char arr[10] ={1}; | |
| 842 | \\ char *arr1[10] ={0}; | |
| 1132 | 843 | \\} |
| 1133 | 844 | , &[_][]const u8{ |
| 1134 | \\pub fn bar() void {} | |
| 1135 | \\pub fn baz() c_int { | |
| 1136 | \\ return 0; | |
| 1137 | \\} | |
| 1138 | \\pub export fn foo() void { | |
| 1139 | \\ bar(); | |
| 1140 | \\ _ = baz(); | |
| 845 | \\pub fn foo() void { | |
| 846 | \\ var arr: [10]u8 = .{ | |
| 847 | \\ @as(u8, 1), | |
| 848 | \\ } ++ .{0} ** 9; | |
| 849 | \\ var arr1: [10][*c]u8 = .{ | |
| 850 | \\ null, | |
| 851 | \\ } ++ .{null} ** 9; | |
| 1141 | 852 | \\} |
| 1142 | 853 | }); |
| 1143 | 854 | |
| 1144 | cases.addC("field access expression", | |
| 1145 | \\struct Foo { | |
| 1146 | \\ int field; | |
| 855 | cases.add_2("enums", | |
| 856 | \\typedef enum { | |
| 857 | \\ a, | |
| 858 | \\ b, | |
| 859 | \\ c, | |
| 860 | \\} d; | |
| 861 | \\enum { | |
| 862 | \\ e, | |
| 863 | \\ f = 4, | |
| 864 | \\ g, | |
| 865 | \\} h = e; | |
| 866 | \\struct Baz { | |
| 867 | \\ enum { | |
| 868 | \\ i, | |
| 869 | \\ j, | |
| 870 | \\ k, | |
| 871 | \\ } l; | |
| 872 | \\ d m; | |
| 873 | \\}; | |
| 874 | \\enum i { | |
| 875 | \\ n, | |
| 876 | \\ o, | |
| 877 | \\ p, | |
| 1147 | 878 | \\}; |
| 1148 | \\int read_field(struct Foo *foo) { | |
| 1149 | \\ return foo->field; | |
| 1150 | \\} | |
| 1151 | 879 | , &[_][]const u8{ |
| 1152 | \\pub const struct_Foo = extern struct { | |
| 1153 | \\ field: c_int, | |
| 880 | \\pub const a = 0; | |
| 881 | \\pub const b = 1; | |
| 882 | \\pub const c = 2; | |
| 883 | \\const enum_unnamed_1 = extern enum { | |
| 884 | \\ a, | |
| 885 | \\ b, | |
| 886 | \\ c, | |
| 1154 | 887 | \\}; |
| 1155 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { | |
| 1156 | \\ return foo.*.field; | |
| 1157 | \\} | |
| 888 | \\pub const d = enum_unnamed_1; | |
| 889 | \\pub const e = 0; | |
| 890 | \\pub const f = 4; | |
| 891 | \\pub const g = 5; | |
| 892 | \\const enum_unnamed_2 = extern enum { | |
| 893 | \\ e = 0, | |
| 894 | \\ f = 4, | |
| 895 | \\ g = 5, | |
| 896 | \\}; | |
| 897 | \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e); | |
| 898 | \\pub const i = 0; | |
| 899 | \\pub const j = 1; | |
| 900 | \\pub const k = 2; | |
| 901 | \\const enum_unnamed_3 = extern enum { | |
| 902 | \\ i, | |
| 903 | \\ j, | |
| 904 | \\ k, | |
| 905 | \\}; | |
| 906 | \\pub const struct_Baz = extern struct { | |
| 907 | \\ l: enum_unnamed_3, | |
| 908 | \\ m: d, | |
| 909 | \\}; | |
| 910 | \\pub const n = 0; | |
| 911 | \\pub const o = 1; | |
| 912 | \\pub const p = 2; | |
| 913 | \\pub const enum_i = extern enum { | |
| 914 | \\ n, | |
| 915 | \\ o, | |
| 916 | \\ p, | |
| 917 | \\}; | |
| 918 | , | |
| 919 | \\pub const Baz = struct_Baz; | |
| 1158 | 920 | }); |
| 1159 | 921 | |
| 1160 | cases.addC("null statements", | |
| 1161 | \\void foo(void) { | |
| 1162 | \\ ;;;;; | |
| 1163 | \\} | |
| 922 | cases.add_2("#define a char literal", | |
| 923 | \\#define A_CHAR 'a' | |
| 1164 | 924 | , &[_][]const u8{ |
| 1165 | \\pub export fn foo() void { | |
| 1166 | \\ {} | |
| 1167 | \\ {} | |
| 1168 | \\ {} | |
| 1169 | \\ {} | |
| 1170 | \\ {} | |
| 1171 | \\} | |
| 925 | \\pub const A_CHAR = 'a'; | |
| 1172 | 926 | }); |
| 1173 | 927 | |
| 1174 | cases.add("undefined array global", | |
| 1175 | \\int array[100]; | |
| 928 | cases.add_2("comment after integer literal", | |
| 929 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1176 | 930 | , &[_][]const u8{ |
| 1177 | \\pub var array: [100]c_int = undefined; | |
| 931 | \\pub const SDL_INIT_VIDEO = 0x00000020; | |
| 1178 | 932 | }); |
| 1179 | 933 | |
| 1180 | cases.addC("array access", | |
| 1181 | \\int array[100]; | |
| 1182 | \\int foo(int index) { | |
| 1183 | \\ return array[index]; | |
| 1184 | \\} | |
| 934 | cases.add_2("u integer suffix after hex literal", | |
| 935 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1185 | 936 | , &[_][]const u8{ |
| 1186 | \\pub var array: [100]c_int = undefined; | |
| 1187 | \\pub export fn foo(index: c_int) c_int { | |
| 1188 | \\ return array[index]; | |
| 1189 | \\} | |
| 937 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); | |
| 1190 | 938 | }); |
| 1191 | 939 | |
| 1192 | cases.addC("c style cast", | |
| 1193 | \\int float_to_int(float a) { | |
| 1194 | \\ return (int)a; | |
| 1195 | \\} | |
| 940 | cases.add_2("l integer suffix after hex literal", | |
| 941 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1196 | 942 | , &[_][]const u8{ |
| 1197 | \\pub export fn float_to_int(a: f32) c_int { | |
| 1198 | \\ return @as(c_int, a); | |
| 1199 | \\} | |
| 943 | \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); | |
| 1200 | 944 | }); |
| 1201 | 945 | |
| 1202 | cases.addC("void cast", | |
| 1203 | \\void foo(int a) { | |
| 1204 | \\ (void) a; | |
| 1205 | \\} | |
| 946 | cases.add_2("ul integer suffix after hex literal", | |
| 947 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1206 | 948 | , &[_][]const u8{ |
| 1207 | \\pub export fn foo(a: c_int) void { | |
| 1208 | \\ _ = a; | |
| 1209 | \\} | |
| 949 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); | |
| 1210 | 950 | }); |
| 1211 | 951 | |
| 1212 | cases.addC("implicit cast to void *", | |
| 1213 | \\void *foo(unsigned short *x) { | |
| 1214 | \\ return x; | |
| 1215 | \\} | |
| 952 | cases.add_2("lu integer suffix after hex literal", | |
| 953 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1216 | 954 | , &[_][]const u8{ |
| 1217 | \\pub export fn foo(x: [*c]c_ushort) ?*c_void { | |
| 1218 | \\ return @ptrCast(?*c_void, x); | |
| 1219 | \\} | |
| 955 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); | |
| 1220 | 956 | }); |
| 1221 | 957 | |
| 1222 | cases.addC("sizeof", | |
| 1223 | \\#include <stddef.h> | |
| 1224 | \\size_t size_of(void) { | |
| 1225 | \\ return sizeof(int); | |
| 1226 | \\} | |
| 958 | cases.add_2("ll integer suffix after hex literal", | |
| 959 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1227 | 960 | , &[_][]const u8{ |
| 1228 | \\pub export fn size_of() usize { | |
| 1229 | \\ return @sizeOf(c_int); | |
| 1230 | \\} | |
| 961 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); | |
| 1231 | 962 | }); |
| 1232 | 963 | |
| 1233 | cases.addC("null pointer implicit cast", | |
| 1234 | \\int* foo(void) { | |
| 1235 | \\ return 0; | |
| 1236 | \\} | |
| 964 | cases.add_2("ull integer suffix after hex literal", | |
| 965 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1237 | 966 | , &[_][]const u8{ |
| 1238 | \\pub export fn foo() [*c]c_int { | |
| 1239 | \\ return null; | |
| 1240 | \\} | |
| 967 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | |
| 1241 | 968 | }); |
| 1242 | 969 | |
| 1243 | cases.addC("comma operator", | |
| 1244 | \\int foo(void) { | |
| 1245 | \\ return 1, 2; | |
| 1246 | \\} | |
| 970 | cases.add_2("llu integer suffix after hex literal", | |
| 971 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 1247 | 972 | , &[_][]const u8{ |
| 1248 | \\pub export fn foo() c_int { | |
| 1249 | \\ return x: { | |
| 1250 | \\ _ = 1; | |
| 1251 | \\ break :x 2; | |
| 1252 | \\ }; | |
| 1253 | \\} | |
| 973 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | |
| 1254 | 974 | }); |
| 1255 | 975 | |
| 1256 | cases.addC("statement expression", | |
| 1257 | \\int foo(void) { | |
| 1258 | \\ return ({ | |
| 1259 | \\ int a = 1; | |
| 1260 | \\ a; | |
| 1261 | \\ }); | |
| 1262 | \\} | |
| 976 | cases.add_2("generate inline func for #define global extern fn", | |
| 977 | \\extern void (*fn_ptr)(void); | |
| 978 | \\#define foo fn_ptr | |
| 979 | \\ | |
| 980 | \\extern char (*fn_ptr2)(int, float); | |
| 981 | \\#define bar fn_ptr2 | |
| 1263 | 982 | , &[_][]const u8{ |
| 1264 | \\pub export fn foo() c_int { | |
| 1265 | \\ return x: { | |
| 1266 | \\ var a: c_int = 1; | |
| 1267 | \\ break :x a; | |
| 1268 | \\ }; | |
| 983 | \\pub extern var fn_ptr: ?extern fn () void; | |
| 984 | , | |
| 985 | \\pub inline fn foo() void { | |
| 986 | \\ return fn_ptr.?(); | |
| 1269 | 987 | \\} |
| 1270 | }); | |
| 1271 | ||
| 1272 | cases.addC("__extension__ cast", | |
| 1273 | \\int foo(void) { | |
| 1274 | \\ return __extension__ 1; | |
| 988 | , | |
| 989 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | |
| 990 | , | |
| 991 | \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { | |
| 992 | \\ return fn_ptr2.?(arg_1, arg_2); | |
| 993 | \\} | |
| 994 | }); | |
| 995 | ||
| 996 | cases.add_2("macros with field targets", | |
| 997 | \\typedef unsigned int GLbitfield; | |
| 998 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | |
| 999 | \\typedef void(*OpenGLProc)(void); | |
| 1000 | \\union OpenGLProcs { | |
| 1001 | \\ OpenGLProc ptr[1]; | |
| 1002 | \\ struct { | |
| 1003 | \\ PFNGLCLEARPROC Clear; | |
| 1004 | \\ } gl; | |
| 1005 | \\}; | |
| 1006 | \\extern union OpenGLProcs glProcs; | |
| 1007 | \\#define glClearUnion glProcs.gl.Clear | |
| 1008 | \\#define glClearPFN PFNGLCLEARPROC | |
| 1009 | , &[_][]const u8{ | |
| 1010 | \\pub const GLbitfield = c_uint; | |
| 1011 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | |
| 1012 | \\pub const OpenGLProc = ?extern fn () void; | |
| 1013 | \\const struct_unnamed_1 = extern struct { | |
| 1014 | \\ Clear: PFNGLCLEARPROC, | |
| 1015 | \\}; | |
| 1016 | \\pub const union_OpenGLProcs = extern union { | |
| 1017 | \\ ptr: [1]OpenGLProc, | |
| 1018 | \\ gl: struct_unnamed_1, | |
| 1019 | \\}; | |
| 1020 | \\pub extern var glProcs: union_OpenGLProcs; | |
| 1021 | , | |
| 1022 | \\pub const glClearPFN = PFNGLCLEARPROC; | |
| 1023 | , | |
| 1024 | \\pub inline fn glClearUnion(arg_2: GLbitfield) void { | |
| 1025 | \\ return glProcs.gl.Clear.?(arg_2); | |
| 1026 | \\} | |
| 1027 | , | |
| 1028 | \\pub const OpenGLProcs = union_OpenGLProcs; | |
| 1029 | }); | |
| 1030 | ||
| 1031 | cases.add_2("macro pointer cast", | |
| 1032 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | |
| 1033 | , &[_][]const u8{ | |
| 1034 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | |
| 1035 | }); | |
| 1036 | ||
| 1037 | cases.add_2("basic macro function", | |
| 1038 | \\extern int c; | |
| 1039 | \\#define BASIC(c) (c*2) | |
| 1040 | , &[_][]const u8{ | |
| 1041 | \\pub extern var c: c_int; | |
| 1042 | , | |
| 1043 | \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) { | |
| 1044 | \\ return c_1 * 2; | |
| 1045 | \\} | |
| 1046 | }); | |
| 1047 | ||
| 1048 | cases.add_2("macro defines string literal with hex", | |
| 1049 | \\#define FOO "aoeu\xab derp" | |
| 1050 | \\#define FOO2 "aoeu\x0007a derp" | |
| 1051 | \\#define FOO_CHAR '\xfF' | |
| 1052 | , &[_][]const u8{ | |
| 1053 | \\pub const FOO = "aoeu\xab derp"; | |
| 1054 | , | |
| 1055 | \\pub const FOO2 = "aoeu\x7a derp"; | |
| 1056 | , | |
| 1057 | \\pub const FOO_CHAR = '\xff'; | |
| 1058 | }); | |
| 1059 | ||
| 1060 | cases.add_2("variable aliasing", | |
| 1061 | \\static long a = 2; | |
| 1062 | \\static long b = 2; | |
| 1063 | \\static int c = 4; | |
| 1064 | \\void foo(char c) { | |
| 1065 | \\ int a; | |
| 1066 | \\ char b = 123; | |
| 1067 | \\ b = (char) a; | |
| 1068 | \\ { | |
| 1069 | \\ int d = 5; | |
| 1070 | \\ } | |
| 1071 | \\ unsigned d = 440; | |
| 1072 | \\} | |
| 1073 | , &[_][]const u8{ | |
| 1074 | \\pub var a: c_long = @as(c_long, 2); | |
| 1075 | \\pub var b: c_long = @as(c_long, 2); | |
| 1076 | \\pub var c: c_int = 4; | |
| 1077 | \\pub export fn foo(_arg_c_1: u8) void { | |
| 1078 | \\ var c_1 = _arg_c_1; | |
| 1079 | \\ var a_2: c_int = undefined; | |
| 1080 | \\ var b_3: u8 = @as(u8, 123); | |
| 1081 | \\ b_3 = @as(u8, a_2); | |
| 1082 | \\ { | |
| 1083 | \\ var d: c_int = 5; | |
| 1084 | \\ } | |
| 1085 | \\ var d: c_uint = @as(c_uint, 440); | |
| 1086 | \\} | |
| 1087 | }); | |
| 1088 | ||
| 1089 | cases.add_2("comma operator", | |
| 1090 | \\int foo(char c) { | |
| 1091 | \\ 2, 4; | |
| 1092 | \\ return 2, 4, 6; | |
| 1093 | \\} | |
| 1094 | , &[_][]const u8{ | |
| 1095 | \\pub export fn foo(_arg_c: u8) c_int { | |
| 1096 | \\ var c = _arg_c; | |
| 1097 | \\ _ = 2; | |
| 1098 | \\ _ = 4; | |
| 1099 | \\ _ = 2; | |
| 1100 | \\ _ = 4; | |
| 1101 | \\ return 6; | |
| 1102 | \\} | |
| 1103 | }); | |
| 1104 | ||
| 1105 | cases.add_2("wors-case assign", | |
| 1106 | \\int foo(char c) { | |
| 1107 | \\ int a; | |
| 1108 | \\ int b; | |
| 1109 | \\ a = b = 2; | |
| 1110 | \\} | |
| 1111 | , &[_][]const u8{ | |
| 1112 | \\pub export fn foo(_arg_c: u8) c_int { | |
| 1113 | \\ var c = _arg_c; | |
| 1114 | \\ var a: c_int = undefined; | |
| 1115 | \\ var b: c_int = undefined; | |
| 1116 | \\ a = blk: { | |
| 1117 | \\ const _tmp_1 = 2; | |
| 1118 | \\ b = _tmp_1; | |
| 1119 | \\ break :blk _tmp_1; | |
| 1120 | \\ }; | |
| 1121 | \\} | |
| 1122 | }); | |
| 1123 | ||
| 1124 | cases.add_2("if statements", | |
| 1125 | \\int foo(char c) { | |
| 1126 | \\ if (2) { | |
| 1127 | \\ int a = 2; | |
| 1128 | \\ } | |
| 1129 | \\ if (2, 5) { | |
| 1130 | \\ int a = 2; | |
| 1131 | \\ } | |
| 1132 | \\} | |
| 1133 | , &[_][]const u8{ | |
| 1134 | \\pub export fn foo(_arg_c: u8) c_int { | |
| 1135 | \\ var c = _arg_c; | |
| 1136 | \\ if (2 != 0) { | |
| 1137 | \\ var a: c_int = 2; | |
| 1138 | \\ } | |
| 1139 | \\ if ((blk: { | |
| 1140 | \\ _ = 2; | |
| 1141 | \\ break :blk 5; | |
| 1142 | \\ }) != 0) { | |
| 1143 | \\ var a: c_int = 2; | |
| 1144 | \\ } | |
| 1145 | \\} | |
| 1146 | }); | |
| 1147 | ||
| 1148 | cases.add_2("while loops", | |
| 1149 | \\int foo() { | |
| 1150 | \\ int a = 5; | |
| 1151 | \\ while (2) | |
| 1152 | \\ a = 2; | |
| 1153 | \\ while (4) { | |
| 1154 | \\ int a = 4; | |
| 1155 | \\ a = 9; | |
| 1156 | \\ return 6, a; | |
| 1157 | \\ } | |
| 1158 | \\ do { | |
| 1159 | \\ int a = 2; | |
| 1160 | \\ a = 12; | |
| 1161 | \\ } while (4); | |
| 1162 | \\ do | |
| 1163 | \\ a = 7; | |
| 1164 | \\ while (4); | |
| 1275 | 1165 | \\} |
| 1276 | 1166 | , &[_][]const u8{ |
| 1277 | 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 | }); |
| 1281 | 1187 | |
| 1282 | cases.addC("bitshift", | |
| 1283 | \\int foo(void) { | |
| 1284 | \\ return (1 << 2) >> 1; | |
| 1188 | cases.add_2("for loops", | |
| 1189 | \\int foo() { | |
| 1190 | \\ for (int i = 2, b = 4; i + 2; i = 2) { | |
| 1191 | \\ int a = 2; | |
| 1192 | \\ a = 6, 5, 7; | |
| 1193 | \\ } | |
| 1194 | \\ char i = 2; | |
| 1285 | 1195 | \\} |
| 1286 | 1196 | , &[_][]const u8{ |
| 1287 | 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 | }); |
| 1291 | 1211 | |
| 1292 | cases.addC("compound assignment operators", | |
| 1293 | \\void foo(void) { | |
| 1294 | \\ int a = 0; | |
| 1295 | \\ a += (a += 1); | |
| 1296 | \\ a -= (a -= 1); | |
| 1297 | \\ a *= (a *= 1); | |
| 1298 | \\ a &= (a &= 1); | |
| 1299 | \\ a |= (a |= 1); | |
| 1300 | \\ a ^= (a ^= 1); | |
| 1301 | \\ a >>= (a >>= 1); | |
| 1302 | \\ a <<= (a <<= 1); | |
| 1212 | cases.add_2("shadowing primitive types", | |
| 1213 | \\unsigned anyerror = 2; | |
| 1214 | , &[_][]const u8{ | |
| 1215 | \\pub export var _anyerror: c_uint = @as(c_uint, 2); | |
| 1216 | }); | |
| 1217 | ||
| 1218 | cases.add_2("floats", | |
| 1219 | \\float a = 3.1415; | |
| 1220 | \\double b = 3.1415; | |
| 1221 | \\int c = 3.1415; | |
| 1222 | \\double d = 3; | |
| 1223 | , &[_][]const u8{ | |
| 1224 | \\pub export var a: f32 = @floatCast(f32, 3.1415); | |
| 1225 | \\pub export var b: f64 = 3.1415; | |
| 1226 | \\pub export var c: c_int = @floatToInt(c_int, 3.1415); | |
| 1227 | \\pub export var d: f64 = @intToFloat(f64, 3); | |
| 1228 | }); | |
| 1229 | ||
| 1230 | cases.add_2("conditional operator", | |
| 1231 | \\int bar(void) { | |
| 1232 | \\ if (2 ? 5 : 5 ? 4 : 6) 2; | |
| 1233 | \\ return 2 ? 5 : 5 ? 4 : 6; | |
| 1303 | 1234 | \\} |
| 1304 | 1235 | , &[_][]const u8{ |
| 1305 | \\pub export fn foo() void { | |
| 1306 | \\ var a: c_int = 0; | |
| 1307 | \\ a += (x: { | |
| 1308 | \\ const _ref = &a; | |
| 1309 | \\ _ref.* = (_ref.* + 1); | |
| 1310 | \\ break :x _ref.*; | |
| 1311 | \\ }); | |
| 1312 | \\ a -= (x: { | |
| 1313 | \\ const _ref = &a; | |
| 1314 | \\ _ref.* = (_ref.* - 1); | |
| 1315 | \\ break :x _ref.*; | |
| 1316 | \\ }); | |
| 1317 | \\ a *= (x: { | |
| 1318 | \\ const _ref = &a; | |
| 1319 | \\ _ref.* = (_ref.* * 1); | |
| 1320 | \\ break :x _ref.*; | |
| 1321 | \\ }); | |
| 1322 | \\ a &= (x: { | |
| 1323 | \\ const _ref = &a; | |
| 1324 | \\ _ref.* = (_ref.* & 1); | |
| 1325 | \\ break :x _ref.*; | |
| 1326 | \\ }); | |
| 1327 | \\ a |= (x: { | |
| 1328 | \\ const _ref = &a; | |
| 1329 | \\ _ref.* = (_ref.* | 1); | |
| 1330 | \\ break :x _ref.*; | |
| 1331 | \\ }); | |
| 1332 | \\ a ^= (x: { | |
| 1333 | \\ const _ref = &a; | |
| 1334 | \\ _ref.* = (_ref.* ^ 1); | |
| 1335 | \\ break :x _ref.*; | |
| 1336 | \\ }); | |
| 1337 | \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: { | |
| 1338 | \\ const _ref = &a; | |
| 1339 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1)); | |
| 1340 | \\ break :x _ref.*; | |
| 1341 | \\ })); | |
| 1342 | \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: { | |
| 1343 | \\ const _ref = &a; | |
| 1344 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1)); | |
| 1345 | \\ break :x _ref.*; | |
| 1346 | \\ })); | |
| 1236 | \\pub export fn bar() c_int { | |
| 1237 | \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2; | |
| 1238 | \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6; | |
| 1239 | \\} | |
| 1240 | }); | |
| 1241 | ||
| 1242 | cases.add_2("switch on int", | |
| 1243 | \\int switch_fn(int i) { | |
| 1244 | \\ int res = 0; | |
| 1245 | \\ switch (i) { | |
| 1246 | \\ case 0: | |
| 1247 | \\ res = 1; | |
| 1248 | \\ case 1 ... 3: | |
| 1249 | \\ res = 2; | |
| 1250 | \\ default: | |
| 1251 | \\ res = 3 * i; | |
| 1252 | \\ break; | |
| 1253 | \\ case 4: | |
| 1254 | \\ res = 5; | |
| 1255 | \\ } | |
| 1256 | \\} | |
| 1257 | , &[_][]const u8{ | |
| 1258 | \\pub export fn switch_fn(_arg_i: c_int) c_int { | |
| 1259 | \\ var i = _arg_i; | |
| 1260 | \\ var res: c_int = 0; | |
| 1261 | \\ __switch: { | |
| 1262 | \\ __case_2: { | |
| 1263 | \\ __default: { | |
| 1264 | \\ __case_1: { | |
| 1265 | \\ __case_0: { | |
| 1266 | \\ switch (i) { | |
| 1267 | \\ 0 => break :__case_0, | |
| 1268 | \\ 1...3 => break :__case_1, | |
| 1269 | \\ else => break :__default, | |
| 1270 | \\ 4 => break :__case_2, | |
| 1271 | \\ } | |
| 1272 | \\ } | |
| 1273 | \\ res = 1; | |
| 1274 | \\ } | |
| 1275 | \\ res = 2; | |
| 1276 | \\ } | |
| 1277 | \\ res = (3 * i); | |
| 1278 | \\ break :__switch; | |
| 1279 | \\ } | |
| 1280 | \\ res = 5; | |
| 1281 | \\ } | |
| 1282 | \\} | |
| 1283 | }); | |
| 1284 | ||
| 1285 | cases.add_2("type referenced struct", | |
| 1286 | \\struct Foo { | |
| 1287 | \\ struct Bar{ | |
| 1288 | \\ int b; | |
| 1289 | \\ }; | |
| 1290 | \\ struct Bar c; | |
| 1291 | \\}; | |
| 1292 | , &[_][]const u8{ | |
| 1293 | \\pub const struct_Bar = extern struct { | |
| 1294 | \\ b: c_int, | |
| 1295 | \\}; | |
| 1296 | \\pub const struct_Foo = extern struct { | |
| 1297 | \\ c: struct_Bar, | |
| 1298 | \\}; | |
| 1299 | }); | |
| 1300 | ||
| 1301 | cases.add_2("undefined array global", | |
| 1302 | \\int array[100] = {}; | |
| 1303 | , &[_][]const u8{ | |
| 1304 | \\pub export var array: [100]c_int = .{0} ** 100; | |
| 1305 | }); | |
| 1306 | ||
| 1307 | cases.add_2("restrict -> noalias", | |
| 1308 | \\void foo(void *restrict bar, void *restrict); | |
| 1309 | , &[_][]const u8{ | |
| 1310 | \\pub extern fn foo(noalias bar: ?*c_void, noalias ?*c_void) void; | |
| 1311 | }); | |
| 1312 | ||
| 1313 | cases.add_2("assign", | |
| 1314 | \\int max(int a) { | |
| 1315 | \\ int tmp; | |
| 1316 | \\ tmp = a; | |
| 1317 | \\ a = tmp; | |
| 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 | }); |
| 1349 | 2433 | |
| 1350 | cases.addC("compound assignment operators unsigned", | |
| 1351 | \\void foo(void) { | |
| 1352 | \\ unsigned a = 0; | |
| 1353 | \\ a += (a += 1); | |
| 1354 | \\ a -= (a -= 1); | |
| 1355 | \\ a *= (a *= 1); | |
| 1356 | \\ a &= (a &= 1); | |
| 1357 | \\ a |= (a |= 1); | |
| 1358 | \\ a ^= (a ^= 1); | |
| 1359 | \\ a >>= (a >>= 1); | |
| 1360 | \\ a <<= (a <<= 1); | |
| 2434 | cases.addC("assign", | |
| 2435 | \\int max(int a) { | |
| 2436 | \\ int tmp; | |
| 2437 | \\ tmp = a; | |
| 2438 | \\ a = tmp; | |
| 1361 | 2439 | \\} |
| 1362 | 2440 | , &[_][]const u8{ |
| 1363 | \\pub export fn foo() void { | |
| 1364 | \\ var a: c_uint = @as(c_uint, 0); | |
| 1365 | \\ a +%= (x: { | |
| 1366 | \\ const _ref = &a; | |
| 1367 | \\ _ref.* = (_ref.* +% @as(c_uint, 1)); | |
| 1368 | \\ break :x _ref.*; | |
| 1369 | \\ }); | |
| 1370 | \\ a -%= (x: { | |
| 1371 | \\ const _ref = &a; | |
| 1372 | \\ _ref.* = (_ref.* -% @as(c_uint, 1)); | |
| 1373 | \\ break :x _ref.*; | |
| 1374 | \\ }); | |
| 1375 | \\ a *%= (x: { | |
| 1376 | \\ const _ref = &a; | |
| 1377 | \\ _ref.* = (_ref.* *% @as(c_uint, 1)); | |
| 1378 | \\ break :x _ref.*; | |
| 1379 | \\ }); | |
| 1380 | \\ a &= (x: { | |
| 1381 | \\ const _ref = &a; | |
| 1382 | \\ _ref.* = (_ref.* & @as(c_uint, 1)); | |
| 1383 | \\ break :x _ref.*; | |
| 1384 | \\ }); | |
| 1385 | \\ a |= (x: { | |
| 1386 | \\ const _ref = &a; | |
| 1387 | \\ _ref.* = (_ref.* | @as(c_uint, 1)); | |
| 1388 | \\ break :x _ref.*; | |
| 1389 | \\ }); | |
| 1390 | \\ a ^= (x: { | |
| 1391 | \\ const _ref = &a; | |
| 1392 | \\ _ref.* = (_ref.* ^ @as(c_uint, 1)); | |
| 1393 | \\ break :x _ref.*; | |
| 1394 | \\ }); | |
| 1395 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: { | |
| 1396 | \\ const _ref = &a; | |
| 1397 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1)); | |
| 1398 | \\ break :x _ref.*; | |
| 1399 | \\ })); | |
| 1400 | \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: { | |
| 1401 | \\ const _ref = &a; | |
| 1402 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1)); | |
| 1403 | \\ break :x _ref.*; | |
| 1404 | \\ })); | |
| 2441 | \\pub export fn max(_arg_a: c_int) c_int { | |
| 2442 | \\ var a = _arg_a; | |
| 2443 | \\ var tmp: c_int = undefined; | |
| 2444 | \\ tmp = a; | |
| 2445 | \\ a = tmp; | |
| 1405 | 2446 | \\} |
| 1406 | 2447 | }); |
| 1407 | 2448 | |
| 1408 | cases.addC("post increment/decrement", | |
| 1409 | \\void foo(void) { | |
| 1410 | \\ int i = 0; | |
| 1411 | \\ unsigned u = 0; | |
| 1412 | \\ i++; | |
| 1413 | \\ i--; | |
| 1414 | \\ u++; | |
| 1415 | \\ u--; | |
| 1416 | \\ i = i++; | |
| 1417 | \\ i = i--; | |
| 1418 | \\ u = u++; | |
| 1419 | \\ u = u--; | |
| 2449 | cases.addC("chaining assign", | |
| 2450 | \\void max(int a) { | |
| 2451 | \\ int b, c; | |
| 2452 | \\ c = b = a; | |
| 1420 | 2453 | \\} |
| 1421 | 2454 | , &[_][]const u8{ |
| 1422 | \\pub export fn foo() void { | |
| 1423 | \\ var i: c_int = 0; | |
| 1424 | \\ var u: c_uint = @as(c_uint, 0); | |
| 1425 | \\ i += 1; | |
| 1426 | \\ i -= 1; | |
| 1427 | \\ u +%= 1; | |
| 1428 | \\ u -%= 1; | |
| 1429 | \\ i = (x: { | |
| 1430 | \\ const _ref = &i; | |
| 1431 | \\ const _tmp = _ref.*; | |
| 1432 | \\ _ref.* += 1; | |
| 1433 | \\ break :x _tmp; | |
| 1434 | \\ }); | |
| 1435 | \\ i = (x: { | |
| 1436 | \\ const _ref = &i; | |
| 1437 | \\ const _tmp = _ref.*; | |
| 1438 | \\ _ref.* -= 1; | |
| 1439 | \\ break :x _tmp; | |
| 1440 | \\ }); | |
| 1441 | \\ u = (x: { | |
| 1442 | \\ const _ref = &u; | |
| 1443 | \\ const _tmp = _ref.*; | |
| 1444 | \\ _ref.* +%= 1; | |
| 1445 | \\ break :x _tmp; | |
| 1446 | \\ }); | |
| 1447 | \\ u = (x: { | |
| 1448 | \\ const _ref = &u; | |
| 1449 | \\ const _tmp = _ref.*; | |
| 1450 | \\ _ref.* -%= 1; | |
| 2455 | \\pub export fn max(a: c_int) void { | |
| 2456 | \\ var b: c_int = undefined; | |
| 2457 | \\ var c: c_int = undefined; | |
| 2458 | \\ c = (x: { | |
| 2459 | \\ const _tmp = a; | |
| 2460 | \\ b = _tmp; | |
| 1451 | 2461 | \\ break :x _tmp; |
| 1452 | 2462 | \\ }); |
| 1453 | 2463 | \\} |
| 1454 | 2464 | }); |
| 1455 | 2465 | |
| 1456 | cases.addC("pre increment/decrement", | |
| 1457 | \\void foo(void) { | |
| 1458 | \\ int i = 0; | |
| 1459 | \\ unsigned u = 0; | |
| 1460 | \\ ++i; | |
| 1461 | \\ --i; | |
| 1462 | \\ ++u; | |
| 1463 | \\ --u; | |
| 1464 | \\ i = ++i; | |
| 1465 | \\ i = --i; | |
| 1466 | \\ u = ++u; | |
| 1467 | \\ u = --u; | |
| 1468 | \\} | |
| 2466 | cases.add("anonymous enum", | |
| 2467 | \\enum { | |
| 2468 | \\ One, | |
| 2469 | \\ Two, | |
| 2470 | \\}; | |
| 1469 | 2471 | , &[_][]const u8{ |
| 1470 | \\pub export fn foo() void { | |
| 1471 | \\ var i: c_int = 0; | |
| 1472 | \\ var u: c_uint = @as(c_uint, 0); | |
| 1473 | \\ i += 1; | |
| 1474 | \\ i -= 1; | |
| 1475 | \\ u +%= 1; | |
| 1476 | \\ u -%= 1; | |
| 1477 | \\ i = (x: { | |
| 1478 | \\ const _ref = &i; | |
| 1479 | \\ _ref.* += 1; | |
| 1480 | \\ break :x _ref.*; | |
| 1481 | \\ }); | |
| 1482 | \\ i = (x: { | |
| 1483 | \\ const _ref = &i; | |
| 1484 | \\ _ref.* -= 1; | |
| 1485 | \\ break :x _ref.*; | |
| 1486 | \\ }); | |
| 1487 | \\ u = (x: { | |
| 1488 | \\ const _ref = &u; | |
| 1489 | \\ _ref.* +%= 1; | |
| 1490 | \\ break :x _ref.*; | |
| 1491 | \\ }); | |
| 1492 | \\ u = (x: { | |
| 1493 | \\ const _ref = &u; | |
| 1494 | \\ _ref.* -%= 1; | |
| 1495 | \\ break :x _ref.*; | |
| 1496 | \\ }); | |
| 1497 | \\} | |
| 2472 | \\pub const One = 0; | |
| 2473 | \\pub const Two = 1; | |
| 1498 | 2474 | }); |
| 1499 | 2475 | |
| 1500 | cases.addC("do loop", | |
| 1501 | \\void foo(void) { | |
| 1502 | \\ int a = 2; | |
| 1503 | \\ do { | |
| 1504 | \\ a--; | |
| 1505 | \\ } while (a != 0); | |
| 1506 | \\ | |
| 1507 | \\ int b = 2; | |
| 1508 | \\ do | |
| 1509 | \\ b--; | |
| 1510 | \\ while (b != 0); | |
| 2476 | cases.addC("c style cast", | |
| 2477 | \\int float_to_int(float a) { | |
| 2478 | \\ return (int)a; | |
| 1511 | 2479 | \\} |
| 1512 | 2480 | , &[_][]const u8{ |
| 1513 | \\pub export fn foo() void { | |
| 1514 | \\ var a: c_int = 2; | |
| 1515 | \\ while (true) { | |
| 1516 | \\ a -= 1; | |
| 1517 | \\ if (!(a != 0)) break; | |
| 1518 | \\ } | |
| 1519 | \\ var b: c_int = 2; | |
| 1520 | \\ while (true) { | |
| 1521 | \\ b -= 1; | |
| 1522 | \\ if (!(b != 0)) break; | |
| 1523 | \\ } | |
| 2481 | \\pub export fn float_to_int(a: f32) c_int { | |
| 2482 | \\ return @as(c_int, a); | |
| 1524 | 2483 | \\} |
| 1525 | 2484 | }); |
| 1526 | 2485 | |
| 1527 | cases.addC("deref function pointer", | |
| 1528 | \\void foo(void) {} | |
| 1529 | \\int baz(void) { return 0; } | |
| 1530 | \\void bar(void) { | |
| 1531 | \\ void(*f)(void) = foo; | |
| 1532 | \\ int(*b)(void) = baz; | |
| 1533 | \\ f(); | |
| 1534 | \\ (*(f))(); | |
| 1535 | \\ foo(); | |
| 1536 | \\ b(); | |
| 1537 | \\ (*(b))(); | |
| 1538 | \\ baz(); | |
| 2486 | cases.addC("comma operator", | |
| 2487 | \\int foo(void) { | |
| 2488 | \\ return 1, 2; | |
| 1539 | 2489 | \\} |
| 1540 | 2490 | , &[_][]const u8{ |
| 1541 | \\pub export fn foo() void {} | |
| 1542 | \\pub export fn baz() c_int { | |
| 1543 | \\ return 0; | |
| 1544 | \\} | |
| 1545 | \\pub export fn bar() void { | |
| 1546 | \\ var f: ?extern fn () void = foo; | |
| 1547 | \\ var b: ?extern fn () c_int = baz; | |
| 1548 | \\ f.?(); | |
| 1549 | \\ f.?(); | |
| 1550 | \\ foo(); | |
| 1551 | \\ _ = b.?(); | |
| 1552 | \\ _ = b.?(); | |
| 1553 | \\ _ = baz(); | |
| 2491 | \\pub export fn foo() c_int { | |
| 2492 | \\ return x: { | |
| 2493 | \\ _ = 1; | |
| 2494 | \\ break :x 2; | |
| 2495 | \\ }; | |
| 1554 | 2496 | \\} |
| 1555 | 2497 | }); |
| 1556 | 2498 | |
| 1557 | cases.addC("normal deref", | |
| 1558 | \\void foo(int *x) { | |
| 1559 | \\ *x = 1; | |
| 2499 | cases.addC("escape sequences", | |
| 2500 | \\const char *escapes() { | |
| 2501 | \\char a = '\'', | |
| 2502 | \\ b = '\\', | |
| 2503 | \\ c = '\a', | |
| 2504 | \\ d = '\b', | |
| 2505 | \\ e = '\f', | |
| 2506 | \\ f = '\n', | |
| 2507 | \\ g = '\r', | |
| 2508 | \\ h = '\t', | |
| 2509 | \\ i = '\v', | |
| 2510 | \\ j = '\0', | |
| 2511 | \\ k = '\"'; | |
| 2512 | \\ return "\'\\\a\b\f\n\r\t\v\0\""; | |
| 1560 | 2513 | \\} |
| 2514 | \\ | |
| 1561 | 2515 | , &[_][]const u8{ |
| 1562 | \\pub export fn foo(x: [*c]c_int) void { | |
| 1563 | \\ x.?.* = 1; | |
| 2516 | \\pub export fn escapes() [*c]const u8 { | |
| 2517 | \\ var a: u8 = @as(u8, '\''); | |
| 2518 | \\ var b: u8 = @as(u8, '\\'); | |
| 2519 | \\ var c: u8 = @as(u8, '\x07'); | |
| 2520 | \\ var d: u8 = @as(u8, '\x08'); | |
| 2521 | \\ var e: u8 = @as(u8, '\x0c'); | |
| 2522 | \\ var f: u8 = @as(u8, '\n'); | |
| 2523 | \\ var g: u8 = @as(u8, '\r'); | |
| 2524 | \\ var h: u8 = @as(u8, '\t'); | |
| 2525 | \\ var i: u8 = @as(u8, '\x0b'); | |
| 2526 | \\ var j: u8 = @as(u8, '\x00'); | |
| 2527 | \\ var k: u8 = @as(u8, '\"'); | |
| 2528 | \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; | |
| 1564 | 2529 | \\} |
| 2530 | \\ | |
| 1565 | 2531 | }); |
| 1566 | 2532 | |
| 1567 | cases.add("simple union", | |
| 1568 | \\union Foo { | |
| 1569 | \\ int x; | |
| 1570 | \\ double y; | |
| 1571 | \\}; | |
| 2533 | cases.addC("do loop", | |
| 2534 | \\void foo(void) { | |
| 2535 | \\ int a = 2; | |
| 2536 | \\ do { | |
| 2537 | \\ a--; | |
| 2538 | \\ } while (a != 0); | |
| 2539 | \\ | |
| 2540 | \\ int b = 2; | |
| 2541 | \\ do | |
| 2542 | \\ b--; | |
| 2543 | \\ while (b != 0); | |
| 2544 | \\} | |
| 1572 | 2545 | , &[_][]const u8{ |
| 1573 | \\pub const union_Foo = extern union { | |
| 1574 | \\ x: c_int, | |
| 1575 | \\ y: f64, | |
| 1576 | \\}; | |
| 1577 | , | |
| 1578 | \\pub const Foo = union_Foo; | |
| 2546 | \\pub export fn foo() void { | |
| 2547 | \\ var a: c_int = 2; | |
| 2548 | \\ while (true) { | |
| 2549 | \\ a -= 1; | |
| 2550 | \\ if (!(a != 0)) break; | |
| 2551 | \\ } | |
| 2552 | \\ var b: c_int = 2; | |
| 2553 | \\ while (true) { | |
| 2554 | \\ b -= 1; | |
| 2555 | \\ if (!(b != 0)) break; | |
| 2556 | \\ } | |
| 2557 | \\} | |
| 1579 | 2558 | }); |
| 1580 | 2559 | |
| 1581 | cases.add("address of operator", | |
| 1582 | \\int foo(void) { | |
| 1583 | \\ int x = 1234; | |
| 1584 | \\ int *ptr = &x; | |
| 1585 | \\ return *ptr; | |
| 2560 | cases.addC("==, !=", | |
| 2561 | \\int max(int a, int b) { | |
| 2562 | \\ if (a == b) | |
| 2563 | \\ return a; | |
| 2564 | \\ if (a != b) | |
| 2565 | \\ return b; | |
| 2566 | \\ return a; | |
| 1586 | 2567 | \\} |
| 1587 | 2568 | , &[_][]const u8{ |
| 1588 | \\pub fn foo() c_int { | |
| 1589 | \\ var x: c_int = 1234; | |
| 1590 | \\ var ptr: [*c]c_int = &x; | |
| 1591 | \\ return ptr.?.*; | |
| 2569 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 2570 | \\ if (a == b) return a; | |
| 2571 | \\ if (a != b) return b; | |
| 2572 | \\ return a; | |
| 1592 | 2573 | \\} |
| 1593 | 2574 | }); |
| 1594 | 2575 | |
| 1595 | cases.add("string literal", | |
| 1596 | \\const char *foo(void) { | |
| 1597 | \\ return "bar"; | |
| 2576 | cases.addC("bitwise binary operators", | |
| 2577 | \\int max(int a, int b) { | |
| 2578 | \\ return (a & b) ^ (a | b); | |
| 1598 | 2579 | \\} |
| 1599 | 2580 | , &[_][]const u8{ |
| 1600 | \\pub fn foo() [*c]const u8 { | |
| 1601 | \\ return "bar"; | |
| 2581 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 2582 | \\ return (a & b) ^ (a | b); | |
| 1602 | 2583 | \\} |
| 1603 | 2584 | }); |
| 1604 | 2585 | |
| 1605 | cases.add("return void", | |
| 1606 | \\void foo(void) { | |
| 1607 | \\ return; | |
| 2586 | cases.addC("statement expression", | |
| 2587 | \\int foo(void) { | |
| 2588 | \\ return ({ | |
| 2589 | \\ int a = 1; | |
| 2590 | \\ a; | |
| 2591 | \\ }); | |
| 1608 | 2592 | \\} |
| 1609 | 2593 | , &[_][]const u8{ |
| 1610 | \\pub fn foo() void { | |
| 1611 | \\ return; | |
| 2594 | \\pub export fn foo() c_int { | |
| 2595 | \\ return x: { | |
| 2596 | \\ var a: c_int = 1; | |
| 2597 | \\ break :x a; | |
| 2598 | \\ }; | |
| 1612 | 2599 | \\} |
| 1613 | 2600 | }); |
| 1614 | 2601 | |
| 1615 | cases.add("for loop", | |
| 1616 | \\void foo(void) { | |
| 1617 | \\ for (int i = 0; i < 10; i += 1) { } | |
| 2602 | cases.addC("field access expression", | |
| 2603 | \\struct Foo { | |
| 2604 | \\ int field; | |
| 2605 | \\}; | |
| 2606 | \\int read_field(struct Foo *foo) { | |
| 2607 | \\ return foo->field; | |
| 1618 | 2608 | \\} |
| 1619 | 2609 | , &[_][]const u8{ |
| 1620 | \\pub fn foo() void { | |
| 1621 | \\ { | |
| 1622 | \\ var i: c_int = 0; | |
| 1623 | \\ while (i < 10) : (i += 1) {} | |
| 1624 | \\ } | |
| 2610 | \\pub const struct_Foo = extern struct { | |
| 2611 | \\ field: c_int, | |
| 2612 | \\}; | |
| 2613 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { | |
| 2614 | \\ return foo.*.field; | |
| 1625 | 2615 | \\} |
| 1626 | 2616 | }); |
| 1627 | 2617 | |
| 1628 | cases.add("empty for loop", | |
| 1629 | \\void foo(void) { | |
| 1630 | \\ for (;;) { } | |
| 2618 | cases.addC("array access", | |
| 2619 | \\int array[100]; | |
| 2620 | \\int foo(int index) { | |
| 2621 | \\ return array[index]; | |
| 1631 | 2622 | \\} |
| 1632 | 2623 | , &[_][]const u8{ |
| 1633 | \\pub fn foo() void { | |
| 1634 | \\ while (true) {} | |
| 2624 | \\pub var array: [100]c_int = undefined; | |
| 2625 | \\pub export fn foo(index: c_int) c_int { | |
| 2626 | \\ return array[index]; | |
| 1635 | 2627 | \\} |
| 1636 | 2628 | }); |
| 1637 | 2629 | |
| 1638 | cases.add("break statement", | |
| 1639 | \\void foo(void) { | |
| 1640 | \\ for (;;) { | |
| 1641 | \\ break; | |
| 1642 | \\ } | |
| 2630 | cases.addC("logical and, logical or", | |
| 2631 | \\int max(int a, int b) { | |
| 2632 | \\ if (a < b || a == b) | |
| 2633 | \\ return b; | |
| 2634 | \\ if (a >= b && a == b) | |
| 2635 | \\ return a; | |
| 2636 | \\ return a; | |
| 1643 | 2637 | \\} |
| 1644 | 2638 | , &[_][]const u8{ |
| 1645 | \\pub fn foo() void { | |
| 1646 | \\ while (true) { | |
| 1647 | \\ break; | |
| 1648 | \\ } | |
| 2639 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 2640 | \\ if ((a < b) or (a == b)) return b; | |
| 2641 | \\ if ((a >= b) and (a == b)) return a; | |
| 2642 | \\ return a; | |
| 1649 | 2643 | \\} |
| 1650 | 2644 | }); |
| 1651 | 2645 | |
| 1652 | cases.add("continue statement", | |
| 1653 | \\void foo(void) { | |
| 1654 | \\ for (;;) { | |
| 1655 | \\ continue; | |
| 1656 | \\ } | |
| 2646 | cases.addC("if statement", | |
| 2647 | \\int max(int a, int b) { | |
| 2648 | \\ if (a < b) | |
| 2649 | \\ return b; | |
| 2650 | \\ | |
| 2651 | \\ if (a < b) | |
| 2652 | \\ return b; | |
| 2653 | \\ else | |
| 2654 | \\ return a; | |
| 2655 | \\ | |
| 2656 | \\ if (a < b) ; else ; | |
| 1657 | 2657 | \\} |
| 1658 | 2658 | , &[_][]const u8{ |
| 1659 | \\pub fn foo() void { | |
| 1660 | \\ while (true) { | |
| 1661 | \\ continue; | |
| 1662 | \\ } | |
| 2659 | \\pub export fn max(a: c_int, b: c_int) c_int { | |
| 2660 | \\ if (a < b) return b; | |
| 2661 | \\ if (a < b) return b else return a; | |
| 2662 | \\ if (a < b) {} else {} | |
| 1663 | 2663 | \\} |
| 1664 | 2664 | }); |
| 1665 | 2665 | |
| ... | ... | @@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1683 | 2683 | \\} |
| 1684 | 2684 | }); |
| 1685 | 2685 | |
| 1686 | cases.add("pointer casting", | |
| 1687 | \\float *ptrcast(int *a) { | |
| 1688 | \\ return (float *)a; | |
| 2686 | cases.add("if on non-bool", | |
| 2687 | \\enum SomeEnum { A, B, C }; | |
| 2688 | \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { | |
| 2689 | \\ if (a) return 0; | |
| 2690 | \\ if (b) return 1; | |
| 2691 | \\ if (c) return 2; | |
| 2692 | \\ if (d) return 3; | |
| 2693 | \\ return 4; | |
| 1689 | 2694 | \\} |
| 1690 | 2695 | , &[_][]const u8{ |
| 1691 | \\fn ptrcast(a: [*c]c_int) [*c]f32 { | |
| 1692 | \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); | |
| 2696 | \\pub const A = enum_SomeEnum.A; | |
| 2697 | \\pub const B = enum_SomeEnum.B; | |
| 2698 | \\pub const C = enum_SomeEnum.C; | |
| 2699 | \\pub const enum_SomeEnum = extern enum { | |
| 2700 | \\ A, | |
| 2701 | \\ B, | |
| 2702 | \\ C, | |
| 2703 | \\}; | |
| 2704 | \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { | |
| 2705 | \\ if (a != 0) return 0; | |
| 2706 | \\ if (b != 0) return 1; | |
| 2707 | \\ if (c != null) return 2; | |
| 2708 | \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3; | |
| 2709 | \\ return 4; | |
| 1693 | 2710 | \\} |
| 1694 | 2711 | }); |
| 1695 | 2712 | |
| 1696 | cases.add("bin not", | |
| 1697 | \\int foo(int x) { | |
| 1698 | \\ return ~x; | |
| 2713 | cases.addAllowWarnings("simple data types", | |
| 2714 | \\#include <stdint.h> | |
| 2715 | \\int foo(char a, unsigned char b, signed char c); | |
| 2716 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 2717 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 2718 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 2719 | , &[_][]const u8{ | |
| 2720 | \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; | |
| 2721 | , | |
| 2722 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; | |
| 2723 | , | |
| 2724 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; | |
| 2725 | }); | |
| 2726 | ||
| 2727 | cases.addC("simple function", | |
| 2728 | \\int abs(int a) { | |
| 2729 | \\ return a < 0 ? -a : a; | |
| 1699 | 2730 | \\} |
| 1700 | 2731 | , &[_][]const u8{ |
| 1701 | \\pub fn foo(x: c_int) c_int { | |
| 1702 | \\ return ~x; | |
| 2732 | \\pub export fn abs(a: c_int) c_int { | |
| 2733 | \\ return if (a < 0) -a else a; | |
| 1703 | 2734 | \\} |
| 1704 | 2735 | }); |
| 1705 | 2736 | |
| 1706 | cases.add("bool not", | |
| 1707 | \\int foo(int a, float b, void *c) { | |
| 1708 | \\ return !(a == 0); | |
| 1709 | \\ return !a; | |
| 1710 | \\ return !b; | |
| 1711 | \\ return !c; | |
| 2737 | cases.addC("post increment", | |
| 2738 | \\unsigned foo1(unsigned a) { | |
| 2739 | \\ a++; | |
| 2740 | \\ return a; | |
| 2741 | \\} | |
| 2742 | \\int foo2(int a) { | |
| 2743 | \\ a++; | |
| 2744 | \\ return a; | |
| 2745 | \\} | |
| 2746 | , &[_][]const u8{ | |
| 2747 | \\pub export fn foo1(_arg_a: c_uint) c_uint { | |
| 2748 | \\ var a = _arg_a; | |
| 2749 | \\ a +%= 1; | |
| 2750 | \\ return a; | |
| 2751 | \\} | |
| 2752 | \\pub export fn foo2(_arg_a: c_int) c_int { | |
| 2753 | \\ var a = _arg_a; | |
| 2754 | \\ a += 1; | |
| 2755 | \\ return a; | |
| 2756 | \\} | |
| 2757 | }); | |
| 2758 | ||
| 2759 | cases.addC("deref function pointer", | |
| 2760 | \\void foo(void) {} | |
| 2761 | \\int baz(void) { return 0; } | |
| 2762 | \\void bar(void) { | |
| 2763 | \\ void(*f)(void) = foo; | |
| 2764 | \\ int(*b)(void) = baz; | |
| 2765 | \\ f(); | |
| 2766 | \\ (*(f))(); | |
| 2767 | \\ foo(); | |
| 2768 | \\ b(); | |
| 2769 | \\ (*(b))(); | |
| 2770 | \\ baz(); | |
| 2771 | \\} | |
| 2772 | , &[_][]const u8{ | |
| 2773 | \\pub export fn foo() void {} | |
| 2774 | \\pub export fn baz() c_int { | |
| 2775 | \\ return 0; | |
| 2776 | \\} | |
| 2777 | \\pub export fn bar() void { | |
| 2778 | \\ var f: ?extern fn () void = foo; | |
| 2779 | \\ var b: ?extern fn () c_int = baz; | |
| 2780 | \\ f.?(); | |
| 2781 | \\ f.?(); | |
| 2782 | \\ foo(); | |
| 2783 | \\ _ = b.?(); | |
| 2784 | \\ _ = b.?(); | |
| 2785 | \\ _ = baz(); | |
| 2786 | \\} | |
| 2787 | }); | |
| 2788 | ||
| 2789 | cases.addC("pre increment/decrement", | |
| 2790 | \\void foo(void) { | |
| 2791 | \\ int i = 0; | |
| 2792 | \\ unsigned u = 0; | |
| 2793 | \\ ++i; | |
| 2794 | \\ --i; | |
| 2795 | \\ ++u; | |
| 2796 | \\ --u; | |
| 2797 | \\ i = ++i; | |
| 2798 | \\ i = --i; | |
| 2799 | \\ u = ++u; | |
| 2800 | \\ u = --u; | |
| 1712 | 2801 | \\} |
| 1713 | 2802 | , &[_][]const u8{ |
| 1714 | \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { | |
| 1715 | \\ return !(a == 0); | |
| 1716 | \\ return !(a != 0); | |
| 1717 | \\ return !(b != 0); | |
| 1718 | \\ return !(c != null); | |
| 2803 | \\pub export fn foo() void { | |
| 2804 | \\ var i: c_int = 0; | |
| 2805 | \\ var u: c_uint = @as(c_uint, 0); | |
| 2806 | \\ i += 1; | |
| 2807 | \\ i -= 1; | |
| 2808 | \\ u +%= 1; | |
| 2809 | \\ u -%= 1; | |
| 2810 | \\ i = (x: { | |
| 2811 | \\ const _ref = &i; | |
| 2812 | \\ _ref.* += 1; | |
| 2813 | \\ break :x _ref.*; | |
| 2814 | \\ }); | |
| 2815 | \\ i = (x: { | |
| 2816 | \\ const _ref = &i; | |
| 2817 | \\ _ref.* -= 1; | |
| 2818 | \\ break :x _ref.*; | |
| 2819 | \\ }); | |
| 2820 | \\ u = (x: { | |
| 2821 | \\ const _ref = &u; | |
| 2822 | \\ _ref.* +%= 1; | |
| 2823 | \\ break :x _ref.*; | |
| 2824 | \\ }); | |
| 2825 | \\ u = (x: { | |
| 2826 | \\ const _ref = &u; | |
| 2827 | \\ _ref.* -%= 1; | |
| 2828 | \\ break :x _ref.*; | |
| 2829 | \\ }); | |
| 1719 | 2830 | \\} |
| 1720 | 2831 | }); |
| 1721 | 2832 | |
| 1722 | cases.add("primitive types included in defined symbols", | |
| 1723 | \\int foo(int u32) { | |
| 1724 | \\ return u32; | |
| 2833 | cases.addC("shift right assign", | |
| 2834 | \\int log2(unsigned a) { | |
| 2835 | \\ int i = 0; | |
| 2836 | \\ while (a > 0) { | |
| 2837 | \\ a >>= 1; | |
| 2838 | \\ } | |
| 2839 | \\ return i; | |
| 1725 | 2840 | \\} |
| 1726 | 2841 | , &[_][]const u8{ |
| 1727 | \\pub fn foo(u32_0: c_int) c_int { | |
| 1728 | \\ return u32_0; | |
| 2842 | \\pub export fn log2(_arg_a: c_uint) c_int { | |
| 2843 | \\ var a = _arg_a; | |
| 2844 | \\ var i: c_int = 0; | |
| 2845 | \\ while (a > @as(c_uint, 0)) { | |
| 2846 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1); | |
| 2847 | \\ } | |
| 2848 | \\ return i; | |
| 1729 | 2849 | \\} |
| 1730 | 2850 | }); |
| 1731 | 2851 | |
| 1732 | cases.add("if on non-bool", | |
| 1733 | \\enum SomeEnum { A, B, C }; | |
| 1734 | \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { | |
| 1735 | \\ if (a) return 0; | |
| 1736 | \\ if (b) return 1; | |
| 1737 | \\ if (c) return 2; | |
| 1738 | \\ if (d) return 3; | |
| 1739 | \\ return 4; | |
| 2852 | cases.addC("shift right assign with a fixed size type", | |
| 2853 | \\#include <stdint.h> | |
| 2854 | \\int log2(uint32_t a) { | |
| 2855 | \\ int i = 0; | |
| 2856 | \\ while (a > 0) { | |
| 2857 | \\ a >>= 1; | |
| 2858 | \\ } | |
| 2859 | \\ return i; | |
| 1740 | 2860 | \\} |
| 1741 | 2861 | , &[_][]const u8{ |
| 1742 | \\pub const A = enum_SomeEnum.A; | |
| 1743 | \\pub const B = enum_SomeEnum.B; | |
| 1744 | \\pub const C = enum_SomeEnum.C; | |
| 1745 | \\pub const enum_SomeEnum = extern enum { | |
| 1746 | \\ A, | |
| 1747 | \\ B, | |
| 1748 | \\ C, | |
| 1749 | \\}; | |
| 1750 | \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { | |
| 1751 | \\ if (a != 0) return 0; | |
| 1752 | \\ if (b != 0) return 1; | |
| 1753 | \\ if (c != null) return 2; | |
| 1754 | \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3; | |
| 1755 | \\ return 4; | |
| 2862 | \\pub export fn log2(_arg_a: u32) c_int { | |
| 2863 | \\ var a = _arg_a; | |
| 2864 | \\ var i: c_int = 0; | |
| 2865 | \\ while (a > @as(c_uint, 0)) { | |
| 2866 | \\ a >>= @as(u5, 1); | |
| 2867 | \\ } | |
| 2868 | \\ return i; | |
| 1756 | 2869 | \\} |
| 1757 | 2870 | }); |
| 1758 | 2871 | |
| 1759 | cases.add("while on non-bool", | |
| 1760 | \\int while_none_bool(int a, float b, void *c) { | |
| 1761 | \\ while (a) return 0; | |
| 1762 | \\ while (b) return 1; | |
| 1763 | \\ while (c) return 2; | |
| 1764 | \\ return 3; | |
| 2872 | cases.addC("compound assignment operators", | |
| 2873 | \\void foo(void) { | |
| 2874 | \\ int a = 0; | |
| 2875 | \\ a += (a += 1); | |
| 2876 | \\ a -= (a -= 1); | |
| 2877 | \\ a *= (a *= 1); | |
| 2878 | \\ a &= (a &= 1); | |
| 2879 | \\ a |= (a |= 1); | |
| 2880 | \\ a ^= (a ^= 1); | |
| 2881 | \\ a >>= (a >>= 1); | |
| 2882 | \\ a <<= (a <<= 1); | |
| 1765 | 2883 | \\} |
| 1766 | 2884 | , &[_][]const u8{ |
| 1767 | \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | |
| 1768 | \\ while (a != 0) return 0; | |
| 1769 | \\ while (b != 0) return 1; | |
| 1770 | \\ while (c != null) return 2; | |
| 1771 | \\ return 3; | |
| 2885 | \\pub export fn foo() void { | |
| 2886 | \\ var a: c_int = 0; | |
| 2887 | \\ a += (x: { | |
| 2888 | \\ const _ref = &a; | |
| 2889 | \\ _ref.* = (_ref.* + 1); | |
| 2890 | \\ break :x _ref.*; | |
| 2891 | \\ }); | |
| 2892 | \\ a -= (x: { | |
| 2893 | \\ const _ref = &a; | |
| 2894 | \\ _ref.* = (_ref.* - 1); | |
| 2895 | \\ break :x _ref.*; | |
| 2896 | \\ }); | |
| 2897 | \\ a *= (x: { | |
| 2898 | \\ const _ref = &a; | |
| 2899 | \\ _ref.* = (_ref.* * 1); | |
| 2900 | \\ break :x _ref.*; | |
| 2901 | \\ }); | |
| 2902 | \\ a &= (x: { | |
| 2903 | \\ const _ref = &a; | |
| 2904 | \\ _ref.* = (_ref.* & 1); | |
| 2905 | \\ break :x _ref.*; | |
| 2906 | \\ }); | |
| 2907 | \\ a |= (x: { | |
| 2908 | \\ const _ref = &a; | |
| 2909 | \\ _ref.* = (_ref.* | 1); | |
| 2910 | \\ break :x _ref.*; | |
| 2911 | \\ }); | |
| 2912 | \\ a ^= (x: { | |
| 2913 | \\ const _ref = &a; | |
| 2914 | \\ _ref.* = (_ref.* ^ 1); | |
| 2915 | \\ break :x _ref.*; | |
| 2916 | \\ }); | |
| 2917 | \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: { | |
| 2918 | \\ const _ref = &a; | |
| 2919 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1)); | |
| 2920 | \\ break :x _ref.*; | |
| 2921 | \\ })); | |
| 2922 | \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: { | |
| 2923 | \\ const _ref = &a; | |
| 2924 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1)); | |
| 2925 | \\ break :x _ref.*; | |
| 2926 | \\ })); | |
| 1772 | 2927 | \\} |
| 1773 | 2928 | }); |
| 1774 | 2929 | |
| 1775 | cases.add("for on non-bool", | |
| 1776 | \\int for_none_bool(int a, float b, void *c) { | |
| 1777 | \\ for (;a;) return 0; | |
| 1778 | \\ for (;b;) return 1; | |
| 1779 | \\ for (;c;) return 2; | |
| 1780 | \\ return 3; | |
| 2930 | cases.addC("compound assignment operators unsigned", | |
| 2931 | \\void foo(void) { | |
| 2932 | \\ unsigned a = 0; | |
| 2933 | \\ a += (a += 1); | |
| 2934 | \\ a -= (a -= 1); | |
| 2935 | \\ a *= (a *= 1); | |
| 2936 | \\ a &= (a &= 1); | |
| 2937 | \\ a |= (a |= 1); | |
| 2938 | \\ a ^= (a ^= 1); | |
| 2939 | \\ a >>= (a >>= 1); | |
| 2940 | \\ a <<= (a <<= 1); | |
| 1781 | 2941 | \\} |
| 1782 | 2942 | , &[_][]const u8{ |
| 1783 | \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | |
| 1784 | \\ while (a != 0) return 0; | |
| 1785 | \\ while (b != 0) return 1; | |
| 1786 | \\ while (c != null) return 2; | |
| 1787 | \\ return 3; | |
| 2943 | \\pub export fn foo() void { | |
| 2944 | \\ var a: c_uint = @as(c_uint, 0); | |
| 2945 | \\ a +%= (x: { | |
| 2946 | \\ const _ref = &a; | |
| 2947 | \\ _ref.* = (_ref.* +% @as(c_uint, 1)); | |
| 2948 | \\ break :x _ref.*; | |
| 2949 | \\ }); | |
| 2950 | \\ a -%= (x: { | |
| 2951 | \\ const _ref = &a; | |
| 2952 | \\ _ref.* = (_ref.* -% @as(c_uint, 1)); | |
| 2953 | \\ break :x _ref.*; | |
| 2954 | \\ }); | |
| 2955 | \\ a *%= (x: { | |
| 2956 | \\ const _ref = &a; | |
| 2957 | \\ _ref.* = (_ref.* *% @as(c_uint, 1)); | |
| 2958 | \\ break :x _ref.*; | |
| 2959 | \\ }); | |
| 2960 | \\ a &= (x: { | |
| 2961 | \\ const _ref = &a; | |
| 2962 | \\ _ref.* = (_ref.* & @as(c_uint, 1)); | |
| 2963 | \\ break :x _ref.*; | |
| 2964 | \\ }); | |
| 2965 | \\ a |= (x: { | |
| 2966 | \\ const _ref = &a; | |
| 2967 | \\ _ref.* = (_ref.* | @as(c_uint, 1)); | |
| 2968 | \\ break :x _ref.*; | |
| 2969 | \\ }); | |
| 2970 | \\ a ^= (x: { | |
| 2971 | \\ const _ref = &a; | |
| 2972 | \\ _ref.* = (_ref.* ^ @as(c_uint, 1)); | |
| 2973 | \\ break :x _ref.*; | |
| 2974 | \\ }); | |
| 2975 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: { | |
| 2976 | \\ const _ref = &a; | |
| 2977 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1)); | |
| 2978 | \\ break :x _ref.*; | |
| 2979 | \\ })); | |
| 2980 | \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: { | |
| 2981 | \\ const _ref = &a; | |
| 2982 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1)); | |
| 2983 | \\ break :x _ref.*; | |
| 2984 | \\ })); | |
| 1788 | 2985 | \\} |
| 1789 | 2986 | }); |
| 1790 | 2987 | |
| 1791 | cases.add("switch on int", | |
| 1792 | \\int switch_fn(int i) { | |
| 1793 | \\ int res = 0; | |
| 1794 | \\ switch (i) { | |
| 1795 | \\ case 0: | |
| 1796 | \\ res = 1; | |
| 1797 | \\ case 1: | |
| 1798 | \\ res = 2; | |
| 1799 | \\ default: | |
| 1800 | \\ res = 3 * i; | |
| 1801 | \\ break; | |
| 1802 | \\ case 2: | |
| 1803 | \\ res = 5; | |
| 1804 | \\ } | |
| 2988 | cases.addC("post increment/decrement", | |
| 2989 | \\void foo(void) { | |
| 2990 | \\ int i = 0; | |
| 2991 | \\ unsigned u = 0; | |
| 2992 | \\ i++; | |
| 2993 | \\ i--; | |
| 2994 | \\ u++; | |
| 2995 | \\ u--; | |
| 2996 | \\ i = i++; | |
| 2997 | \\ i = i--; | |
| 2998 | \\ u = u++; | |
| 2999 | \\ u = u--; | |
| 1805 | 3000 | \\} |
| 1806 | 3001 | , &[_][]const u8{ |
| 1807 | \\pub fn switch_fn(i: c_int) c_int { | |
| 1808 | \\ var res: c_int = 0; | |
| 1809 | \\ __switch: { | |
| 1810 | \\ __case_2: { | |
| 1811 | \\ __default: { | |
| 1812 | \\ __case_1: { | |
| 1813 | \\ __case_0: { | |
| 1814 | \\ switch (i) { | |
| 1815 | \\ 0 => break :__case_0, | |
| 1816 | \\ 1 => break :__case_1, | |
| 1817 | \\ else => break :__default, | |
| 1818 | \\ 2 => break :__case_2, | |
| 1819 | \\ } | |
| 1820 | \\ } | |
| 1821 | \\ res = 1; | |
| 1822 | \\ } | |
| 1823 | \\ res = 2; | |
| 1824 | \\ } | |
| 1825 | \\ res = (3 * i); | |
| 1826 | \\ break :__switch; | |
| 1827 | \\ } | |
| 1828 | \\ res = 5; | |
| 1829 | \\ } | |
| 3002 | \\pub export fn foo() void { | |
| 3003 | \\ var i: c_int = 0; | |
| 3004 | \\ var u: c_uint = @as(c_uint, 0); | |
| 3005 | \\ i += 1; | |
| 3006 | \\ i -= 1; | |
| 3007 | \\ u +%= 1; | |
| 3008 | \\ u -%= 1; | |
| 3009 | \\ i = (x: { | |
| 3010 | \\ const _ref = &i; | |
| 3011 | \\ const _tmp = _ref.*; | |
| 3012 | \\ _ref.* += 1; | |
| 3013 | \\ break :x _tmp; | |
| 3014 | \\ }); | |
| 3015 | \\ i = (x: { | |
| 3016 | \\ const _ref = &i; | |
| 3017 | \\ const _tmp = _ref.*; | |
| 3018 | \\ _ref.* -= 1; | |
| 3019 | \\ break :x _tmp; | |
| 3020 | \\ }); | |
| 3021 | \\ u = (x: { | |
| 3022 | \\ const _ref = &u; | |
| 3023 | \\ const _tmp = _ref.*; | |
| 3024 | \\ _ref.* +%= 1; | |
| 3025 | \\ break :x _tmp; | |
| 3026 | \\ }); | |
| 3027 | \\ u = (x: { | |
| 3028 | \\ const _ref = &u; | |
| 3029 | \\ const _tmp = _ref.*; | |
| 3030 | \\ _ref.* -%= 1; | |
| 3031 | \\ break :x _tmp; | |
| 3032 | \\ }); | |
| 1830 | 3033 | \\} |
| 1831 | 3034 | }); |
| 1832 | 3035 | |
| ... | ... | @@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1885 | 3088 | \\} |
| 1886 | 3089 | }); |
| 1887 | 3090 | |
| 1888 | cases.addC("pointer conversion with different alignment", | |
| 1889 | \\void test_ptr_cast() { | |
| 1890 | \\ void *p; | |
| 1891 | \\ { | |
| 1892 | \\ char *to_char = (char *)p; | |
| 1893 | \\ short *to_short = (short *)p; | |
| 1894 | \\ int *to_int = (int *)p; | |
| 1895 | \\ long long *to_longlong = (long long *)p; | |
| 1896 | \\ } | |
| 1897 | \\ { | |
| 1898 | \\ char *to_char = p; | |
| 1899 | \\ short *to_short = p; | |
| 1900 | \\ int *to_int = p; | |
| 1901 | \\ long long *to_longlong = p; | |
| 1902 | \\ } | |
| 1903 | \\} | |
| 1904 | , &[_][]const u8{ | |
| 1905 | \\pub export fn test_ptr_cast() void { | |
| 1906 | \\ var p: ?*c_void = undefined; | |
| 1907 | \\ { | |
| 1908 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | |
| 1909 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | |
| 1910 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | |
| 1911 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | |
| 1912 | \\ } | |
| 1913 | \\ { | |
| 1914 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | |
| 1915 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | |
| 1916 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | |
| 1917 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | |
| 1918 | \\ } | |
| 1919 | \\} | |
| 1920 | }); | |
| 1921 | ||
| 1922 | cases.addC("escape sequences", | |
| 1923 | \\const char *escapes() { | |
| 1924 | \\char a = '\'', | |
| 1925 | \\ b = '\\', | |
| 1926 | \\ c = '\a', | |
| 1927 | \\ d = '\b', | |
| 1928 | \\ e = '\f', | |
| 1929 | \\ f = '\n', | |
| 1930 | \\ g = '\r', | |
| 1931 | \\ h = '\t', | |
| 1932 | \\ i = '\v', | |
| 1933 | \\ j = '\0', | |
| 1934 | \\ k = '\"'; | |
| 1935 | \\ return "\'\\\a\b\f\n\r\t\v\0\""; | |
| 3091 | cases.addC("function call", | |
| 3092 | \\static void bar(void) { } | |
| 3093 | \\void foo(int *(baz)(void)) { | |
| 3094 | \\ bar(); | |
| 3095 | \\ baz(); | |
| 1936 | 3096 | \\} |
| 1937 | \\ | |
| 1938 | 3097 | , &[_][]const u8{ |
| 1939 | \\pub export fn escapes() [*c]const u8 { | |
| 1940 | \\ var a: u8 = @as(u8, '\''); | |
| 1941 | \\ var b: u8 = @as(u8, '\\'); | |
| 1942 | \\ var c: u8 = @as(u8, '\x07'); | |
| 1943 | \\ var d: u8 = @as(u8, '\x08'); | |
| 1944 | \\ var e: u8 = @as(u8, '\x0c'); | |
| 1945 | \\ var f: u8 = @as(u8, '\n'); | |
| 1946 | \\ var g: u8 = @as(u8, '\r'); | |
| 1947 | \\ var h: u8 = @as(u8, '\t'); | |
| 1948 | \\ var i: u8 = @as(u8, '\x0b'); | |
| 1949 | \\ var j: u8 = @as(u8, '\x00'); | |
| 1950 | \\ var k: u8 = @as(u8, '\"'); | |
| 1951 | \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; | |
| 3098 | \\pub fn bar() void {} | |
| 3099 | \\pub export fn foo(baz: ?extern fn () [*c]c_int) void { | |
| 3100 | \\ bar(); | |
| 3101 | \\ _ = baz.?(); | |
| 1952 | 3102 | \\} |
| 1953 | \\ | |
| 1954 | 3103 | }); |
| 1955 | 3104 | |
| 1956 | if (builtin.os != builtin.Os.windows) { | |
| 1957 | // sysv_abi not currently supported on windows | |
| 1958 | cases.add("Macro qualified functions", | |
| 1959 | \\void __attribute__((sysv_abi)) foo(void); | |
| 1960 | , &[_][]const u8{ | |
| 1961 | \\pub extern fn foo() void; | |
| 1962 | }); | |
| 1963 | } | |
| 1964 | ||
| 1965 | /////////////// Cases for only stage1 because stage2 behavior is better //////////////// | |
| 1966 | cases.addC("Parameterless function prototypes", | |
| 1967 | \\void foo() {} | |
| 1968 | \\void bar(void) {} | |
| 3105 | cases.add("macro defines string literal with hex", | |
| 3106 | \\#define FOO "aoeu\xab derp" | |
| 3107 | \\#define FOO2 "aoeu\x0007a derp" | |
| 3108 | \\#define FOO_CHAR '\xfF' | |
| 1969 | 3109 | , &[_][]const u8{ |
| 1970 | \\pub export fn foo() void {} | |
| 1971 | \\pub export fn bar() void {} | |
| 3110 | \\pub const FOO = "aoeu\xab derp"; | |
| 3111 | , | |
| 3112 | \\pub const FOO2 = "aoeuz derp"; | |
| 3113 | , | |
| 3114 | \\pub const FOO_CHAR = 255; | |
| 1972 | 3115 | }); |
| 1973 | 3116 | |
| 1974 | cases.add("#define a char literal", | |
| 1975 | \\#define A_CHAR 'a' | |
| 3117 | cases.add("macro defines string literal with octal", | |
| 3118 | \\#define FOO "aoeu\023 derp" | |
| 3119 | \\#define FOO2 "aoeu\0234 derp" | |
| 3120 | \\#define FOO_CHAR '\077' | |
| 1976 | 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 | }); |
| 1979 | 3128 | |
| 1980 | cases.add("generate inline func for #define global extern fn", | |
| 1981 | \\extern void (*fn_ptr)(void); | |
| 1982 | \\#define foo fn_ptr | |
| 1983 | \\ | |
| 1984 | \\extern char (*fn_ptr2)(int, float); | |
| 1985 | \\#define bar fn_ptr2 | |
| 3129 | cases.add("enums", | |
| 3130 | \\enum Foo { | |
| 3131 | \\ FooA, | |
| 3132 | \\ FooB, | |
| 3133 | \\ Foo1, | |
| 3134 | \\}; | |
| 1986 | 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 { | |
| 1990 | \\ return fn_ptr.?(); | |
| 1991 | \\} | |
| 3142 | \\pub const FooA = enum_Foo.A; | |
| 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 { | |
| 1996 | \\ return fn_ptr2.?(arg0, arg1); | |
| 1997 | \\} | |
| 1998 | }); | |
| 1999 | cases.add("comment after integer literal", | |
| 2000 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2001 | , &[_][]const u8{ | |
| 2002 | \\pub const SDL_INIT_VIDEO = 32; | |
| 2003 | }); | |
| 2004 | ||
| 2005 | cases.add("u integer suffix after hex literal", | |
| 2006 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2007 | , &[_][]const u8{ | |
| 2008 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); | |
| 2009 | }); | |
| 2010 | ||
| 2011 | cases.add("l integer suffix after hex literal", | |
| 2012 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2013 | , &[_][]const u8{ | |
| 2014 | \\pub const SDL_INIT_VIDEO = @as(c_long, 32); | |
| 2015 | }); | |
| 2016 | ||
| 2017 | cases.add("ul integer suffix after hex literal", | |
| 2018 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2019 | , &[_][]const u8{ | |
| 2020 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | |
| 2021 | }); | |
| 2022 | ||
| 2023 | cases.add("lu integer suffix after hex literal", | |
| 2024 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2025 | , &[_][]const u8{ | |
| 2026 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | |
| 2027 | }); | |
| 2028 | ||
| 2029 | cases.add("ll integer suffix after hex literal", | |
| 2030 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2031 | , &[_][]const u8{ | |
| 2032 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); | |
| 2033 | }); | |
| 2034 | ||
| 2035 | cases.add("ull integer suffix after hex literal", | |
| 2036 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2037 | , &[_][]const u8{ | |
| 2038 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | |
| 2039 | }); | |
| 2040 | ||
| 2041 | cases.add("llu integer suffix after hex literal", | |
| 2042 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 2043 | , &[_][]const u8{ | |
| 2044 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | |
| 3146 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 3147 | , | |
| 3148 | \\pub const Foo = enum_Foo; | |
| 2045 | 3149 | }); |
| 2046 | 3150 | |
| 2047 | cases.add("macros with field targets", | |
| 2048 | \\typedef unsigned int GLbitfield; | |
| 2049 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | |
| 2050 | \\typedef void(*OpenGLProc)(void); | |
| 2051 | \\union OpenGLProcs { | |
| 2052 | \\ OpenGLProc ptr[1]; | |
| 2053 | \\ struct { | |
| 2054 | \\ PFNGLCLEARPROC Clear; | |
| 2055 | \\ } gl; | |
| 3151 | cases.add("enums", | |
| 3152 | \\enum Foo { | |
| 3153 | \\ FooA = 2, | |
| 3154 | \\ FooB = 5, | |
| 3155 | \\ Foo1, | |
| 2056 | 3156 | \\}; |
| 2057 | \\extern union OpenGLProcs glProcs; | |
| 2058 | \\#define glClearUnion glProcs.gl.Clear | |
| 2059 | \\#define glClearPFN PFNGLCLEARPROC | |
| 2060 | 3157 | , &[_][]const u8{ |
| 2061 | \\pub const GLbitfield = c_uint; | |
| 2062 | , | |
| 2063 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | |
| 2064 | , | |
| 2065 | \\pub const OpenGLProc = ?extern fn () void; | |
| 2066 | , | |
| 2067 | \\pub const union_OpenGLProcs = extern union { | |
| 2068 | \\ ptr: [1]OpenGLProc, | |
| 2069 | \\ gl: extern struct { | |
| 2070 | \\ Clear: PFNGLCLEARPROC, | |
| 2071 | \\ }, | |
| 3158 | \\pub const enum_Foo = extern enum { | |
| 3159 | \\ A = 2, | |
| 3160 | \\ B = 5, | |
| 3161 | \\ @"1" = 6, | |
| 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 { | |
| 2079 | \\ return glProcs.gl.Clear.?(arg0); | |
| 2080 | \\} | |
| 3168 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 2081 | 3169 | , |
| 2082 | \\pub const OpenGLProcs = union_OpenGLProcs; | |
| 2083 | }); | |
| 2084 | ||
| 2085 | cases.add("macro pointer cast", | |
| 2086 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | |
| 2087 | , &[_][]const u8{ | |
| 2088 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | |
| 3170 | \\pub const Foo = enum_Foo; | |
| 2089 | 3171 | }); |
| 2090 | 3172 | } |