| author | |
| committer | |
| log | 28dbdba37eed0cfd875cfc337446da3048743dd9 |
| tree | 71d3d4479809da72c5410e7dd49855805f25abe5 |
| parent | ba1d213f480eb0cb7c8641a8d8cb1d6763e82438 |
| parent | 9d31b65b34a222ff8b11d5bcaefcfc3c22ef4250 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
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,7 +582,9 @@ pub fn formatAsciiChar( |
| 582 | comptime Errors: type, | 582 | comptime Errors: type, |
| 583 | output: fn (@TypeOf(context), []const u8) Errors!void, | 583 | output: fn (@TypeOf(context), []const u8) Errors!void, |
| 584 | ) Errors!void { | 584 | ) Errors!void { |
| 585 | return output(context, @as(*const [1]u8, &c)[0..]); | 585 | if (std.ascii.isPrint(c)) |
| 586 | return output(context, @as(*const [1]u8, &c)[0..]); | ||
| 587 | return format(context, Errors, output, "\\x{x:0<2}", .{c}); | ||
| 586 | } | 588 | } |
| 587 | 589 | ||
| 588 | pub fn formatBuf( | 590 | pub fn formatBuf( |
lib/std/zig/ast.zig+16-16| ... | @@ -1431,13 +1431,13 @@ pub const Node = struct { | ... | @@ -1431,13 +1431,13 @@ pub const Node = struct { |
| 1431 | AssignBitShiftRight, | 1431 | AssignBitShiftRight, |
| 1432 | AssignBitXor, | 1432 | AssignBitXor, |
| 1433 | AssignDiv, | 1433 | AssignDiv, |
| 1434 | AssignMinus, | 1434 | AssignSub, |
| 1435 | AssignMinusWrap, | 1435 | AssignSubWrap, |
| 1436 | AssignMod, | 1436 | AssignMod, |
| 1437 | AssignPlus, | 1437 | AssignAdd, |
| 1438 | AssignPlusWrap, | 1438 | AssignAddWrap, |
| 1439 | AssignTimes, | 1439 | AssignMul, |
| 1440 | AssignTimesWarp, | 1440 | AssignMulWrap, |
| 1441 | BangEqual, | 1441 | BangEqual, |
| 1442 | BitAnd, | 1442 | BitAnd, |
| 1443 | BitOr, | 1443 | BitOr, |
| ... | @@ -1456,8 +1456,8 @@ pub const Node = struct { | ... | @@ -1456,8 +1456,8 @@ pub const Node = struct { |
| 1456 | LessThan, | 1456 | LessThan, |
| 1457 | MergeErrorSets, | 1457 | MergeErrorSets, |
| 1458 | Mod, | 1458 | Mod, |
| 1459 | Mult, | 1459 | Mul, |
| 1460 | MultWrap, | 1460 | MulWrap, |
| 1461 | Period, | 1461 | Period, |
| 1462 | Range, | 1462 | Range, |
| 1463 | Sub, | 1463 | Sub, |
| ... | @@ -1490,13 +1490,13 @@ pub const Node = struct { | ... | @@ -1490,13 +1490,13 @@ pub const Node = struct { |
| 1490 | Op.AssignBitShiftRight, | 1490 | Op.AssignBitShiftRight, |
| 1491 | Op.AssignBitXor, | 1491 | Op.AssignBitXor, |
| 1492 | Op.AssignDiv, | 1492 | Op.AssignDiv, |
| 1493 | Op.AssignMinus, | 1493 | Op.AssignSub, |
| 1494 | Op.AssignMinusWrap, | 1494 | Op.AssignSubWrap, |
| 1495 | Op.AssignMod, | 1495 | Op.AssignMod, |
| 1496 | Op.AssignPlus, | 1496 | Op.AssignAdd, |
| 1497 | Op.AssignPlusWrap, | 1497 | Op.AssignAddWrap, |
| 1498 | Op.AssignTimes, | 1498 | Op.AssignMul, |
| 1499 | Op.AssignTimesWarp, | 1499 | Op.AssignMulWrap, |
| 1500 | Op.BangEqual, | 1500 | Op.BangEqual, |
| 1501 | Op.BitAnd, | 1501 | Op.BitAnd, |
| 1502 | Op.BitOr, | 1502 | Op.BitOr, |
| ... | @@ -1514,8 +1514,8 @@ pub const Node = struct { | ... | @@ -1514,8 +1514,8 @@ pub const Node = struct { |
| 1514 | Op.LessThan, | 1514 | Op.LessThan, |
| 1515 | Op.MergeErrorSets, | 1515 | Op.MergeErrorSets, |
| 1516 | Op.Mod, | 1516 | Op.Mod, |
| 1517 | Op.Mult, | 1517 | Op.Mul, |
| 1518 | Op.MultWrap, | 1518 | Op.MulWrap, |
| 1519 | Op.Period, | 1519 | Op.Period, |
| 1520 | Op.Range, | 1520 | Op.Range, |
| 1521 | Op.Sub, | 1521 | Op.Sub, |
lib/std/zig/parse.zig+8-8| ... | @@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1981 | 1981 | ||
| 1982 | const token = nextToken(it); | 1982 | const token = nextToken(it); |
| 1983 | const op = switch (token.ptr.id) { | 1983 | const op = switch (token.ptr.id) { |
| 1984 | .AsteriskEqual => Op{ .AssignTimes = {} }, | 1984 | .AsteriskEqual => Op{ .AssignMul = {} }, |
| 1985 | .SlashEqual => Op{ .AssignDiv = {} }, | 1985 | .SlashEqual => Op{ .AssignDiv = {} }, |
| 1986 | .PercentEqual => Op{ .AssignMod = {} }, | 1986 | .PercentEqual => Op{ .AssignMod = {} }, |
| 1987 | .PlusEqual => Op{ .AssignPlus = {} }, | 1987 | .PlusEqual => Op{ .AssignAdd = {} }, |
| 1988 | .MinusEqual => Op{ .AssignMinus = {} }, | 1988 | .MinusEqual => Op{ .AssignSub = {} }, |
| 1989 | .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, | 1989 | .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, |
| 1990 | .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, | 1990 | .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, |
| 1991 | .AmpersandEqual => Op{ .AssignBitAnd = {} }, | 1991 | .AmpersandEqual => Op{ .AssignBitAnd = {} }, |
| 1992 | .CaretEqual => Op{ .AssignBitXor = {} }, | 1992 | .CaretEqual => Op{ .AssignBitXor = {} }, |
| 1993 | .PipeEqual => Op{ .AssignBitOr = {} }, | 1993 | .PipeEqual => Op{ .AssignBitOr = {} }, |
| 1994 | .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} }, | 1994 | .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, |
| 1995 | .PlusPercentEqual => Op{ .AssignPlusWrap = {} }, | 1995 | .PlusPercentEqual => Op{ .AssignAddWrap = {} }, |
| 1996 | .MinusPercentEqual => Op{ .AssignMinusWrap = {} }, | 1996 | .MinusPercentEqual => Op{ .AssignSubWrap = {} }, |
| 1997 | .Equal => Op{ .Assign = {} }, | 1997 | .Equal => Op{ .Assign = {} }, |
| 1998 | else => { | 1998 | else => { |
| 1999 | putBackToken(it, token.index); | 1999 | putBackToken(it, token.index); |
| ... | @@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2120,11 +2120,11 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2120 | const token = nextToken(it); | 2120 | const token = nextToken(it); |
| 2121 | const op = switch (token.ptr.id) { | 2121 | const op = switch (token.ptr.id) { |
| 2122 | .PipePipe => ops{ .BoolOr = {} }, | 2122 | .PipePipe => ops{ .BoolOr = {} }, |
| 2123 | .Asterisk => ops{ .Mult = {} }, | 2123 | .Asterisk => ops{ .Mul = {} }, |
| 2124 | .Slash => ops{ .Div = {} }, | 2124 | .Slash => ops{ .Div = {} }, |
| 2125 | .Percent => ops{ .Mod = {} }, | 2125 | .Percent => ops{ .Mod = {} }, |
| 2126 | .AsteriskAsterisk => ops{ .ArrayMult = {} }, | 2126 | .AsteriskAsterisk => ops{ .ArrayMult = {} }, |
| 2127 | .AsteriskPercent => ops{ .MultWrap = {} }, | 2127 | .AsteriskPercent => ops{ .MulWrap = {} }, |
| 2128 | else => { | 2128 | else => { |
| 2129 | putBackToken(it, token.index); | 2129 | putBackToken(it, token.index); |
| 2130 | return null; | 2130 | return null; |
lib/std/zig/render.zig+1-1| ... | @@ -1635,7 +1635,7 @@ fn renderExpression( | ... | @@ -1635,7 +1635,7 @@ fn renderExpression( |
| 1635 | .If => { | 1635 | .If => { |
| 1636 | const if_node = @fieldParentPtr(ast.Node.If, "base", base); | 1636 | const if_node = @fieldParentPtr(ast.Node.If, "base", base); |
| 1637 | 1637 | ||
| 1638 | const lparen = tree.prevToken(if_node.condition.firstToken()); | 1638 | const lparen = tree.nextToken(if_node.if_token); |
| 1639 | const rparen = tree.nextToken(if_node.condition.lastToken()); | 1639 | const rparen = tree.nextToken(if_node.condition.lastToken()); |
| 1640 | 1640 | ||
| 1641 | try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if | 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,6 +27,10 @@ pub const CToken = struct { |
| 27 | Lt, | 27 | Lt, |
| 28 | Comma, | 28 | Comma, |
| 29 | Fn, | 29 | Fn, |
| 30 | Arrow, | ||
| 31 | LBrace, | ||
| 32 | RBrace, | ||
| 33 | Pipe, | ||
| 30 | }; | 34 | }; |
| 31 | 35 | ||
| 32 | pub const NumLitSuffix = enum { | 36 | pub const NumLitSuffix = enum { |
| ... | @@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken { | ... | @@ -71,69 +75,130 @@ fn zigifyEscapeSequences(allocator: *std.mem.Allocator, tok: CToken) !CToken { |
| 71 | } | 75 | } |
| 72 | } else return tok; | 76 | } else return tok; |
| 73 | var bytes = try allocator.alloc(u8, tok.bytes.len * 2); | 77 | var bytes = try allocator.alloc(u8, tok.bytes.len * 2); |
| 74 | var escape = false; | 78 | var state: enum { |
| 79 | Start, | ||
| 80 | Escape, | ||
| 81 | Hex, | ||
| 82 | Octal, | ||
| 83 | } = .Start; | ||
| 75 | var i: usize = 0; | 84 | var i: usize = 0; |
| 85 | var count: u8 = 0; | ||
| 86 | var num: u8 = 0; | ||
| 76 | for (tok.bytes) |c| { | 87 | for (tok.bytes) |c| { |
| 77 | if (escape) { | 88 | switch (state) { |
| 78 | switch (c) { | 89 | .Escape => { |
| 79 | 'n', 'r', 't', '\\', '\'', '\"', 'x' => { | 90 | switch (c) { |
| 80 | bytes[i] = c; | 91 | 'n', 'r', 't', '\\', '\'', '\"' => { |
| 81 | }, | 92 | bytes[i] = c; |
| 82 | 'a' => { | 93 | }, |
| 83 | bytes[i] = 'x'; | 94 | '0'...'7' => { |
| 84 | i += 1; | 95 | count += 1; |
| 85 | bytes[i] = '0'; | 96 | num += c - '0'; |
| 86 | i += 1; | 97 | state = .Octal; |
| 87 | bytes[i] = '7'; | 98 | bytes[i] = 'x'; |
| 88 | }, | 99 | }, |
| 89 | 'b' => { | 100 | 'x' => { |
| 90 | bytes[i] = 'x'; | 101 | state = .Hex; |
| 91 | i += 1; | 102 | bytes[i] = 'x'; |
| 92 | bytes[i] = '0'; | 103 | }, |
| 93 | i += 1; | 104 | 'a' => { |
| 94 | bytes[i] = '8'; | 105 | bytes[i] = 'x'; |
| 95 | }, | 106 | i += 1; |
| 96 | 'f' => { | 107 | bytes[i] = '0'; |
| 97 | bytes[i] = 'x'; | 108 | i += 1; |
| 98 | i += 1; | 109 | bytes[i] = '7'; |
| 99 | bytes[i] = '0'; | 110 | }, |
| 100 | i += 1; | 111 | 'b' => { |
| 101 | bytes[i] = 'C'; | 112 | bytes[i] = 'x'; |
| 102 | }, | 113 | i += 1; |
| 103 | 'v' => { | 114 | bytes[i] = '0'; |
| 104 | bytes[i] = 'x'; | 115 | i += 1; |
| 105 | i += 1; | 116 | bytes[i] = '8'; |
| 106 | bytes[i] = '0'; | 117 | }, |
| 107 | i += 1; | 118 | 'f' => { |
| 108 | bytes[i] = 'B'; | 119 | bytes[i] = 'x'; |
| 109 | }, | 120 | i += 1; |
| 110 | '?' => { | 121 | bytes[i] = '0'; |
| 111 | i -= 1; | 122 | i += 1; |
| 112 | bytes[i] = '?'; | 123 | bytes[i] = 'C'; |
| 113 | }, | 124 | }, |
| 114 | 'u', 'U' => { | 125 | 'v' => { |
| 115 | // TODO unicode escape sequences | 126 | bytes[i] = 'x'; |
| 116 | return error.TokenizingFailed; | 127 | i += 1; |
| 117 | }, | 128 | bytes[i] = '0'; |
| 118 | '0'...'7' => { | 129 | i += 1; |
| 119 | // TODO octal escape sequences | 130 | bytes[i] = 'B'; |
| 120 | return error.TokenizingFailed; | 131 | }, |
| 121 | }, | 132 | '?' => { |
| 122 | else => { | 133 | i -= 1; |
| 123 | // unknown escape sequence | 134 | bytes[i] = '?'; |
| 124 | return error.TokenizingFailed; | 135 | }, |
| 125 | }, | 136 | 'u', 'U' => { |
| 126 | } | 137 | // TODO unicode escape sequences |
| 127 | i += 1; | 138 | return error.TokenizingFailed; |
| 128 | escape = false; | 139 | }, |
| 129 | } else { | 140 | else => { |
| 130 | if (c == '\\') { | 141 | // unknown escape sequence |
| 131 | escape = true; | 142 | return error.TokenizingFailed; |
| 132 | } | 143 | }, |
| 133 | bytes[i] = c; | 144 | } |
| 134 | i += 1; | 145 | i += 1; |
| 146 | if (state == .Escape) | ||
| 147 | state = .Start; | ||
| 148 | }, | ||
| 149 | .Start => { | ||
| 150 | if (c == '\\') { | ||
| 151 | state = .Escape; | ||
| 152 | } | ||
| 153 | bytes[i] = c; | ||
| 154 | i += 1; | ||
| 155 | }, | ||
| 156 | .Hex => { | ||
| 157 | switch (c) { | ||
| 158 | '0'...'9' => { | ||
| 159 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | ||
| 160 | num += c - '0'; | ||
| 161 | }, | ||
| 162 | 'a'...'f' => { | ||
| 163 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | ||
| 164 | num += c - 'a' + 10; | ||
| 165 | }, | ||
| 166 | 'A'...'F' => { | ||
| 167 | num = std.math.mul(u8, num, 16) catch return error.TokenizingFailed; | ||
| 168 | num += c - 'A' + 10; | ||
| 169 | }, | ||
| 170 | else => { | ||
| 171 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2}); | ||
| 172 | num = 0; | ||
| 173 | if (c == '\\') | ||
| 174 | state = .Escape | ||
| 175 | else | ||
| 176 | state = .Start; | ||
| 177 | bytes[i] = c; | ||
| 178 | i += 1; | ||
| 179 | }, | ||
| 180 | } | ||
| 181 | }, | ||
| 182 | .Octal => { | ||
| 183 | switch (c) { | ||
| 184 | '0'...'7' => { | ||
| 185 | count += 1; | ||
| 186 | num = std.math.mul(u8, num, 8) catch return error.TokenizingFailed; | ||
| 187 | num += c - '0'; | ||
| 188 | if (count < 3) | ||
| 189 | continue; | ||
| 190 | }, | ||
| 191 | else => {}, | ||
| 192 | } | ||
| 193 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2}); | ||
| 194 | state = .Start; | ||
| 195 | count = 0; | ||
| 196 | num = 0; | ||
| 197 | }, | ||
| 135 | } | 198 | } |
| 136 | } | 199 | } |
| 200 | if (state == .Hex or state == .Octal) | ||
| 201 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{.fill = '0', .width = 2}); | ||
| 137 | return CToken{ | 202 | return CToken{ |
| 138 | .id = tok.id, | 203 | .id = tok.id, |
| 139 | .bytes = bytes[0..i], | 204 | .bytes = bytes[0..i], |
| ... | @@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -164,6 +229,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 164 | NumLitIntSuffixL, | 229 | NumLitIntSuffixL, |
| 165 | NumLitIntSuffixLL, | 230 | NumLitIntSuffixLL, |
| 166 | NumLitIntSuffixUL, | 231 | NumLitIntSuffixUL, |
| 232 | Minus, | ||
| 233 | Done, | ||
| 167 | } = .Start; | 234 | } = .Start; |
| 168 | 235 | ||
| 169 | var result = CToken{ | 236 | var result = CToken{ |
| ... | @@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -178,9 +245,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 178 | const c = chars[i.*]; | 245 | const c = chars[i.*]; |
| 179 | if (c == 0) { | 246 | if (c == 0) { |
| 180 | switch (state) { | 247 | switch (state) { |
| 181 | .Start => { | ||
| 182 | return result; | ||
| 183 | }, | ||
| 184 | .Identifier, | 248 | .Identifier, |
| 185 | .Decimal, | 249 | .Decimal, |
| 186 | .Hex, | 250 | .Hex, |
| ... | @@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -193,6 +257,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 193 | result.bytes = chars[begin_index..i.*]; | 257 | result.bytes = chars[begin_index..i.*]; |
| 194 | return result; | 258 | return result; |
| 195 | }, | 259 | }, |
| 260 | .Start, | ||
| 261 | .Minus, | ||
| 262 | .Done, | ||
| 196 | .NumLitIntSuffixU, | 263 | .NumLitIntSuffixU, |
| 197 | .NumLitIntSuffixL, | 264 | .NumLitIntSuffixL, |
| 198 | .NumLitIntSuffixUL, | 265 | .NumLitIntSuffixUL, |
| ... | @@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -212,7 +279,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 212 | => return error.TokenizingFailed, | 279 | => return error.TokenizingFailed, |
| 213 | } | 280 | } |
| 214 | } | 281 | } |
| 215 | i.* += 1; | ||
| 216 | switch (state) { | 282 | switch (state) { |
| 217 | .Start => { | 283 | .Start => { |
| 218 | switch (c) { | 284 | switch (c) { |
| ... | @@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -220,12 +286,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 220 | '\'' => { | 286 | '\'' => { |
| 221 | state = .CharLit; | 287 | state = .CharLit; |
| 222 | result.id = .CharLit; | 288 | result.id = .CharLit; |
| 223 | begin_index = i.* - 1; | 289 | begin_index = i.*; |
| 224 | }, | 290 | }, |
| 225 | '\"' => { | 291 | '\"' => { |
| 226 | state = .String; | 292 | state = .String; |
| 227 | result.id = .StrLit; | 293 | result.id = .StrLit; |
| 228 | begin_index = i.* - 1; | 294 | begin_index = i.*; |
| 229 | }, | 295 | }, |
| 230 | '/' => { | 296 | '/' => { |
| 231 | state = .OpenComment; | 297 | state = .OpenComment; |
| ... | @@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -239,21 +305,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 239 | 'a'...'z', 'A'...'Z', '_' => { | 305 | 'a'...'z', 'A'...'Z', '_' => { |
| 240 | state = .Identifier; | 306 | state = .Identifier; |
| 241 | result.id = .Identifier; | 307 | result.id = .Identifier; |
| 242 | begin_index = i.* - 1; | 308 | begin_index = i.*; |
| 243 | }, | 309 | }, |
| 244 | '1'...'9' => { | 310 | '1'...'9' => { |
| 245 | state = .Decimal; | 311 | state = .Decimal; |
| 246 | result.id = .NumLitInt; | 312 | result.id = .NumLitInt; |
| 247 | begin_index = i.* - 1; | 313 | begin_index = i.*; |
| 248 | }, | 314 | }, |
| 249 | '0' => { | 315 | '0' => { |
| 250 | state = .GotZero; | 316 | state = .GotZero; |
| 251 | result.id = .NumLitInt; | 317 | result.id = .NumLitInt; |
| 252 | begin_index = i.* - 1; | 318 | begin_index = i.*; |
| 253 | }, | 319 | }, |
| 254 | '.' => { | 320 | '.' => { |
| 255 | result.id = .Dot; | 321 | result.id = .Dot; |
| 256 | return result; | 322 | state = .Done; |
| 257 | }, | 323 | }, |
| 258 | '<' => { | 324 | '<' => { |
| 259 | result.id = .Lt; | 325 | result.id = .Lt; |
| ... | @@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -261,40 +327,64 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 261 | }, | 327 | }, |
| 262 | '(' => { | 328 | '(' => { |
| 263 | result.id = .LParen; | 329 | result.id = .LParen; |
| 264 | return result; | 330 | state = .Done; |
| 265 | }, | 331 | }, |
| 266 | ')' => { | 332 | ')' => { |
| 267 | result.id = .RParen; | 333 | result.id = .RParen; |
| 268 | return result; | 334 | state = .Done; |
| 269 | }, | 335 | }, |
| 270 | '*' => { | 336 | '*' => { |
| 271 | result.id = .Asterisk; | 337 | result.id = .Asterisk; |
| 272 | return result; | 338 | state = .Done; |
| 273 | }, | 339 | }, |
| 274 | '-' => { | 340 | '-' => { |
| 341 | state = .Minus; | ||
| 275 | result.id = .Minus; | 342 | result.id = .Minus; |
| 276 | return result; | ||
| 277 | }, | 343 | }, |
| 278 | '!' => { | 344 | '!' => { |
| 279 | result.id = .Bang; | 345 | result.id = .Bang; |
| 280 | return result; | 346 | state = .Done; |
| 281 | }, | 347 | }, |
| 282 | '~' => { | 348 | '~' => { |
| 283 | result.id = .Tilde; | 349 | result.id = .Tilde; |
| 284 | return result; | 350 | state = .Done; |
| 285 | }, | 351 | }, |
| 286 | ',' => { | 352 | ',' => { |
| 287 | result.id = .Comma; | 353 | result.id = .Comma; |
| 288 | return result; | 354 | state = .Done; |
| 355 | }, | ||
| 356 | '[' => { | ||
| 357 | result.id = .LBrace; | ||
| 358 | state = .Done; | ||
| 359 | }, | ||
| 360 | ']' => { | ||
| 361 | result.id = .RBrace; | ||
| 362 | state = .Done; | ||
| 363 | }, | ||
| 364 | '|' => { | ||
| 365 | result.id = .Pipe; | ||
| 366 | state = .Done; | ||
| 289 | }, | 367 | }, |
| 290 | else => return error.TokenizingFailed, | 368 | else => return error.TokenizingFailed, |
| 291 | } | 369 | } |
| 292 | }, | 370 | }, |
| 371 | .Done => return result, | ||
| 372 | .Minus => { | ||
| 373 | switch (c) { | ||
| 374 | '>' => { | ||
| 375 | result.id = .Arrow; | ||
| 376 | state = .Done; | ||
| 377 | }, | ||
| 378 | else => { | ||
| 379 | return result; | ||
| 380 | }, | ||
| 381 | } | ||
| 382 | }, | ||
| 293 | .GotLt => { | 383 | .GotLt => { |
| 294 | switch (c) { | 384 | switch (c) { |
| 295 | '<' => { | 385 | '<' => { |
| 296 | result.id = .Shl; | 386 | result.id = .Shl; |
| 297 | return result; | 387 | state = .Done; |
| 298 | }, | 388 | }, |
| 299 | else => { | 389 | else => { |
| 300 | return result; | 390 | return result; |
| ... | @@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -310,19 +400,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 310 | 'f', | 400 | 'f', |
| 311 | 'F', | 401 | 'F', |
| 312 | => { | 402 | => { |
| 313 | i.* -= 1; | ||
| 314 | result.num_lit_suffix = .F; | 403 | result.num_lit_suffix = .F; |
| 315 | result.bytes = chars[begin_index..i.*]; | 404 | result.bytes = chars[begin_index..i.*]; |
| 316 | return result; | 405 | state = .Done; |
| 317 | }, | 406 | }, |
| 318 | 'l', 'L' => { | 407 | 'l', 'L' => { |
| 319 | i.* -= 1; | ||
| 320 | result.num_lit_suffix = .L; | 408 | result.num_lit_suffix = .L; |
| 321 | result.bytes = chars[begin_index..i.*]; | 409 | result.bytes = chars[begin_index..i.*]; |
| 322 | return result; | 410 | state = .Done; |
| 323 | }, | 411 | }, |
| 324 | else => { | 412 | else => { |
| 325 | i.* -= 1; | ||
| 326 | result.bytes = chars[begin_index..i.*]; | 413 | result.bytes = chars[begin_index..i.*]; |
| 327 | return result; | 414 | return result; |
| 328 | }, | 415 | }, |
| ... | @@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -352,16 +439,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 352 | '0'...'9' => {}, | 439 | '0'...'9' => {}, |
| 353 | 'f', 'F' => { | 440 | 'f', 'F' => { |
| 354 | result.num_lit_suffix = .F; | 441 | result.num_lit_suffix = .F; |
| 355 | result.bytes = chars[begin_index .. i.* - 1]; | 442 | result.bytes = chars[begin_index..i.*]; |
| 356 | return result; | 443 | state = .Done; |
| 357 | }, | 444 | }, |
| 358 | 'l', 'L' => { | 445 | 'l', 'L' => { |
| 359 | result.num_lit_suffix = .L; | 446 | result.num_lit_suffix = .L; |
| 360 | result.bytes = chars[begin_index .. i.* - 1]; | 447 | result.bytes = chars[begin_index..i.*]; |
| 361 | return result; | 448 | state = .Done; |
| 362 | }, | 449 | }, |
| 363 | else => { | 450 | else => { |
| 364 | i.* -= 1; | ||
| 365 | result.bytes = chars[begin_index..i.*]; | 451 | result.bytes = chars[begin_index..i.*]; |
| 366 | return result; | 452 | return result; |
| 367 | }, | 453 | }, |
| ... | @@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -374,19 +460,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 374 | 'u', 'U' => { | 460 | 'u', 'U' => { |
| 375 | state = .NumLitIntSuffixU; | 461 | state = .NumLitIntSuffixU; |
| 376 | result.num_lit_suffix = .U; | 462 | result.num_lit_suffix = .U; |
| 377 | result.bytes = chars[begin_index .. i.* - 1]; | 463 | result.bytes = chars[begin_index..i.*]; |
| 378 | }, | 464 | }, |
| 379 | 'l', 'L' => { | 465 | 'l', 'L' => { |
| 380 | state = .NumLitIntSuffixL; | 466 | state = .NumLitIntSuffixL; |
| 381 | result.num_lit_suffix = .L; | 467 | result.num_lit_suffix = .L; |
| 382 | result.bytes = chars[begin_index .. i.* - 1]; | 468 | result.bytes = chars[begin_index..i.*]; |
| 383 | }, | 469 | }, |
| 384 | '.' => { | 470 | '.' => { |
| 385 | result.id = .NumLitFloat; | 471 | result.id = .NumLitFloat; |
| 386 | state = .Float; | 472 | state = .Float; |
| 387 | }, | 473 | }, |
| 388 | else => { | 474 | else => { |
| 389 | i.* -= 1; | ||
| 390 | result.bytes = chars[begin_index..i.*]; | 475 | result.bytes = chars[begin_index..i.*]; |
| 391 | return result; | 476 | return result; |
| 392 | }, | 477 | }, |
| ... | @@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -407,12 +492,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 407 | 'u', 'U' => { | 492 | 'u', 'U' => { |
| 408 | state = .NumLitIntSuffixU; | 493 | state = .NumLitIntSuffixU; |
| 409 | result.num_lit_suffix = .U; | 494 | result.num_lit_suffix = .U; |
| 410 | result.bytes = chars[begin_index .. i.* - 1]; | 495 | result.bytes = chars[begin_index..i.*]; |
| 411 | }, | 496 | }, |
| 412 | 'l', 'L' => { | 497 | 'l', 'L' => { |
| 413 | state = .NumLitIntSuffixL; | 498 | state = .NumLitIntSuffixL; |
| 414 | result.num_lit_suffix = .L; | 499 | result.num_lit_suffix = .L; |
| 415 | result.bytes = chars[begin_index .. i.* - 1]; | 500 | result.bytes = chars[begin_index..i.*]; |
| 416 | }, | 501 | }, |
| 417 | else => { | 502 | else => { |
| 418 | i.* -= 1; | 503 | i.* -= 1; |
| ... | @@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -425,7 +510,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 425 | '0'...'7' => {}, | 510 | '0'...'7' => {}, |
| 426 | '8', '9' => return error.TokenizingFailed, | 511 | '8', '9' => return error.TokenizingFailed, |
| 427 | else => { | 512 | else => { |
| 428 | i.* -= 1; | ||
| 429 | result.bytes = chars[begin_index..i.*]; | 513 | result.bytes = chars[begin_index..i.*]; |
| 430 | return result; | 514 | return result; |
| 431 | }, | 515 | }, |
| ... | @@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -438,16 +522,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 438 | // marks the number literal as unsigned | 522 | // marks the number literal as unsigned |
| 439 | state = .NumLitIntSuffixU; | 523 | state = .NumLitIntSuffixU; |
| 440 | result.num_lit_suffix = .U; | 524 | result.num_lit_suffix = .U; |
| 441 | result.bytes = chars[begin_index .. i.* - 1]; | 525 | result.bytes = chars[begin_index..i.*]; |
| 442 | }, | 526 | }, |
| 443 | 'l', 'L' => { | 527 | 'l', 'L' => { |
| 444 | // marks the number literal as long | 528 | // marks the number literal as long |
| 445 | state = .NumLitIntSuffixL; | 529 | state = .NumLitIntSuffixL; |
| 446 | result.num_lit_suffix = .L; | 530 | result.num_lit_suffix = .L; |
| 447 | result.bytes = chars[begin_index .. i.* - 1]; | 531 | result.bytes = chars[begin_index..i.*]; |
| 448 | }, | 532 | }, |
| 449 | else => { | 533 | else => { |
| 450 | i.* -= 1; | ||
| 451 | result.bytes = chars[begin_index..i.*]; | 534 | result.bytes = chars[begin_index..i.*]; |
| 452 | return result; | 535 | return result; |
| 453 | }, | 536 | }, |
| ... | @@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -461,16 +544,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 461 | // marks the number literal as unsigned | 544 | // marks the number literal as unsigned |
| 462 | state = .NumLitIntSuffixU; | 545 | state = .NumLitIntSuffixU; |
| 463 | result.num_lit_suffix = .U; | 546 | result.num_lit_suffix = .U; |
| 464 | result.bytes = chars[begin_index .. i.* - 1]; | 547 | result.bytes = chars[begin_index..i.*]; |
| 465 | }, | 548 | }, |
| 466 | 'l', 'L' => { | 549 | 'l', 'L' => { |
| 467 | // marks the number literal as long | 550 | // marks the number literal as long |
| 468 | state = .NumLitIntSuffixL; | 551 | state = .NumLitIntSuffixL; |
| 469 | result.num_lit_suffix = .L; | 552 | result.num_lit_suffix = .L; |
| 470 | result.bytes = chars[begin_index .. i.* - 1]; | 553 | result.bytes = chars[begin_index..i.*]; |
| 471 | }, | 554 | }, |
| 472 | else => { | 555 | else => { |
| 473 | i.* -= 1; | ||
| 474 | result.bytes = chars[begin_index..i.*]; | 556 | result.bytes = chars[begin_index..i.*]; |
| 475 | return result; | 557 | return result; |
| 476 | }, | 558 | }, |
| ... | @@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -483,7 +565,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 483 | state = .NumLitIntSuffixUL; | 565 | state = .NumLitIntSuffixUL; |
| 484 | }, | 566 | }, |
| 485 | else => { | 567 | else => { |
| 486 | i.* -= 1; | ||
| 487 | return result; | 568 | return result; |
| 488 | }, | 569 | }, |
| 489 | } | 570 | } |
| ... | @@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -496,10 +577,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 496 | }, | 577 | }, |
| 497 | 'u', 'U' => { | 578 | 'u', 'U' => { |
| 498 | result.num_lit_suffix = .LU; | 579 | result.num_lit_suffix = .LU; |
| 499 | return result; | 580 | state = .Done; |
| 500 | }, | 581 | }, |
| 501 | else => { | 582 | else => { |
| 502 | i.* -= 1; | ||
| 503 | return result; | 583 | return result; |
| 504 | }, | 584 | }, |
| 505 | } | 585 | } |
| ... | @@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -508,10 +588,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 508 | switch (c) { | 588 | switch (c) { |
| 509 | 'u', 'U' => { | 589 | 'u', 'U' => { |
| 510 | result.num_lit_suffix = .LLU; | 590 | result.num_lit_suffix = .LLU; |
| 511 | return result; | 591 | state = .Done; |
| 512 | }, | 592 | }, |
| 513 | else => { | 593 | else => { |
| 514 | i.* -= 1; | ||
| 515 | return result; | 594 | return result; |
| 516 | }, | 595 | }, |
| 517 | } | 596 | } |
| ... | @@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -520,10 +599,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 520 | switch (c) { | 599 | switch (c) { |
| 521 | 'l', 'L' => { | 600 | 'l', 'L' => { |
| 522 | result.num_lit_suffix = .LLU; | 601 | result.num_lit_suffix = .LLU; |
| 523 | return result; | 602 | state = .Done; |
| 524 | }, | 603 | }, |
| 525 | else => { | 604 | else => { |
| 526 | i.* -= 1; | ||
| 527 | return result; | 605 | return result; |
| 528 | }, | 606 | }, |
| 529 | } | 607 | } |
| ... | @@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -532,17 +610,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 532 | switch (c) { | 610 | switch (c) { |
| 533 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, | 611 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, |
| 534 | else => { | 612 | else => { |
| 535 | i.* -= 1; | ||
| 536 | result.bytes = chars[begin_index..i.*]; | 613 | result.bytes = chars[begin_index..i.*]; |
| 537 | return result; | 614 | return result; |
| 538 | }, | 615 | }, |
| 539 | } | 616 | } |
| 540 | }, | 617 | }, |
| 541 | .String => { // TODO char escapes | 618 | .String => { |
| 542 | switch (c) { | 619 | switch (c) { |
| 543 | '\"' => { | 620 | '\"' => { |
| 544 | result.bytes = chars[begin_index..i.*]; | 621 | result.bytes = chars[begin_index .. i.* + 1]; |
| 545 | return result; | 622 | state = .Done; |
| 546 | }, | 623 | }, |
| 547 | else => {}, | 624 | else => {}, |
| 548 | } | 625 | } |
| ... | @@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -550,8 +627,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 550 | .CharLit => { | 627 | .CharLit => { |
| 551 | switch (c) { | 628 | switch (c) { |
| 552 | '\'' => { | 629 | '\'' => { |
| 553 | result.bytes = chars[begin_index..i.*]; | 630 | result.bytes = chars[begin_index .. i.* + 1]; |
| 554 | return result; | 631 | state = .Done; |
| 555 | }, | 632 | }, |
| 556 | else => {}, | 633 | else => {}, |
| 557 | } | 634 | } |
| ... | @@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -566,7 +643,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 566 | }, | 643 | }, |
| 567 | else => { | 644 | else => { |
| 568 | result.id = .Slash; | 645 | result.id = .Slash; |
| 569 | return result; | 646 | state = .Done; |
| 570 | }, | 647 | }, |
| 571 | } | 648 | } |
| 572 | }, | 649 | }, |
| ... | @@ -598,6 +675,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -598,6 +675,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 598 | } | 675 | } |
| 599 | }, | 676 | }, |
| 600 | } | 677 | } |
| 678 | i.* += 1; | ||
| 601 | } | 679 | } |
| 602 | unreachable; | 680 | unreachable; |
| 603 | } | 681 | } |
| ... | @@ -645,7 +723,7 @@ test "tokenize macro" { | ... | @@ -645,7 +723,7 @@ test "tokenize macro" { |
| 645 | expect(it.next() == null); | 723 | expect(it.next() == null); |
| 646 | tl.shrink(0); | 724 | tl.shrink(0); |
| 647 | 725 | ||
| 648 | const src5 = "FOO 0l"; | 726 | const src5 = "FOO 0ull"; |
| 649 | try tokenizeCMacro(&tl, src5); | 727 | try tokenizeCMacro(&tl, src5); |
| 650 | it = tl.iterator(0); | 728 | it = tl.iterator(0); |
| 651 | expect(it.next().?.id == .Identifier); | 729 | expect(it.next().?.id == .Identifier); |
| ... | @@ -654,3 +732,25 @@ test "tokenize macro" { | ... | @@ -654,3 +732,25 @@ test "tokenize macro" { |
| 654 | expect(it.next() == null); | 732 | expect(it.next() == null); |
| 655 | tl.shrink(0); | 733 | tl.shrink(0); |
| 656 | } | 734 | } |
| 735 | |||
| 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,6 +76,10 @@ pub const struct_ZigClangFunctionType = @OpaqueType(); |
| 76 | pub const struct_ZigClangPredefinedExpr = @OpaqueType(); | 76 | pub const struct_ZigClangPredefinedExpr = @OpaqueType(); |
| 77 | pub const struct_ZigClangInitListExpr = @OpaqueType(); | 77 | pub const struct_ZigClangInitListExpr = @OpaqueType(); |
| 78 | pub const ZigClangPreprocessingRecord = @OpaqueType(); | 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 | pub const ZigClangBO = extern enum { | 84 | pub const ZigClangBO = extern enum { |
| 81 | PtrMemD, | 85 | PtrMemD, |
| ... | @@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum { | ... | @@ -710,6 +714,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum { |
| 710 | UTF32, | 714 | UTF32, |
| 711 | }; | 715 | }; |
| 712 | 716 | ||
| 717 | pub const ZigClangCharacterLiteral_CharacterKind = extern enum { | ||
| 718 | Ascii, | ||
| 719 | Wide, | ||
| 720 | UTF8, | ||
| 721 | UTF16, | ||
| 722 | UTF32, | ||
| 723 | }; | ||
| 724 | |||
| 713 | pub const ZigClangRecordDecl_field_iterator = extern struct { | 725 | pub const ZigClangRecordDecl_field_iterator = extern struct { |
| 714 | opaque: *c_void, | 726 | opaque: *c_void, |
| 715 | }; | 727 | }; |
| ... | @@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum { | ... | @@ -730,6 +742,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum { |
| 730 | InclusionDirectiveKind, | 742 | InclusionDirectiveKind, |
| 731 | }; | 743 | }; |
| 732 | 744 | ||
| 745 | pub const ZigClangExpr_ConstExprUsage = extern enum { | ||
| 746 | EvaluateForCodeGen, | ||
| 747 | EvaluateForMangling, | ||
| 748 | }; | ||
| 749 | |||
| 733 | pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; | 750 | pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; |
| 734 | pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; | 751 | pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; |
| 735 | pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; | 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,6 +761,8 @@ pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumTyp |
| 744 | pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; | 761 | pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; |
| 745 | pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; | 762 | pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; |
| 746 | pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; | 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 | pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl; | 766 | pub extern fn ZigClangRecordDecl_getDefinition(self: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangRecordDecl; |
| 748 | pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl; | 767 | pub extern fn ZigClangEnumDecl_getDefinition(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangEnumDecl; |
| 749 | pub extern fn ZigClangRecordDecl_getLocation(self: ?*const struct_ZigClangRecordDecl) struct_ZigClangSourceLocation; | 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,16 +810,16 @@ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitList |
| 791 | pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr; | 810 | pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr; |
| 792 | pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint; | 811 | pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint; |
| 793 | pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind; | 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 | pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint; | 814 | pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint; |
| 796 | pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint; | 815 | pub extern fn ZigClangAPValue_getArraySize(self: ?*const struct_ZigClangAPValue) c_uint; |
| 797 | pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase; | 816 | pub extern fn ZigClangAPValue_getLValueBase(self: ?*const struct_ZigClangAPValue) struct_ZigClangAPValueLValueBase; |
| 798 | pub extern fn ZigClangAPSInt_isSigned(self: ?*const struct_ZigClangAPSInt) bool; | 817 | pub extern fn ZigClangAPSInt_isSigned(self: *const struct_ZigClangAPSInt) bool; |
| 799 | pub extern fn ZigClangAPSInt_isNegative(self: ?*const struct_ZigClangAPSInt) bool; | 818 | pub extern fn ZigClangAPSInt_isNegative(self: *const struct_ZigClangAPSInt) bool; |
| 800 | pub extern fn ZigClangAPSInt_negate(self: ?*const struct_ZigClangAPSInt) ?*const struct_ZigClangAPSInt; | 819 | pub extern fn ZigClangAPSInt_negate(self: *const struct_ZigClangAPSInt) *const struct_ZigClangAPSInt; |
| 801 | pub extern fn ZigClangAPSInt_free(self: ?*const struct_ZigClangAPSInt) void; | 820 | pub extern fn ZigClangAPSInt_free(self: *const struct_ZigClangAPSInt) void; |
| 802 | pub extern fn ZigClangAPSInt_getRawData(self: ?*const struct_ZigClangAPSInt) [*:0]const u64; | 821 | pub extern fn ZigClangAPSInt_getRawData(self: *const struct_ZigClangAPSInt) [*:0]const u64; |
| 803 | pub extern fn ZigClangAPSInt_getNumWords(self: ?*const struct_ZigClangAPSInt) c_uint; | 822 | pub extern fn ZigClangAPSInt_getNumWords(self: *const struct_ZigClangAPSInt) c_uint; |
| 804 | 823 | ||
| 805 | pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64; | 824 | pub extern fn ZigClangAPInt_getLimitedValue(self: *const struct_ZigClangAPInt, limit: u64) u64; |
| 806 | pub extern fn ZigClangAPValueLValueBase_dyn_cast_Expr(self: struct_ZigClangAPValueLValueBase) ?*const struct_ZigClangExpr; | 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,6 +841,7 @@ pub extern fn ZigClangFunctionType_getReturnType(self: *const ZigClangFunctionTy |
| 822 | pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool; | 841 | pub extern fn ZigClangFunctionProtoType_isVariadic(self: *const struct_ZigClangFunctionProtoType) bool; |
| 823 | pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint; | 842 | pub extern fn ZigClangFunctionProtoType_getNumParams(self: *const struct_ZigClangFunctionProtoType) c_uint; |
| 824 | pub extern fn ZigClangFunctionProtoType_getParamType(self: *const struct_ZigClangFunctionProtoType, i: c_uint) ZigClangQualType; | 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 | pub const ZigClangSourceLocation = struct_ZigClangSourceLocation; | 846 | pub const ZigClangSourceLocation = struct_ZigClangSourceLocation; |
| 827 | pub const ZigClangQualType = struct_ZigClangQualType; | 847 | pub const ZigClangQualType = struct_ZigClangQualType; |
| ... | @@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple | ... | @@ -976,6 +996,7 @@ pub extern fn ZigClangIncompleteArrayType_getElementType(*const ZigClangIncomple |
| 976 | pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType; | 996 | pub extern fn ZigClangConstantArrayType_getElementType(self: *const struct_ZigClangConstantArrayType) ZigClangQualType; |
| 977 | pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt; | 997 | pub extern fn ZigClangConstantArrayType_getSize(self: *const struct_ZigClangConstantArrayType) *const struct_ZigClangAPInt; |
| 978 | pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl; | 998 | pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl; |
| 999 | pub extern fn ZigClangDeclRefExpr_getFoundDecl(*const ZigClangDeclRefExpr) *const ZigClangNamedDecl; | ||
| 979 | 1000 | ||
| 980 | pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; | 1001 | pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; |
| 981 | 1002 | ||
| ... | @@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti | ... | @@ -1036,3 +1057,74 @@ pub extern fn ZigClangPreprocessedEntity_getKind(*const ZigClangPreprocessedEnti |
| 1036 | pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8; | 1057 | pub extern fn ZigClangMacroDefinitionRecord_getName_getNameStart(*const ZigClangMacroDefinitionRecord) [*:0]const u8; |
| 1037 | pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; | 1058 | pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getBegin(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; |
| 1038 | pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClangMacroDefinitionRecord) ZigClangSourceLocation; | 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,6 +8,7 @@ const Token = std.zig.Token; |
| 8 | usingnamespace @import("clang.zig"); | 8 | usingnamespace @import("clang.zig"); |
| 9 | const ctok = @import("c_tokenizer.zig"); | 9 | const ctok = @import("c_tokenizer.zig"); |
| 10 | const CToken = ctok.CToken; | 10 | const CToken = ctok.CToken; |
| 11 | const mem = std.mem; | ||
| 11 | 12 | ||
| 12 | const CallingConvention = std.builtin.TypeInfo.CallingConvention; | 13 | const CallingConvention = std.builtin.TypeInfo.CallingConvention; |
| 13 | 14 | ||
| ... | @@ -47,35 +48,34 @@ const Scope = struct { | ... | @@ -47,35 +48,34 @@ const Scope = struct { |
| 47 | Switch, | 48 | Switch, |
| 48 | Block, | 49 | Block, |
| 49 | Root, | 50 | Root, |
| 50 | While, | 51 | Condition, |
| 51 | FnDef, | 52 | Loop, |
| 52 | Ref, | ||
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | const Switch = struct { | 55 | const Switch = struct { |
| 56 | base: Scope, | 56 | base: Scope, |
| 57 | }; | 57 | pending_block: *ast.Node.Block, |
| 58 | 58 | cases: *ast.Node.Switch.CaseList, | |
| 59 | /// used when getting a member `a.b` | 59 | has_default: bool = false, |
| 60 | const Ref = struct { | ||
| 61 | base: Scope, | ||
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| 64 | const Block = struct { | 62 | const Block = struct { |
| 65 | base: Scope, | 63 | base: Scope, |
| 66 | block_node: *ast.Node.Block, | 64 | block_node: *ast.Node.Block, |
| 67 | variables: AliasList, | 65 | variables: AliasList, |
| 66 | label: ?[]const u8, | ||
| 68 | 67 | ||
| 69 | /// Don't forget to set rbrace token later | 68 | /// Don't forget to set rbrace token and block_node later |
| 70 | fn init(c: *Context, parent: *Scope, block_node: *ast.Node.Block) !*Block { | 69 | fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block { |
| 71 | const block = try c.a().create(Block); | 70 | const block = try c.a().create(Block); |
| 72 | block.* = .{ | 71 | block.* = .{ |
| 73 | .base = .{ | 72 | .base = .{ |
| 74 | .id = .Block, | 73 | .id = .Block, |
| 75 | .parent = parent, | 74 | .parent = parent, |
| 76 | }, | 75 | }, |
| 77 | .block_node = block_node, | 76 | .block_node = undefined, |
| 78 | .variables = AliasList.init(c.a()), | 77 | .variables = AliasList.init(c.a()), |
| 78 | .label = label, | ||
| 79 | }; | 79 | }; |
| 80 | return block; | 80 | return block; |
| 81 | } | 81 | } |
| ... | @@ -83,7 +83,7 @@ const Scope = struct { | ... | @@ -83,7 +83,7 @@ const Scope = struct { |
| 83 | fn getAlias(scope: *Block, name: []const u8) ?[]const u8 { | 83 | fn getAlias(scope: *Block, name: []const u8) ?[]const u8 { |
| 84 | var it = scope.variables.iterator(0); | 84 | var it = scope.variables.iterator(0); |
| 85 | while (it.next()) |p| { | 85 | while (it.next()) |p| { |
| 86 | if (std.mem.eql(u8, p.name, name)) | 86 | if (mem.eql(u8, p.name, name)) |
| 87 | return p.alias; | 87 | return p.alias; |
| 88 | } | 88 | } |
| 89 | return scope.base.parent.?.getAlias(name); | 89 | return scope.base.parent.?.getAlias(name); |
| ... | @@ -92,7 +92,7 @@ const Scope = struct { | ... | @@ -92,7 +92,7 @@ const Scope = struct { |
| 92 | fn contains(scope: *Block, name: []const u8) bool { | 92 | fn contains(scope: *Block, name: []const u8) bool { |
| 93 | var it = scope.variables.iterator(0); | 93 | var it = scope.variables.iterator(0); |
| 94 | while (it.next()) |p| { | 94 | while (it.next()) |p| { |
| 95 | if (std.mem.eql(u8, p.name, name)) | 95 | if (mem.eql(u8, p.name, name)) |
| 96 | return true; | 96 | return true; |
| 97 | } | 97 | } |
| 98 | return scope.base.parent.?.contains(name); | 98 | return scope.base.parent.?.contains(name); |
| ... | @@ -120,52 +120,23 @@ const Scope = struct { | ... | @@ -120,52 +120,23 @@ const Scope = struct { |
| 120 | } | 120 | } |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | const While = struct { | 123 | fn findBlockScope(inner: *Scope, c: *Context) !*Scope.Block { |
| 124 | base: Scope, | 124 | var scope = inner; |
| 125 | }; | 125 | while (true) { |
| 126 | 126 | switch (scope.id) { | |
| 127 | const FnDef = struct { | 127 | .Root => unreachable, |
| 128 | base: Scope, | 128 | .Block => return @fieldParentPtr(Block, "base", scope), |
| 129 | params: AliasList, | 129 | .Condition => { |
| 130 | 130 | // comma operator used | |
| 131 | fn init(c: *Context) FnDef { | 131 | return try Block.init(c, scope, "blk"); |
| 132 | return .{ | ||
| 133 | .base = .{ | ||
| 134 | .id = .FnDef, | ||
| 135 | .parent = &c.global_scope.base, | ||
| 136 | }, | 132 | }, |
| 137 | .params = AliasList.init(c.a()), | 133 | else => scope = scope.parent.?, |
| 138 | }; | ||
| 139 | } | ||
| 140 | |||
| 141 | fn getAlias(scope: *FnDef, name: []const u8) ?[]const u8 { | ||
| 142 | var it = scope.params.iterator(0); | ||
| 143 | while (it.next()) |p| { | ||
| 144 | if (std.mem.eql(u8, p.name, name)) | ||
| 145 | return p.alias; | ||
| 146 | } | 134 | } |
| 147 | return scope.base.parent.?.getAlias(name); | ||
| 148 | } | ||
| 149 | |||
| 150 | fn contains(scope: *FnDef, name: []const u8) bool { | ||
| 151 | var it = scope.params.iterator(0); | ||
| 152 | while (it.next()) |p| { | ||
| 153 | if (std.mem.eql(u8, p.name, name)) | ||
| 154 | return true; | ||
| 155 | } | ||
| 156 | return scope.base.parent.?.contains(name); | ||
| 157 | } | ||
| 158 | }; | ||
| 159 | |||
| 160 | fn findBlockScope(inner: *Scope) *Scope.Block { | ||
| 161 | var scope = inner; | ||
| 162 | while (true) : (scope = scope.parent orelse unreachable) { | ||
| 163 | if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope); | ||
| 164 | } | 135 | } |
| 165 | } | 136 | } |
| 166 | 137 | ||
| 167 | fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 { | 138 | fn createAlias(scope: *Scope, c: *Context, name: []const u8) !?[]const u8 { |
| 168 | if (scope.contains(name)) { | 139 | if (isZigPrimitiveType(name) or scope.contains(name)) { |
| 169 | return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }); | 140 | return try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }); |
| 170 | } | 141 | } |
| 171 | return null; | 142 | return null; |
| ... | @@ -174,22 +145,41 @@ const Scope = struct { | ... | @@ -174,22 +145,41 @@ const Scope = struct { |
| 174 | fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { | 145 | fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { |
| 175 | return switch (scope.id) { | 146 | return switch (scope.id) { |
| 176 | .Root => null, | 147 | .Root => null, |
| 177 | .Ref => null, | ||
| 178 | .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), | ||
| 179 | .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), | 148 | .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), |
| 180 | else => @panic("TODO Scope.getAlias"), | 149 | .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), |
| 181 | }; | 150 | }; |
| 182 | } | 151 | } |
| 183 | 152 | ||
| 184 | fn contains(scope: *Scope, name: []const u8) bool { | 153 | fn contains(scope: *Scope, name: []const u8) bool { |
| 185 | return switch (scope.id) { | 154 | return switch (scope.id) { |
| 186 | .Ref => false, | ||
| 187 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), | 155 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), |
| 188 | .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), | ||
| 189 | .Block => @fieldParentPtr(Block, "base", scope).contains(name), | 156 | .Block => @fieldParentPtr(Block, "base", scope).contains(name), |
| 190 | else => @panic("TODO Scope.contains"), | 157 | .Switch, .Loop, .Condition => scope.parent.?.contains(name), |
| 191 | }; | 158 | }; |
| 192 | } | 159 | } |
| 160 | |||
| 161 | fn getBreakableScope(inner: *Scope) *Scope { | ||
| 162 | var scope = inner; | ||
| 163 | while (true) { | ||
| 164 | switch (scope.id) { | ||
| 165 | .Root => unreachable, | ||
| 166 | .Switch => return scope, | ||
| 167 | .Loop => return scope, | ||
| 168 | else => scope = scope.parent.?, | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | fn getSwitch(inner: *Scope) *Scope.Switch { | ||
| 174 | var scope = inner; | ||
| 175 | while (true) { | ||
| 176 | switch (scope.id) { | ||
| 177 | .Root => unreachable, | ||
| 178 | .Switch => return @fieldParentPtr(Switch, "base", scope), | ||
| 179 | else => scope = scope.parent.?, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 193 | }; | 183 | }; |
| 194 | 184 | ||
| 195 | const Context = struct { | 185 | const Context = struct { |
| ... | @@ -200,7 +190,6 @@ const Context = struct { | ... | @@ -200,7 +190,6 @@ const Context = struct { |
| 200 | decl_table: DeclTable, | 190 | decl_table: DeclTable, |
| 201 | alias_list: AliasList, | 191 | alias_list: AliasList, |
| 202 | global_scope: *Scope.Root, | 192 | global_scope: *Scope.Root, |
| 203 | ptr_params: std.BufSet, | ||
| 204 | clang_context: *ZigClangASTContext, | 193 | clang_context: *ZigClangASTContext, |
| 205 | mangle_count: u64 = 0, | 194 | mangle_count: u64 = 0, |
| 206 | 195 | ||
| ... | @@ -209,13 +198,13 @@ const Context = struct { | ... | @@ -209,13 +198,13 @@ const Context = struct { |
| 209 | return c.mangle_count; | 198 | return c.mangle_count; |
| 210 | } | 199 | } |
| 211 | 200 | ||
| 212 | fn a(c: *Context) *std.mem.Allocator { | 201 | fn a(c: *Context) *mem.Allocator { |
| 213 | return &c.tree.arena_allocator.allocator; | 202 | return &c.tree.arena_allocator.allocator; |
| 214 | } | 203 | } |
| 215 | 204 | ||
| 216 | /// Convert a null-terminated C string to a slice allocated in the arena | 205 | /// Convert a null-terminated C string to a slice allocated in the arena |
| 217 | fn str(c: *Context, s: [*:0]const u8) ![]u8 { | 206 | fn str(c: *Context, s: [*:0]const u8) ![]u8 { |
| 218 | return std.mem.dupe(c.a(), u8, std.mem.toSliceConst(u8, s)); | 207 | return mem.dupe(c.a(), u8, mem.toSliceConst(u8, s)); |
| 219 | } | 208 | } |
| 220 | 209 | ||
| 221 | /// Convert a clang source location to a file:line:column string | 210 | /// Convert a clang source location to a file:line:column string |
| ... | @@ -231,7 +220,7 @@ const Context = struct { | ... | @@ -231,7 +220,7 @@ const Context = struct { |
| 231 | }; | 220 | }; |
| 232 | 221 | ||
| 233 | pub fn translate( | 222 | pub fn translate( |
| 234 | backing_allocator: *std.mem.Allocator, | 223 | backing_allocator: *mem.Allocator, |
| 235 | args_begin: [*]?[*]const u8, | 224 | args_begin: [*]?[*]const u8, |
| 236 | args_end: [*]?[*]const u8, | 225 | args_end: [*]?[*]const u8, |
| 237 | errors: *[]ClangErrMsg, | 226 | errors: *[]ClangErrMsg, |
| ... | @@ -286,7 +275,6 @@ pub fn translate( | ... | @@ -286,7 +275,6 @@ pub fn translate( |
| 286 | .decl_table = DeclTable.init(arena), | 275 | .decl_table = DeclTable.init(arena), |
| 287 | .alias_list = AliasList.init(arena), | 276 | .alias_list = AliasList.init(arena), |
| 288 | .global_scope = try arena.create(Scope.Root), | 277 | .global_scope = try arena.create(Scope.Root), |
| 289 | .ptr_params = std.BufSet.init(arena), | ||
| 290 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, | 278 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, |
| 291 | }; | 279 | }; |
| 292 | context.global_scope.* = Scope.Root.init(&context); | 280 | context.global_scope.* = Scope.Root.init(&context); |
| ... | @@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { | ... | @@ -333,13 +321,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 333 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); | 321 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); |
| 334 | }, | 322 | }, |
| 335 | .Typedef => { | 323 | .Typedef => { |
| 336 | return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); | 324 | _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 337 | }, | 325 | }, |
| 338 | .Enum => { | 326 | .Enum => { |
| 339 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); | 327 | _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); |
| 340 | }, | 328 | }, |
| 341 | .Record => { | 329 | .Record => { |
| 342 | return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); | 330 | _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 343 | }, | 331 | }, |
| 344 | .Var => { | 332 | .Var => { |
| 345 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); | 333 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); |
| ... | @@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { | ... | @@ -352,22 +340,17 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 352 | } | 340 | } |
| 353 | 341 | ||
| 354 | fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | 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 | const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); | 343 | const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); |
| 358 | _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name); | 344 | if (c.global_scope.sym_table.contains(fn_name)) |
| 345 | return; // Avoid processing this decl twice | ||
| 346 | const rp = makeRestorePoint(c); | ||
| 359 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); | 347 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); |
| 360 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); | ||
| 361 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); | ||
| 362 | var fndef_scope = Scope.FnDef.init(c); | ||
| 363 | var scope = &fndef_scope.base; | ||
| 364 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); | 348 | const has_body = ZigClangFunctionDecl_hasBody(fn_decl); |
| 365 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); | 349 | const storage_class = ZigClangFunctionDecl_getStorageClass(fn_decl); |
| 366 | const decl_ctx = FnDeclContext{ | 350 | const decl_ctx = FnDeclContext{ |
| 367 | .fn_name = fn_name, | 351 | .fn_name = fn_name, |
| 368 | .has_body = has_body, | 352 | .has_body = has_body, |
| 369 | .storage_class = storage_class, | 353 | .storage_class = storage_class, |
| 370 | .scope = &scope, | ||
| 371 | .is_export = switch (storage_class) { | 354 | .is_export = switch (storage_class) { |
| 372 | .None => has_body, | 355 | .None => has_body, |
| 373 | .Extern, .Static => false, | 356 | .Extern, .Static => false, |
| ... | @@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -377,6 +360,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 377 | else => unreachable, | 360 | else => unreachable, |
| 378 | }, | 361 | }, |
| 379 | }; | 362 | }; |
| 363 | |||
| 364 | var fn_qt = ZigClangFunctionDecl_getType(fn_decl); | ||
| 365 | var fn_type = ZigClangQualType_getTypePtr(fn_qt); | ||
| 366 | if (ZigClangType_getTypeClass(fn_type) == .Attributed) { | ||
| 367 | const attr_type = @ptrCast(*const ZigClangAttributedType, fn_type); | ||
| 368 | fn_qt = ZigClangAttributedType_getEquivalentType(attr_type); | ||
| 369 | fn_type = ZigClangQualType_getTypePtr(fn_qt); | ||
| 370 | } | ||
| 371 | |||
| 380 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { | 372 | const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { |
| 381 | .FunctionProto => blk: { | 373 | .FunctionProto => blk: { |
| 382 | const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); | 374 | const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); |
| ... | @@ -396,7 +388,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -396,7 +388,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 396 | error.OutOfMemory => |e| return e, | 388 | error.OutOfMemory => |e| return e, |
| 397 | }; | 389 | }; |
| 398 | }, | 390 | }, |
| 399 | else => unreachable, | 391 | else => return failDecl(c, fn_decl_loc, fn_name, "unable to resolve function type {}", .{ZigClangType_getTypeClass(fn_type)}), |
| 400 | }; | 392 | }; |
| 401 | 393 | ||
| 402 | if (!decl_ctx.has_body) { | 394 | if (!decl_ctx.has_body) { |
| ... | @@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -406,20 +398,47 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 406 | 398 | ||
| 407 | // actual function definition with body | 399 | // actual function definition with body |
| 408 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); | 400 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); |
| 409 | const body_node = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { | 401 | const block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); |
| 402 | var scope = &block_scope.base; | ||
| 403 | const block_node = try transCreateNodeBlock(rp.c, null); | ||
| 404 | block_scope.block_node = block_node; | ||
| 405 | |||
| 406 | var it = proto_node.params.iterator(0); | ||
| 407 | while (it.next()) |p| { | ||
| 408 | const param = @fieldParentPtr(ast.Node.ParamDecl, "base", p.*); | ||
| 409 | const param_name = tokenSlice(c, param.name_token orelse | ||
| 410 | return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name})); | ||
| 411 | |||
| 412 | const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: { | ||
| 413 | try block_scope.variables.push(.{ .name = param_name, .alias = a }); | ||
| 414 | break :blk a; | ||
| 415 | } else param_name; | ||
| 416 | const arg_name = try std.fmt.allocPrint(c.a(), "_arg_{}", .{checked_param_name}); | ||
| 417 | |||
| 418 | const node = try transCreateNodeVarDecl(c, false, false, checked_param_name); | ||
| 419 | node.eq_token = try appendToken(c, .Equal, "="); | ||
| 420 | node.init_node = try transCreateNodeIdentifier(c, arg_name); | ||
| 421 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 422 | try block_node.statements.push(&node.base); | ||
| 423 | param.name_token = try appendIdentifier(c, arg_name); | ||
| 424 | _ = try appendToken(c, .Colon, ":"); | ||
| 425 | } | ||
| 426 | |||
| 427 | transCompoundStmtInline(rp, &block_scope.base, @ptrCast(*const ZigClangCompoundStmt, body_stmt), block_node) catch |err| switch (err) { | ||
| 410 | error.OutOfMemory => |e| return e, | 428 | error.OutOfMemory => |e| return e, |
| 411 | error.UnsupportedTranslation, | 429 | error.UnsupportedTranslation, |
| 412 | error.UnsupportedType, | 430 | error.UnsupportedType, |
| 413 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), | 431 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), |
| 414 | }; | 432 | }; |
| 415 | assert(body_node.id == .Block); | 433 | block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 416 | proto_node.body_node = body_node; | 434 | proto_node.body_node = &block_node.base; |
| 417 | |||
| 418 | return addTopLevelDecl(c, fn_name, &proto_node.base); | 435 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 419 | } | 436 | } |
| 420 | 437 | ||
| 421 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | 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 | const rp = makeRestorePoint(c); | 442 | const rp = makeRestorePoint(c); |
| 424 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 443 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 425 | 444 | ||
| ... | @@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -429,8 +448,10 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 429 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | 448 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 430 | 449 | ||
| 431 | const scope = &c.global_scope.base; | 450 | const scope = &c.global_scope.base; |
| 432 | const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); | 451 | |
| 433 | _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); | 452 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 453 | // TODO https://github.com/ziglang/zig/issues/1802 | ||
| 454 | const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "_{}", .{var_name}) else var_name; | ||
| 434 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); | 455 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); |
| 435 | 456 | ||
| 436 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); | 457 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| ... | @@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -449,12 +470,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 449 | else | 470 | else |
| 450 | try appendToken(c, .Keyword_var, "var"); | 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 | _ = try appendToken(c, .Colon, ":"); | 475 | _ = try appendToken(c, .Colon, ":"); |
| 455 | const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { | 476 | const type_node = transQualType(rp, qual_type, var_decl_loc) catch |err| switch (err) { |
| 456 | error.UnsupportedType => { | 477 | error.UnsupportedType => { |
| 457 | return failDecl(c, var_decl_loc, var_name, "unable to resolve variable type", .{}); | 478 | return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{}); |
| 458 | }, | 479 | }, |
| 459 | error.OutOfMemory => |e| return e, | 480 | error.OutOfMemory => |e| return e, |
| 460 | }; | 481 | }; |
| ... | @@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -469,14 +490,14 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 469 | error.UnsupportedTranslation, | 490 | error.UnsupportedTranslation, |
| 470 | error.UnsupportedType, | 491 | error.UnsupportedType, |
| 471 | => { | 492 | => { |
| 472 | return failDecl(c, var_decl_loc, var_name, "unable to translate initializer", .{}); | 493 | return failDecl(c, var_decl_loc, checked_name, "unable to translate initializer", .{}); |
| 473 | }, | 494 | }, |
| 474 | error.OutOfMemory => |e| return e, | 495 | error.OutOfMemory => |e| return e, |
| 475 | } | 496 | } |
| 476 | else | 497 | else |
| 477 | try transCreateNodeUndefinedLiteral(c); | 498 | try transCreateNodeUndefinedLiteral(c); |
| 478 | } else if (storage_class != .Extern) { | 499 | } else if (storage_class != .Extern) { |
| 479 | return failDecl(c, var_decl_loc, var_name, "non-extern variable has no initializer", .{}); | 500 | return failDecl(c, var_decl_loc, checked_name, "non-extern variable has no initializer", .{}); |
| 480 | } | 501 | } |
| 481 | 502 | ||
| 482 | const node = try c.a().create(ast.Node.VarDecl); | 503 | const node = try c.a().create(ast.Node.VarDecl); |
| ... | @@ -496,269 +517,538 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -496,269 +517,538 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 496 | .init_node = init_node, | 517 | .init_node = init_node, |
| 497 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | 518 | .semicolon_token = try appendToken(c, .Semicolon, ";"), |
| 498 | }; | 519 | }; |
| 499 | return addTopLevelDecl(c, var_name, &node.base); | 520 | return addTopLevelDecl(c, checked_name, &node.base); |
| 500 | } | 521 | } |
| 501 | 522 | ||
| 502 | fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { | 523 | fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, builtin_name: []const u8) !*ast.Node { |
| 503 | if (c.decl_table.contains( | 524 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), builtin_name); |
| 504 | @ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), | 525 | return transCreateNodeIdentifier(c, builtin_name); |
| 505 | )) return; // Avoid processing this decl twice | 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 | const rp = makeRestorePoint(c); | 531 | const rp = makeRestorePoint(c); |
| 507 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | ||
| 508 | const const_tok = try appendToken(c, .Keyword_const, "const"); | ||
| 509 | 532 | ||
| 510 | const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); | 533 | const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); |
| 534 | |||
| 535 | if (mem.eql(u8, typedef_name, "uint8_t")) | ||
| 536 | return transTypeDefAsBuiltin(c, typedef_decl, "u8") | ||
| 537 | else if (mem.eql(u8, typedef_name, "int8_t")) | ||
| 538 | return transTypeDefAsBuiltin(c, typedef_decl, "i8") | ||
| 539 | else if (mem.eql(u8, typedef_name, "uint16_t")) | ||
| 540 | return transTypeDefAsBuiltin(c, typedef_decl, "u16") | ||
| 541 | else if (mem.eql(u8, typedef_name, "int16_t")) | ||
| 542 | return transTypeDefAsBuiltin(c, typedef_decl, "i16") | ||
| 543 | else if (mem.eql(u8, typedef_name, "uint32_t")) | ||
| 544 | return transTypeDefAsBuiltin(c, typedef_decl, "u32") | ||
| 545 | else if (mem.eql(u8, typedef_name, "int32_t")) | ||
| 546 | return transTypeDefAsBuiltin(c, typedef_decl, "i32") | ||
| 547 | else if (mem.eql(u8, typedef_name, "uint64_t")) | ||
| 548 | return transTypeDefAsBuiltin(c, typedef_decl, "u64") | ||
| 549 | else if (mem.eql(u8, typedef_name, "int64_t")) | ||
| 550 | return transTypeDefAsBuiltin(c, typedef_decl, "i64") | ||
| 551 | else if (mem.eql(u8, typedef_name, "intptr_t")) | ||
| 552 | return transTypeDefAsBuiltin(c, typedef_decl, "isize") | ||
| 553 | else if (mem.eql(u8, typedef_name, "uintptr_t")) | ||
| 554 | return transTypeDefAsBuiltin(c, typedef_decl, "usize") | ||
| 555 | else if (mem.eql(u8, typedef_name, "ssize_t")) | ||
| 556 | return transTypeDefAsBuiltin(c, typedef_decl, "isize") | ||
| 557 | else if (mem.eql(u8, typedef_name, "size_t")) | ||
| 558 | return transTypeDefAsBuiltin(c, typedef_decl, "usize"); | ||
| 559 | |||
| 511 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); | 560 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); |
| 512 | const name_tok = try appendIdentifier(c, typedef_name); | 561 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 513 | const eq_tok = try appendToken(c, .Equal, "="); | 562 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| 563 | const node = try transCreateNodeVarDecl(c, true, true, typedef_name); | ||
| 564 | node.eq_token = try appendToken(c, .Equal, "="); | ||
| 514 | 565 | ||
| 515 | const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); | 566 | const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); |
| 516 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); | 567 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); |
| 517 | const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { | 568 | node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { |
| 518 | error.UnsupportedType => { | 569 | error.UnsupportedType => { |
| 519 | return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); | 570 | try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); |
| 571 | return null; | ||
| 520 | }, | 572 | }, |
| 521 | error.OutOfMemory => |e| return e, | 573 | error.OutOfMemory => |e| return e, |
| 522 | }; | 574 | }; |
| 523 | 575 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | |
| 524 | const node = try c.a().create(ast.Node.VarDecl); | ||
| 525 | node.* = ast.Node.VarDecl{ | ||
| 526 | .doc_comments = null, | ||
| 527 | .visib_token = visib_tok, | ||
| 528 | .thread_local_token = null, | ||
| 529 | .name_token = name_tok, | ||
| 530 | .eq_token = eq_tok, | ||
| 531 | .mut_token = const_tok, | ||
| 532 | .comptime_token = null, | ||
| 533 | .extern_export_token = null, | ||
| 534 | .lib_name = null, | ||
| 535 | .type_node = null, | ||
| 536 | .align_node = null, | ||
| 537 | .section_node = null, | ||
| 538 | .init_node = type_node, | ||
| 539 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | ||
| 540 | }; | ||
| 541 | try addTopLevelDecl(c, typedef_name, &node.base); | 576 | try addTopLevelDecl(c, typedef_name, &node.base); |
| 577 | return transCreateNodeIdentifier(c, typedef_name); | ||
| 542 | } | 578 | } |
| 543 | 579 | ||
| 544 | fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { | 580 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { |
| 545 | if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice | 581 | if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| |
| 546 | const rp = makeRestorePoint(c); | 582 | return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice |
| 547 | 583 | const record_loc = ZigClangRecordDecl_getLocation(record_decl); | |
| 548 | const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); | ||
| 549 | |||
| 550 | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) | ||
| 551 | "union" | ||
| 552 | else if (ZigClangRecordDecl_isStruct(record_decl)) | ||
| 553 | "struct" | ||
| 554 | else | ||
| 555 | return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); | ||
| 556 | 584 | ||
| 557 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) | 585 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 558 | return; | 586 | var is_unnamed = false; |
| 587 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) { | ||
| 588 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | ||
| 589 | is_unnamed = true; | ||
| 590 | } | ||
| 559 | 591 | ||
| 560 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 592 | var container_kind_name: []const u8 = undefined; |
| 561 | const const_tok = try appendToken(c, .Keyword_const, "const"); | 593 | var container_kind: std.zig.Token.Id = undefined; |
| 594 | if (ZigClangRecordDecl_isUnion(record_decl)) { | ||
| 595 | container_kind_name = "union"; | ||
| 596 | container_kind = .Keyword_union; | ||
| 597 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { | ||
| 598 | container_kind_name = "struct"; | ||
| 599 | container_kind = .Keyword_struct; | ||
| 600 | } else { | ||
| 601 | try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name}); | ||
| 602 | return null; | ||
| 603 | } | ||
| 562 | 604 | ||
| 563 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); | 605 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 564 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); | 606 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| 565 | const name_tok = try appendIdentifier(c, name); | ||
| 566 | 607 | ||
| 567 | const eq_tok = try appendToken(c, .Equal, "="); | 608 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); |
| 568 | const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { | ||
| 569 | error.UnsupportedType => { | ||
| 570 | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); | ||
| 571 | }, | ||
| 572 | error.OutOfMemory => |e| return e, | ||
| 573 | }; | ||
| 574 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 575 | 609 | ||
| 576 | const node = try c.a().create(ast.Node.VarDecl); | 610 | node.eq_token = try appendToken(c, .Equal, "="); |
| 577 | node.* = ast.Node.VarDecl{ | 611 | |
| 578 | .doc_comments = null, | 612 | var semicolon: ast.TokenIndex = undefined; |
| 579 | .visib_token = visib_tok, | 613 | node.init_node = blk: { |
| 580 | .thread_local_token = null, | 614 | const rp = makeRestorePoint(c); |
| 581 | .name_token = name_tok, | 615 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { |
| 582 | .eq_token = eq_tok, | 616 | const opaque = try transCreateNodeOpaqueType(c); |
| 583 | .mut_token = const_tok, | 617 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 584 | .comptime_token = null, | 618 | break :blk opaque; |
| 585 | .extern_export_token = null, | 619 | }; |
| 586 | .lib_name = null, | 620 | |
| 587 | .type_node = null, | 621 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 588 | .align_node = null, | 622 | const container_tok = try appendToken(c, container_kind, container_kind_name); |
| 589 | .section_node = null, | 623 | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 590 | .init_node = init_node, | 624 | |
| 591 | .semicolon_token = semicolon_token, | 625 | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 626 | container_node.* = .{ | ||
| 627 | .layout_token = extern_tok, | ||
| 628 | .kind_token = container_tok, | ||
| 629 | .init_arg_expr = .None, | ||
| 630 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | ||
| 631 | .lbrace_token = lbrace_token, | ||
| 632 | .rbrace_token = undefined, | ||
| 633 | }; | ||
| 634 | |||
| 635 | var it = ZigClangRecordDecl_field_begin(record_def); | ||
| 636 | const end_it = ZigClangRecordDecl_field_end(record_def); | ||
| 637 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { | ||
| 638 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); | ||
| 639 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); | ||
| 640 | |||
| 641 | if (ZigClangFieldDecl_isBitField(field_decl)) { | ||
| 642 | const opaque = try transCreateNodeOpaqueType(c); | ||
| 643 | semicolon = try appendToken(c, .Semicolon, ";"); | ||
| 644 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); | ||
| 645 | break :blk opaque; | ||
| 646 | } | ||
| 647 | const raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); | ||
| 648 | if (raw_name.len < 1) continue; // fix weird windows bug? | ||
| 649 | const field_name = try appendIdentifier(c, raw_name); | ||
| 650 | _ = try appendToken(c, .Colon, ":"); | ||
| 651 | const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { | ||
| 652 | error.UnsupportedType => { | ||
| 653 | try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); | ||
| 654 | return null; | ||
| 655 | }, | ||
| 656 | else => |e| return e, | ||
| 657 | }; | ||
| 658 | |||
| 659 | const field_node = try c.a().create(ast.Node.ContainerField); | ||
| 660 | field_node.* = .{ | ||
| 661 | .doc_comments = null, | ||
| 662 | .comptime_token = null, | ||
| 663 | .name_token = field_name, | ||
| 664 | .type_expr = field_type, | ||
| 665 | .value_expr = null, | ||
| 666 | .align_expr = null, | ||
| 667 | }; | ||
| 668 | |||
| 669 | try container_node.fields_and_decls.push(&field_node.base); | ||
| 670 | _ = try appendToken(c, .Comma, ","); | ||
| 671 | } | ||
| 672 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | ||
| 673 | semicolon = try appendToken(c, .Semicolon, ";"); | ||
| 674 | break :blk &container_node.base; | ||
| 592 | }; | 675 | }; |
| 676 | node.semicolon_token = semicolon; | ||
| 593 | 677 | ||
| 594 | try addTopLevelDecl(c, name, &node.base); | 678 | try addTopLevelDecl(c, name, &node.base); |
| 595 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | 679 | if (!is_unnamed) |
| 680 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | ||
| 681 | return transCreateNodeIdentifier(c, name); | ||
| 596 | } | 682 | } |
| 597 | 683 | ||
| 598 | fn createAlias(c: *Context, alias: var) !void { | 684 | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { |
| 599 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 685 | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| |
| 600 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | 686 | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice |
| 601 | const name_tok = try appendIdentifier(c, alias.alias); | 687 | const rp = makeRestorePoint(c); |
| 688 | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); | ||
| 602 | 689 | ||
| 603 | const eq_tok = try appendToken(c, .Equal, "="); | 690 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); |
| 604 | const init_node = try transCreateNodeIdentifier(c, alias.name); | 691 | var is_unnamed = false; |
| 692 | if (bare_name.len == 0) { | ||
| 693 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | ||
| 694 | is_unnamed = true; | ||
| 695 | } | ||
| 605 | 696 | ||
| 606 | const node = try c.a().create(ast.Node.VarDecl); | 697 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); |
| 607 | node.* = ast.Node.VarDecl{ | 698 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); |
| 608 | .doc_comments = null, | 699 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); |
| 609 | .visib_token = visib_tok, | 700 | node.eq_token = try appendToken(c, .Equal, "="); |
| 610 | .thread_local_token = null, | ||
| 611 | .name_token = name_tok, | ||
| 612 | .eq_token = eq_tok, | ||
| 613 | .mut_token = mut_tok, | ||
| 614 | .comptime_token = null, | ||
| 615 | .extern_export_token = null, | ||
| 616 | .lib_name = null, | ||
| 617 | .type_node = null, | ||
| 618 | .align_node = null, | ||
| 619 | .section_node = null, | ||
| 620 | .init_node = init_node, | ||
| 621 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | ||
| 622 | }; | ||
| 623 | return addTopLevelDecl(c, alias.alias, &node.base); | ||
| 624 | } | ||
| 625 | 701 | ||
| 626 | const ResultUsed = enum { | 702 | node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { |
| 627 | used, | 703 | var pure_enum = true; |
| 628 | unused, | 704 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 629 | }; | 705 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| 706 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | ||
| 707 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | ||
| 708 | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { | ||
| 709 | pure_enum = false; | ||
| 710 | break; | ||
| 711 | } | ||
| 712 | } | ||
| 630 | 713 | ||
| 631 | const LRValue = enum { | 714 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 632 | l_value, | 715 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); |
| 633 | r_value, | ||
| 634 | }; | ||
| 635 | 716 | ||
| 636 | fn transStmt( | 717 | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 637 | rp: RestorePoint, | 718 | container_node.* = .{ |
| 638 | scope: *Scope, | 719 | .layout_token = extern_tok, |
| 639 | stmt: *const ZigClangStmt, | 720 | .kind_token = container_tok, |
| 640 | result_used: ResultUsed, | 721 | .init_arg_expr = .None, |
| 641 | lrvalue: LRValue, | 722 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 642 | ) TransError!*ast.Node { | 723 | .lbrace_token = undefined, |
| 643 | const sc = ZigClangStmt_getStmtClass(stmt); | 724 | .rbrace_token = undefined, |
| 644 | switch (sc) { | 725 | }; |
| 645 | .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used), | ||
| 646 | .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)), | ||
| 647 | .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const ZigClangCStyleCastExpr, stmt), result_used, lrvalue), | ||
| 648 | .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)), | ||
| 649 | .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue), | ||
| 650 | .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used), | ||
| 651 | .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), | ||
| 652 | .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), | ||
| 653 | .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), | ||
| 654 | .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue), | ||
| 655 | .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), | ||
| 656 | .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), | ||
| 657 | else => { | ||
| 658 | return revertAndWarn( | ||
| 659 | rp, | ||
| 660 | error.UnsupportedTranslation, | ||
| 661 | ZigClangStmt_getBeginLoc(stmt), | ||
| 662 | "TODO implement translation of stmt class {}", | ||
| 663 | .{@tagName(sc)}, | ||
| 664 | ); | ||
| 665 | }, | ||
| 666 | } | ||
| 667 | } | ||
| 668 | 726 | ||
| 669 | fn transBinaryOperator( | 727 | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); |
| 670 | rp: RestorePoint, | 728 | |
| 671 | scope: *Scope, | 729 | // TODO only emit this tag type if the enum tag type is not the default. |
| 672 | stmt: *const ZigClangBinaryOperator, | 730 | // I don't know what the default is, need to figure out how clang is deciding. |
| 673 | result_used: ResultUsed, | 731 | // it appears to at least be different across gcc/msvc |
| 674 | ) TransError!*ast.Node { | 732 | if (!isCBuiltinType(int_type, .UInt) and |
| 675 | const op = ZigClangBinaryOperator_getOpcode(stmt); | 733 | !isCBuiltinType(int_type, .Int)) |
| 676 | const qt = ZigClangBinaryOperator_getType(stmt); | 734 | { |
| 677 | switch (op) { | 735 | _ = try appendToken(c, .LParen, "("); |
| 678 | .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn( | 736 | container_node.init_arg_expr = .{ |
| 679 | rp, | 737 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { |
| 680 | error.UnsupportedTranslation, | 738 | error.UnsupportedType => { |
| 681 | ZigClangBinaryOperator_getBeginLoc(stmt), | 739 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); |
| 682 | "TODO: handle more C binary operators: {}", | 740 | return null; |
| 683 | .{op}, | 741 | }, |
| 684 | ), | 742 | else => |e| return e, |
| 685 | .Assign => return &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base, | 743 | }, |
| 686 | .Add => { | 744 | }; |
| 687 | const node = if (cIsUnsignedInteger(qt)) | 745 | _ = try appendToken(c, .RParen, ")"); |
| 688 | try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true) | 746 | } |
| 747 | |||
| 748 | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); | ||
| 749 | |||
| 750 | it = ZigClangEnumDecl_enumerator_begin(enum_def); | ||
| 751 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); | ||
| 752 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | ||
| 753 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | ||
| 754 | |||
| 755 | const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); | ||
| 756 | |||
| 757 | const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name)) | ||
| 758 | enum_val_name[bare_name.len..] | ||
| 689 | else | 759 | else |
| 690 | try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true); | 760 | enum_val_name; |
| 691 | return maybeSuppressResult(rp, scope, result_used, node); | 761 | |
| 762 | const field_name_tok = try appendIdentifier(c, field_name); | ||
| 763 | |||
| 764 | const int_node = if (!pure_enum) blk: { | ||
| 765 | _ = try appendToken(c, .Colon, "="); | ||
| 766 | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | ||
| 767 | } else | ||
| 768 | null; | ||
| 769 | |||
| 770 | const field_node = try c.a().create(ast.Node.ContainerField); | ||
| 771 | field_node.* = .{ | ||
| 772 | .doc_comments = null, | ||
| 773 | .comptime_token = null, | ||
| 774 | .name_token = field_name_tok, | ||
| 775 | .type_expr = null, | ||
| 776 | .value_expr = int_node, | ||
| 777 | .align_expr = null, | ||
| 778 | }; | ||
| 779 | |||
| 780 | try container_node.fields_and_decls.push(&field_node.base); | ||
| 781 | _ = try appendToken(c, .Comma, ","); | ||
| 782 | // In C each enum value is in the global namespace. So we put them there too. | ||
| 783 | // At this point we can rely on the enum emitting successfully. | ||
| 784 | const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); | ||
| 785 | tld_node.eq_token = try appendToken(c, .Equal, "="); | ||
| 786 | tld_node.init_node = try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | ||
| 787 | tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 788 | try addTopLevelDecl(c, field_name, &tld_node.base); | ||
| 789 | } | ||
| 790 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | ||
| 791 | |||
| 792 | break :blk &container_node.base; | ||
| 793 | } else | ||
| 794 | try transCreateNodeOpaqueType(c); | ||
| 795 | |||
| 796 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 797 | |||
| 798 | try addTopLevelDecl(c, name, &node.base); | ||
| 799 | if (!is_unnamed) | ||
| 800 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | ||
| 801 | return transCreateNodeIdentifier(c, name); | ||
| 802 | } | ||
| 803 | |||
| 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 => { | 851 | .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), |
| 694 | const node = if (cIsUnsignedInteger(qt)) | 852 | .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), |
| 695 | try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true) | 853 | .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)), |
| 696 | else | 854 | .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), |
| 697 | try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true); | 855 | .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), |
| 698 | return maybeSuppressResult(rp, scope, result_used, node); | 856 | .NullStmtClass => { |
| 857 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 858 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 859 | return &block.base; | ||
| 699 | }, | 860 | }, |
| 700 | .Mul => { | 861 | .ContinueStmtClass => return try transCreateNodeContinue(rp.c), |
| 701 | const node = if (cIsUnsignedInteger(qt)) | 862 | .BreakStmtClass => return transBreak(rp, scope), |
| 702 | try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true) | 863 | .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)), |
| 703 | else | 864 | .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const ZigClangFloatingLiteral, stmt), result_used), |
| 704 | try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true); | 865 | .ConditionalOperatorClass => return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used), |
| 705 | return maybeSuppressResult(rp, scope, result_used, node); | 866 | .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const ZigClangSwitchStmt, stmt)), |
| 867 | .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const ZigClangCaseStmt, stmt)), | ||
| 868 | .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)), | ||
| 869 | .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), | ||
| 870 | .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), | ||
| 871 | .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), | ||
| 872 | .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), | ||
| 873 | .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), | ||
| 874 | .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used), | ||
| 875 | .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used), | ||
| 876 | .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used), | ||
| 877 | .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used), | ||
| 878 | .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used), | ||
| 879 | else => { | ||
| 880 | return revertAndWarn( | ||
| 881 | rp, | ||
| 882 | error.UnsupportedTranslation, | ||
| 883 | ZigClangStmt_getBeginLoc(stmt), | ||
| 884 | "TODO implement translation of stmt class {}", | ||
| 885 | .{@tagName(sc)}, | ||
| 886 | ); | ||
| 887 | }, | ||
| 888 | } | ||
| 889 | } | ||
| 890 | |||
| 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 | .Div => { | 934 | .Div => { |
| 708 | if (!cIsUnsignedInteger(qt)) { | 935 | if (!cIsUnsignedInteger(qt)) { |
| 709 | // signed integer division uses @divTrunc | 936 | // signed integer division uses @divTrunc |
| 710 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); | 937 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); |
| 711 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | 938 | try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); |
| 712 | try div_trunc_node.params.push(lhs); | ||
| 713 | _ = try appendToken(rp.c, .Comma, ","); | 939 | _ = try appendToken(rp.c, .Comma, ","); |
| 714 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 940 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 715 | try div_trunc_node.params.push(rhs); | 941 | try div_trunc_node.params.push(rhs); |
| 716 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 942 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 717 | return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); | 943 | return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); |
| 718 | } else { | ||
| 719 | // unsigned/float division uses the operator | ||
| 720 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true); | ||
| 721 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 722 | } | 944 | } |
| 723 | }, | 945 | }, |
| 724 | .Rem => { | 946 | .Rem => { |
| 725 | if (!cIsUnsignedInteger(qt)) { | 947 | if (!cIsUnsignedInteger(qt)) { |
| 726 | // signed integer division uses @rem | 948 | // signed integer division uses @rem |
| 727 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); | 949 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); |
| 728 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | 950 | try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); |
| 729 | try rem_node.params.push(lhs); | ||
| 730 | _ = try appendToken(rp.c, .Comma, ","); | 951 | _ = try appendToken(rp.c, .Comma, ","); |
| 731 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 952 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 732 | try rem_node.params.push(rhs); | 953 | try rem_node.params.push(rhs); |
| 733 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 954 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 734 | return maybeSuppressResult(rp, scope, result_used, &rem_node.base); | 955 | return maybeSuppressResult(rp, scope, result_used, &rem_node.base); |
| 956 | } | ||
| 957 | }, | ||
| 958 | .Shl => { | ||
| 959 | const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<"); | ||
| 960 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 961 | }, | ||
| 962 | .Shr => { | ||
| 963 | const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>"); | ||
| 964 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 965 | }, | ||
| 966 | .LAnd => { | ||
| 967 | const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true); | ||
| 968 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 969 | }, | ||
| 970 | .LOr => { | ||
| 971 | const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true); | ||
| 972 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 973 | }, | ||
| 974 | else => {}, | ||
| 975 | } | ||
| 976 | const lhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | ||
| 977 | switch (op) { | ||
| 978 | .Add => { | ||
| 979 | if (cIsUnsignedInteger(qt)) { | ||
| 980 | op_token = try appendToken(rp.c, .PlusPercent, "+%"); | ||
| 981 | op_id = .AddWrap; | ||
| 735 | } else { | 982 | } else { |
| 736 | // unsigned/float division uses the operator | 983 | op_token = try appendToken(rp.c, .Plus, "+"); |
| 737 | const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true); | 984 | op_id = .Add; |
| 738 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 739 | } | 985 | } |
| 740 | }, | 986 | }, |
| 741 | .Shl, | 987 | .Sub => { |
| 742 | .Shr, | 988 | if (cIsUnsignedInteger(qt)) { |
| 743 | .LT, | 989 | op_token = try appendToken(rp.c, .MinusPercent, "-%"); |
| 744 | .GT, | 990 | op_id = .SubWrap; |
| 745 | .LE, | 991 | } else { |
| 746 | .GE, | 992 | op_token = try appendToken(rp.c, .Minus, "-"); |
| 747 | .EQ, | 993 | op_id = .Sub; |
| 748 | .NE, | 994 | } |
| 749 | .And, | 995 | }, |
| 750 | .Xor, | 996 | .Mul => { |
| 751 | .Or, | 997 | if (cIsUnsignedInteger(qt)) { |
| 752 | .LAnd, | 998 | op_token = try appendToken(rp.c, .AsteriskPercent, "*%"); |
| 753 | .LOr, | 999 | op_id = .MulWrap; |
| 754 | .Comma, | 1000 | } else { |
| 755 | => return revertAndWarn( | 1001 | op_token = try appendToken(rp.c, .Asterisk, "*"); |
| 756 | rp, | 1002 | op_id = .Mul; |
| 757 | error.UnsupportedTranslation, | 1003 | } |
| 758 | ZigClangBinaryOperator_getBeginLoc(stmt), | 1004 | }, |
| 759 | "TODO: handle more C binary operators: {}", | 1005 | .Div => { |
| 760 | .{op}, | 1006 | // unsigned/float division uses the operator |
| 761 | ), | 1007 | op_id = .Div; |
| 1008 | op_token = try appendToken(rp.c, .Slash, "/"); | ||
| 1009 | }, | ||
| 1010 | .Rem => { | ||
| 1011 | // unsigned/float division uses the operator | ||
| 1012 | op_id = .Mod; | ||
| 1013 | op_token = try appendToken(rp.c, .Percent, "%"); | ||
| 1014 | }, | ||
| 1015 | .LT => { | ||
| 1016 | op_id = .LessThan; | ||
| 1017 | op_token = try appendToken(rp.c, .AngleBracketLeft, "<"); | ||
| 1018 | }, | ||
| 1019 | .GT => { | ||
| 1020 | op_id = .GreaterThan; | ||
| 1021 | op_token = try appendToken(rp.c, .AngleBracketRight, ">"); | ||
| 1022 | }, | ||
| 1023 | .LE => { | ||
| 1024 | op_id = .LessOrEqual; | ||
| 1025 | op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<="); | ||
| 1026 | }, | ||
| 1027 | .GE => { | ||
| 1028 | op_id = .GreaterOrEqual; | ||
| 1029 | op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">="); | ||
| 1030 | }, | ||
| 1031 | .EQ => { | ||
| 1032 | op_id = .EqualEqual; | ||
| 1033 | op_token = try appendToken(rp.c, .EqualEqual, "=="); | ||
| 1034 | }, | ||
| 1035 | .NE => { | ||
| 1036 | op_id = .BangEqual; | ||
| 1037 | op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1038 | }, | ||
| 1039 | .And => { | ||
| 1040 | op_id = .BitAnd; | ||
| 1041 | op_token = try appendToken(rp.c, .Ampersand, "&"); | ||
| 1042 | }, | ||
| 1043 | .Xor => { | ||
| 1044 | op_id = .BitXor; | ||
| 1045 | op_token = try appendToken(rp.c, .Caret, "^"); | ||
| 1046 | }, | ||
| 1047 | .Or => { | ||
| 1048 | op_id = .BitOr; | ||
| 1049 | op_token = try appendToken(rp.c, .Pipe, "|"); | ||
| 1050 | }, | ||
| 1051 | .Assign, | ||
| 762 | .MulAssign, | 1052 | .MulAssign, |
| 763 | .DivAssign, | 1053 | .DivAssign, |
| 764 | .RemAssign, | 1054 | .RemAssign, |
| ... | @@ -772,6 +1062,9 @@ fn transBinaryOperator( | ... | @@ -772,6 +1062,9 @@ fn transBinaryOperator( |
| 772 | => unreachable, | 1062 | => unreachable, |
| 773 | else => unreachable, | 1063 | else => unreachable, |
| 774 | } | 1064 | } |
| 1065 | |||
| 1066 | const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | ||
| 1067 | return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true); | ||
| 775 | } | 1068 | } |
| 776 | 1069 | ||
| 777 | fn transCompoundStmtInline( | 1070 | fn transCompoundStmtInline( |
| ... | @@ -790,11 +1083,11 @@ fn transCompoundStmtInline( | ... | @@ -790,11 +1083,11 @@ fn transCompoundStmtInline( |
| 790 | } | 1083 | } |
| 791 | 1084 | ||
| 792 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { | 1085 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { |
| 793 | const block_node = try transCreateNodeBlock(rp.c, null); | 1086 | const block_scope = try Scope.Block.init(rp.c, scope, null); |
| 794 | const block_scope = try Scope.Block.init(rp.c, scope, block_node); | 1087 | block_scope.block_node = try transCreateNodeBlock(rp.c, null); |
| 795 | try transCompoundStmtInline(rp, &block_scope.base, stmt, block_node); | 1088 | try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); |
| 796 | block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 1089 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 797 | return &block_node.base; | 1090 | return &block_scope.block_node.base; |
| 798 | } | 1091 | } |
| 799 | 1092 | ||
| 800 | fn transCStyleCastExprClass( | 1093 | fn transCStyleCastExprClass( |
| ... | @@ -818,7 +1111,7 @@ fn transCStyleCastExprClass( | ... | @@ -818,7 +1111,7 @@ fn transCStyleCastExprClass( |
| 818 | 1111 | ||
| 819 | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { | 1112 | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { |
| 820 | const c = rp.c; | 1113 | const c = rp.c; |
| 821 | const block_scope = scope.findBlockScope(); | 1114 | const block_scope = scope.findBlockScope(c) catch unreachable; |
| 822 | 1115 | ||
| 823 | var it = ZigClangDeclStmt_decl_begin(stmt); | 1116 | var it = ZigClangDeclStmt_decl_begin(stmt); |
| 824 | const end_it = ZigClangDeclStmt_decl_end(stmt); | 1117 | const end_it = ZigClangDeclStmt_decl_end(stmt); |
| ... | @@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) | ... | @@ -832,10 +1125,6 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) |
| 832 | else | 1125 | else |
| 833 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | 1126 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 834 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); | 1127 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| 835 | const mut_token = if (ZigClangQualType_isConstQualified(qual_type)) | ||
| 836 | try appendToken(c, .Keyword_const, "const") | ||
| 837 | else | ||
| 838 | try appendToken(c, .Keyword_var, "var"); | ||
| 839 | const name = try c.str(ZigClangDecl_getName_bytes_begin( | 1128 | const name = try c.str(ZigClangDecl_getName_bytes_begin( |
| 840 | @ptrCast(*const ZigClangDecl, var_decl), | 1129 | @ptrCast(*const ZigClangDecl, var_decl), |
| 841 | )); | 1130 | )); |
| ... | @@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) | ... | @@ -843,36 +1132,25 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) |
| 843 | try block_scope.variables.push(.{ .name = name, .alias = a }); | 1132 | try block_scope.variables.push(.{ .name = name, .alias = a }); |
| 844 | break :blk a; | 1133 | break :blk a; |
| 845 | } else name; | 1134 | } else name; |
| 846 | const name_token = try appendIdentifier(c, checked_name); | 1135 | const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), checked_name); |
| 847 | 1136 | ||
| 848 | const colon_token = try appendToken(c, .Colon, ":"); | 1137 | _ = try appendToken(c, .Colon, ":"); |
| 849 | const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); | 1138 | const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); |
| 850 | const type_node = try transQualType(rp, qual_type, loc); | 1139 | node.type_node = try transQualType(rp, qual_type, loc); |
| 851 | 1140 | ||
| 852 | const eq_token = try appendToken(c, .Equal, "="); | 1141 | node.eq_token = try appendToken(c, .Equal, "="); |
| 853 | const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| | 1142 | var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| |
| 854 | try transExpr(rp, scope, expr, .used, .r_value) | 1143 | try transExpr(rp, scope, expr, .used, .r_value) |
| 855 | else | 1144 | else |
| 856 | try transCreateNodeUndefinedLiteral(c); | 1145 | try transCreateNodeUndefinedLiteral(c); |
| 857 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | 1146 | if (isBoolRes(init_node)) { |
| 858 | 1147 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | |
| 859 | const node = try c.a().create(ast.Node.VarDecl); | 1148 | try builtin_node.params.push(init_node); |
| 860 | node.* = ast.Node.VarDecl{ | 1149 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 861 | .doc_comments = null, | 1150 | init_node = &builtin_node.base; |
| 862 | .visib_token = null, | 1151 | } |
| 863 | .thread_local_token = thread_local_token, | 1152 | node.init_node = init_node; |
| 864 | .name_token = name_token, | 1153 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 865 | .eq_token = eq_token, | ||
| 866 | .mut_token = mut_token, | ||
| 867 | .comptime_token = null, | ||
| 868 | .extern_export_token = null, | ||
| 869 | .lib_name = null, | ||
| 870 | .type_node = type_node, | ||
| 871 | .align_node = null, // TODO ?*Node, | ||
| 872 | .section_node = null, | ||
| 873 | .init_node = init_node, | ||
| 874 | .semicolon_token = semicolon_token, | ||
| 875 | }; | ||
| 876 | try block_scope.block_node.statements.push(&node.base); | 1154 | try block_scope.block_node.statements.push(&node.base); |
| 877 | }, | 1155 | }, |
| 878 | else => |kind| return revertAndWarn( | 1156 | else => |kind| return revertAndWarn( |
| ... | @@ -896,7 +1174,6 @@ fn transDeclRefExpr( | ... | @@ -896,7 +1174,6 @@ fn transDeclRefExpr( |
| 896 | const value_decl = ZigClangDeclRefExpr_getDecl(expr); | 1174 | const value_decl = ZigClangDeclRefExpr_getDecl(expr); |
| 897 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); | 1175 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); |
| 898 | const checked_name = if (scope.getAlias(name)) |a| a else name; | 1176 | const checked_name = if (scope.getAlias(name)) |a| a else name; |
| 899 | if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name); | ||
| 900 | return transCreateNodeIdentifier(rp.c, checked_name); | 1177 | return transCreateNodeIdentifier(rp.c, checked_name); |
| 901 | } | 1178 | } |
| 902 | 1179 | ||
| ... | @@ -909,25 +1186,58 @@ fn transImplicitCastExpr( | ... | @@ -909,25 +1186,58 @@ fn transImplicitCastExpr( |
| 909 | const c = rp.c; | 1186 | const c = rp.c; |
| 910 | const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); | 1187 | const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); |
| 911 | const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); | 1188 | const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); |
| 1189 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); | ||
| 1190 | const src_type = getExprQualType(c, sub_expr); | ||
| 912 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { | 1191 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { |
| 913 | .BitCast => { | 1192 | .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => { |
| 914 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); | ||
| 915 | const src_type = getExprQualType(c, sub_expr); | ||
| 916 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); | 1193 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); |
| 917 | }, | 1194 | }, |
| 918 | .IntegralCast => { | 1195 | .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => { |
| 919 | const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr)); | ||
| 920 | const src_type = ZigClangExpr_getType(sub_expr); | ||
| 921 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); | ||
| 922 | }, | ||
| 923 | .FunctionToPointerDecay, .ArrayToPointerDecay => { | ||
| 924 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); | 1196 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 925 | }, | 1197 | }, |
| 926 | .LValueToRValue, .NoOp => { | ||
| 927 | return transExpr(rp, scope, sub_expr, .used, .r_value); | ||
| 928 | }, | ||
| 929 | .NullToPointer => { | 1198 | .NullToPointer => { |
| 930 | return transCreateNodeNullLiteral(rp.c); | 1199 | return try transCreateNodeNullLiteral(rp.c); |
| 1200 | }, | ||
| 1201 | .PointerToBoolean => { | ||
| 1202 | // @ptrToInt(val) != 0 | ||
| 1203 | const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); | ||
| 1204 | try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); | ||
| 1205 | ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1206 | |||
| 1207 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1208 | const rhs_node = try transCreateNodeInt(rp.c, 0); | ||
| 1209 | return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false); | ||
| 1210 | }, | ||
| 1211 | .IntegralToBoolean => { | ||
| 1212 | // val != 0 | ||
| 1213 | const node = try transExpr(rp, scope, sub_expr, .used, .r_value); | ||
| 1214 | |||
| 1215 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1216 | const rhs_node = try transCreateNodeInt(rp.c, 0); | ||
| 1217 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, result_used, false); | ||
| 1218 | }, | ||
| 1219 | .PointerToIntegral => { | ||
| 1220 | // @intCast(dest_type, @ptrToInt(val)) | ||
| 1221 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | ||
| 1222 | try cast_node.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); | ||
| 1223 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1224 | |||
| 1225 | const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); | ||
| 1226 | try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); | ||
| 1227 | ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1228 | try cast_node.params.push(&ptr_to_int.base); | ||
| 1229 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1230 | return maybeSuppressResult(rp, scope, result_used, &cast_node.base); | ||
| 1231 | }, | ||
| 1232 | .IntegralToPointer => { | ||
| 1233 | // @intToPtr(dest_type, val) | ||
| 1234 | const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); | ||
| 1235 | try int_to_ptr.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); | ||
| 1236 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1237 | |||
| 1238 | try int_to_ptr.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); | ||
| 1239 | int_to_ptr.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1240 | return maybeSuppressResult(rp, scope, result_used, &int_to_ptr.base); | ||
| 931 | }, | 1241 | }, |
| 932 | else => |kind| return revertAndWarn( | 1242 | else => |kind| return revertAndWarn( |
| 933 | rp, | 1243 | rp, |
| ... | @@ -939,50 +1249,195 @@ fn transImplicitCastExpr( | ... | @@ -939,50 +1249,195 @@ fn transImplicitCastExpr( |
| 939 | } | 1249 | } |
| 940 | } | 1250 | } |
| 941 | 1251 | ||
| 942 | fn transIntegerLiteral( | 1252 | fn transBoolExpr( |
| 943 | rp: RestorePoint, | 1253 | rp: RestorePoint, |
| 944 | scope: *Scope, | 1254 | scope: *Scope, |
| 945 | expr: *const ZigClangIntegerLiteral, | 1255 | expr: *const ZigClangExpr, |
| 946 | result_used: ResultUsed, | 1256 | used: ResultUsed, |
| 1257 | lrvalue: LRValue, | ||
| 1258 | grouped: bool, | ||
| 947 | ) TransError!*ast.Node { | 1259 | ) TransError!*ast.Node { |
| 948 | var eval_result: ZigClangExprEvalResult = undefined; | 1260 | const lparen = if (grouped) |
| 949 | if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) { | 1261 | try appendToken(rp.c, .LParen, "(") |
| 950 | const loc = ZigClangIntegerLiteral_getBeginLoc(expr); | 1262 | else |
| 951 | return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); | 1263 | undefined; |
| 1264 | var res = try transExpr(rp, scope, expr, used, lrvalue); | ||
| 1265 | |||
| 1266 | if (isBoolRes(res)) { | ||
| 1267 | if (!grouped and res.id == .GroupedExpression) { | ||
| 1268 | const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res); | ||
| 1269 | res = group.expr; | ||
| 1270 | // get zig fmt to work properly | ||
| 1271 | tokenSlice(rp.c, group.lparen)[0] = ')'; | ||
| 1272 | } | ||
| 1273 | return res; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr)); | ||
| 1277 | const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used); | ||
| 1278 | |||
| 1279 | if (grouped) { | ||
| 1280 | const rparen = try appendToken(rp.c, .RParen, ")"); | ||
| 1281 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | ||
| 1282 | grouped_expr.* = .{ | ||
| 1283 | .lparen = lparen, | ||
| 1284 | .expr = node, | ||
| 1285 | .rparen = rparen, | ||
| 1286 | }; | ||
| 1287 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | ||
| 1288 | } else { | ||
| 1289 | return maybeSuppressResult(rp, scope, used, node); | ||
| 952 | } | 1290 | } |
| 953 | const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); | ||
| 954 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 955 | } | 1291 | } |
| 956 | 1292 | ||
| 957 | fn transReturnStmt( | 1293 | fn isBoolRes(res: *ast.Node) bool { |
| 958 | rp: RestorePoint, | 1294 | switch (res.id) { |
| 959 | scope: *Scope, | 1295 | .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) { |
| 960 | expr: *const ZigClangReturnStmt, | 1296 | .BoolOr, |
| 961 | ) TransError!*ast.Node { | 1297 | .BoolAnd, |
| 962 | const node = try transCreateNodeReturnExpr(rp.c); | 1298 | .EqualEqual, |
| 963 | if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { | 1299 | .BangEqual, |
| 964 | node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value); | 1300 | .LessThan, |
| 1301 | .GreaterThan, | ||
| 1302 | .LessOrEqual, | ||
| 1303 | .GreaterOrEqual, | ||
| 1304 | => return true, | ||
| 1305 | |||
| 1306 | else => {}, | ||
| 1307 | }, | ||
| 1308 | .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) { | ||
| 1309 | .BoolNot => return true, | ||
| 1310 | |||
| 1311 | else => {}, | ||
| 1312 | }, | ||
| 1313 | .BoolLiteral => return true, | ||
| 1314 | .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr), | ||
| 1315 | else => {}, | ||
| 965 | } | 1316 | } |
| 966 | _ = try appendToken(rp.c, .Semicolon, ";"); | 1317 | return false; |
| 967 | return &node.base; | ||
| 968 | } | 1318 | } |
| 969 | 1319 | ||
| 970 | fn transStringLiteral( | 1320 | fn finishBoolExpr( |
| 971 | rp: RestorePoint, | 1321 | rp: RestorePoint, |
| 972 | scope: *Scope, | 1322 | scope: *Scope, |
| 973 | stmt: *const ZigClangStringLiteral, | 1323 | loc: ZigClangSourceLocation, |
| 974 | result_used: ResultUsed, | 1324 | ty: *const ZigClangType, |
| 1325 | node: *ast.Node, | ||
| 1326 | used: ResultUsed, | ||
| 975 | ) TransError!*ast.Node { | 1327 | ) TransError!*ast.Node { |
| 976 | const kind = ZigClangStringLiteral_getKind(stmt); | 1328 | switch (ZigClangType_getTypeClass(ty)) { |
| 977 | switch (kind) { | 1329 | .Builtin => { |
| 978 | .Ascii, .UTF8 => { | 1330 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 979 | var len: usize = undefined; | 1331 | |
| 980 | const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len); | 1332 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 981 | const str = bytes_ptr[0..len]; | 1333 | .Bool => return node, |
| 982 | 1334 | .Char_U, | |
| 983 | var char_buf: [4]u8 = undefined; | 1335 | .UChar, |
| 984 | len = 0; | 1336 | .Char_S, |
| 985 | for (str) |c| len += escapeChar(c, &char_buf).len; | 1337 | .SChar, |
| 1338 | .UShort, | ||
| 1339 | .UInt, | ||
| 1340 | .ULong, | ||
| 1341 | .ULongLong, | ||
| 1342 | .Short, | ||
| 1343 | .Int, | ||
| 1344 | .Long, | ||
| 1345 | .LongLong, | ||
| 1346 | .UInt128, | ||
| 1347 | .Int128, | ||
| 1348 | .Float, | ||
| 1349 | .Double, | ||
| 1350 | .Float128, | ||
| 1351 | .LongDouble, | ||
| 1352 | .WChar_U, | ||
| 1353 | .Char8, | ||
| 1354 | .Char16, | ||
| 1355 | .Char32, | ||
| 1356 | .WChar_S, | ||
| 1357 | .Float16, | ||
| 1358 | => { | ||
| 1359 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1360 | const rhs_node = try transCreateNodeInt(rp.c, 0); | ||
| 1361 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | ||
| 1362 | }, | ||
| 1363 | .NullPtr => { | ||
| 1364 | const op_token = try appendToken(rp.c, .EqualEqual, "=="); | ||
| 1365 | const rhs_node = try transCreateNodeNullLiteral(rp.c); | ||
| 1366 | return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false); | ||
| 1367 | }, | ||
| 1368 | else => {}, | ||
| 1369 | } | ||
| 1370 | }, | ||
| 1371 | .Pointer => { | ||
| 1372 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1373 | const rhs_node = try transCreateNodeNullLiteral(rp.c); | ||
| 1374 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | ||
| 1375 | }, | ||
| 1376 | .Typedef => { | ||
| 1377 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); | ||
| 1378 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); | ||
| 1379 | const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); | ||
| 1380 | return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used); | ||
| 1381 | }, | ||
| 1382 | .Enum => { | ||
| 1383 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | ||
| 1384 | const rhs_node = try transCreateNodeInt(rp.c, 0); | ||
| 1385 | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); | ||
| 1386 | }, | ||
| 1387 | .Elaborated => { | ||
| 1388 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); | ||
| 1389 | const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty); | ||
| 1390 | return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used); | ||
| 1391 | }, | ||
| 1392 | else => {}, | ||
| 1393 | } | ||
| 1394 | return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{}); | ||
| 1395 | } | ||
| 1396 | |||
| 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 | const buf = try rp.c.a().alloc(u8, len + "\"\"".len); | 1442 | const buf = try rp.c.a().alloc(u8, len + "\"\"".len); |
| 988 | buf[0] = '"'; | 1443 | buf[0] = '"'; |
| ... | @@ -991,7 +1446,7 @@ fn transStringLiteral( | ... | @@ -991,7 +1446,7 @@ fn transStringLiteral( |
| 991 | 1446 | ||
| 992 | const token = try appendToken(rp.c, .StringLiteral, buf); | 1447 | const token = try appendToken(rp.c, .StringLiteral, buf); |
| 993 | const node = try rp.c.a().create(ast.Node.StringLiteral); | 1448 | const node = try rp.c.a().create(ast.Node.StringLiteral); |
| 994 | node.* = ast.Node.StringLiteral{ | 1449 | node.* = .{ |
| 995 | .token = token, | 1450 | .token = token, |
| 996 | }; | 1451 | }; |
| 997 | return maybeSuppressResult(rp, scope, result_used, &node.base); | 1452 | return maybeSuppressResult(rp, scope, result_used, &node.base); |
| ... | @@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { | ... | @@ -1019,25 +1474,22 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { |
| 1019 | var i: usize = 0; | 1474 | var i: usize = 0; |
| 1020 | for (s) |c| { | 1475 | for (s) |c| { |
| 1021 | const escaped = escapeChar(c, &char_buf); | 1476 | const escaped = escapeChar(c, &char_buf); |
| 1022 | std.mem.copy(u8, buf[i..], escaped); | 1477 | mem.copy(u8, buf[i..], escaped); |
| 1023 | i += escaped.len; | 1478 | i += escaped.len; |
| 1024 | } | 1479 | } |
| 1025 | } | 1480 | } |
| 1026 | 1481 | ||
| 1027 | // Returns either a string literal or a slice of `buf`. | 1482 | // Returns either a string literal or a slice of `buf`. |
| 1028 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { | 1483 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { |
| 1029 | // TODO: https://github.com/ziglang/zig/issues/2749 | 1484 | return switch (c) { |
| 1030 | const escaped = switch (c) { | 1485 | '\"' => "\\\""[0..], |
| 1031 | // Printable ASCII except for ' " \ | 1486 | '\'' => "\\'"[0..], |
| 1032 | ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..], | 1487 | '\\' => "\\\\"[0..], |
| 1033 | '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..], | 1488 | '\n' => "\\n"[0..], |
| 1034 | '\n' => return "\\n"[0..], | 1489 | '\r' => "\\r"[0..], |
| 1035 | '\r' => return "\\r"[0..], | 1490 | '\t' => "\\t"[0..], |
| 1036 | '\t' => return "\\t"[0..], | 1491 | else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable, |
| 1037 | else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable, | ||
| 1038 | }; | 1492 | }; |
| 1039 | std.mem.copy(u8, char_buf, escaped); | ||
| 1040 | return char_buf[0..escaped.len]; | ||
| 1041 | } | 1493 | } |
| 1042 | 1494 | ||
| 1043 | fn transCCast( | 1495 | fn transCCast( |
| ... | @@ -1071,6 +1523,55 @@ fn transCCast( | ... | @@ -1071,6 +1523,55 @@ fn transCCast( |
| 1071 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1523 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1072 | return &builtin_node.base; | 1524 | return &builtin_node.base; |
| 1073 | } | 1525 | } |
| 1526 | if (cIsFloating(src_type) and cIsFloating(dst_type)) { | ||
| 1527 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast"); | ||
| 1528 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | ||
| 1529 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1530 | try builtin_node.params.push(expr); | ||
| 1531 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1532 | return &builtin_node.base; | ||
| 1533 | } | ||
| 1534 | if (cIsFloating(src_type) and !cIsFloating(dst_type)) { | ||
| 1535 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt"); | ||
| 1536 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | ||
| 1537 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1538 | try builtin_node.params.push(expr); | ||
| 1539 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1540 | return &builtin_node.base; | ||
| 1541 | } | ||
| 1542 | if (!cIsFloating(src_type) and cIsFloating(dst_type)) { | ||
| 1543 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat"); | ||
| 1544 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | ||
| 1545 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1546 | try builtin_node.params.push(expr); | ||
| 1547 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1548 | return &builtin_node.base; | ||
| 1549 | } | ||
| 1550 | if (ZigClangQualType_getTypeClass(src_type) == .Elaborated) { | ||
| 1551 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(src_type)); | ||
| 1552 | return transCCast(rp, scope, loc, dst_type, ZigClangElaboratedType_getNamedType(elaborated_ty), expr); | ||
| 1553 | } | ||
| 1554 | if (ZigClangQualType_getTypeClass(dst_type) == .Elaborated) { | ||
| 1555 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(dst_type)); | ||
| 1556 | return transCCast(rp, scope, loc, ZigClangElaboratedType_getNamedType(elaborated_ty), src_type, expr); | ||
| 1557 | } | ||
| 1558 | if (ZigClangQualType_getTypeClass(dst_type) == .Enum) | ||
| 1559 | { | ||
| 1560 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); | ||
| 1561 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | ||
| 1562 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1563 | try builtin_node.params.push(expr); | ||
| 1564 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1565 | return &builtin_node.base; | ||
| 1566 | } | ||
| 1567 | if (ZigClangQualType_getTypeClass(src_type) == .Enum and | ||
| 1568 | ZigClangQualType_getTypeClass(dst_type) != .Enum) | ||
| 1569 | { | ||
| 1570 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt"); | ||
| 1571 | try builtin_node.params.push(expr); | ||
| 1572 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1573 | return &builtin_node.base; | ||
| 1574 | } | ||
| 1074 | // TODO: maybe widen to increase size | 1575 | // TODO: maybe widen to increase size |
| 1075 | // TODO: maybe bitcast to change sign | 1576 | // TODO: maybe bitcast to change sign |
| 1076 | // TODO: maybe truncate to reduce size | 1577 | // TODO: maybe truncate to reduce size |
| ... | @@ -1124,7 +1625,7 @@ fn transInitListExpr( | ... | @@ -1124,7 +1625,7 @@ fn transInitListExpr( |
| 1124 | var cat_tok: ast.TokenIndex = undefined; | 1625 | var cat_tok: ast.TokenIndex = undefined; |
| 1125 | if (init_count != 0) { | 1626 | if (init_count != 0) { |
| 1126 | const dot_tok = try appendToken(rp.c, .Period, "."); | 1627 | const dot_tok = try appendToken(rp.c, .Period, "."); |
| 1127 | init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); | 1628 | init_node = try transCreateNodeContainerInitializer(rp.c, dot_tok); |
| 1128 | var i: c_uint = 0; | 1629 | var i: c_uint = 0; |
| 1129 | while (i < init_count) : (i += 1) { | 1630 | while (i < init_count) : (i += 1) { |
| 1130 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); | 1631 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); |
| ... | @@ -1139,7 +1640,7 @@ fn transInitListExpr( | ... | @@ -1139,7 +1640,7 @@ fn transInitListExpr( |
| 1139 | } | 1640 | } |
| 1140 | 1641 | ||
| 1141 | const dot_tok = try appendToken(rp.c, .Period, "."); | 1642 | const dot_tok = try appendToken(rp.c, .Period, "."); |
| 1142 | var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); | 1643 | var filler_init_node = try transCreateNodeContainerInitializer(rp.c, dot_tok); |
| 1143 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); | 1644 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); |
| 1144 | try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value)); | 1645 | try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value)); |
| 1145 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); | 1646 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| ... | @@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr( | ... | @@ -1185,7 +1686,7 @@ fn transImplicitValueInitExpr( |
| 1185 | .Builtin => blk: { | 1686 | .Builtin => blk: { |
| 1186 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); | 1687 | const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); |
| 1187 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { | 1688 | switch (ZigClangBuiltinType_getKind(builtin_ty)) { |
| 1188 | .Bool => return transCreateNodeBoolLiteral(rp.c, false), | 1689 | .Bool => return try transCreateNodeBoolLiteral(rp.c, false), |
| 1189 | .Char_U, | 1690 | .Char_U, |
| 1190 | .UChar, | 1691 | .UChar, |
| 1191 | .Char_S, | 1692 | .Char_S, |
| ... | @@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr( | ... | @@ -1215,329 +1716,941 @@ fn transImplicitValueInitExpr( |
| 1215 | }; | 1716 | }; |
| 1216 | } | 1717 | } |
| 1217 | 1718 | ||
| 1218 | fn transCPtrCast( | 1719 | fn transIfStmt( |
| 1219 | rp: RestorePoint, | 1720 | rp: RestorePoint, |
| 1220 | loc: ZigClangSourceLocation, | 1721 | scope: *Scope, |
| 1221 | dst_type: ZigClangQualType, | 1722 | stmt: *const ZigClangIfStmt, |
| 1222 | src_type: ZigClangQualType, | 1723 | ) TransError!*ast.Node { |
| 1223 | expr: *ast.Node, | 1724 | // if (c) t |
| 1224 | ) !*ast.Node { | 1725 | // if (c) t else e |
| 1225 | const ty = ZigClangQualType_getTypePtr(dst_type); | 1726 | const if_node = try transCreateNodeIf(rp.c); |
| 1226 | const child_type = ZigClangType_getPointeeType(ty); | ||
| 1227 | 1727 | ||
| 1228 | // Implicit downcasting from higher to lower alignment values is forbidden, | 1728 | var cond_scope = Scope{ |
| 1229 | // use @alignCast to side-step this problem | 1729 | .parent = scope, |
| 1230 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); | 1730 | .id = .Condition, |
| 1231 | const dst_type_node = try transType(rp, ty, loc); | 1731 | }; |
| 1232 | try ptrcast_node.params.push(dst_type_node); | 1732 | if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); |
| 1233 | _ = try appendToken(rp.c, .Comma, ","); | 1733 | _ = try appendToken(rp.c, .RParen, ")"); |
| 1234 | 1734 | ||
| 1235 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { | 1735 | if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); |
| 1236 | // void has 1-byte alignment, so @alignCast is not needed | ||
| 1237 | try ptrcast_node.params.push(expr); | ||
| 1238 | } else { | ||
| 1239 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); | ||
| 1240 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); | ||
| 1241 | const child_type_node = try transQualType(rp, child_type, loc); | ||
| 1242 | try alignof_node.params.push(child_type_node); | ||
| 1243 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1244 | try aligncast_node.params.push(&alignof_node.base); | ||
| 1245 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1246 | try aligncast_node.params.push(expr); | ||
| 1247 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1248 | try ptrcast_node.params.push(&aligncast_node.base); | ||
| 1249 | } | ||
| 1250 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 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 | rp: RestorePoint, | 1746 | rp: RestorePoint, |
| 1257 | scope: *Scope, | 1747 | scope: *Scope, |
| 1258 | used: ResultUsed, | 1748 | stmt: *const ZigClangWhileStmt, |
| 1259 | result: *ast.Node, | ||
| 1260 | ) TransError!*ast.Node { | 1749 | ) TransError!*ast.Node { |
| 1261 | if (used == .used) return result; | 1750 | const while_node = try transCreateNodeWhile(rp.c); |
| 1262 | // NOTE: This is backwards, but the semicolon must immediately follow the node. | 1751 | |
| 1263 | _ = try appendToken(rp.c, .Semicolon, ";"); | 1752 | var cond_scope = Scope{ |
| 1264 | const lhs = try transCreateNodeIdentifier(rp.c, "_"); | 1753 | .parent = scope, |
| 1265 | const op_token = try appendToken(rp.c, .Equal, "="); | 1754 | .id = .Condition, |
| 1266 | const op_node = try rp.c.a().create(ast.Node.InfixOp); | ||
| 1267 | op_node.* = ast.Node.InfixOp{ | ||
| 1268 | .op_token = op_token, | ||
| 1269 | .lhs = lhs, | ||
| 1270 | .op = .Assign, | ||
| 1271 | .rhs = result, | ||
| 1272 | }; | 1755 | }; |
| 1273 | return &op_node.base; | 1756 | while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); |
| 1274 | } | 1757 | _ = try appendToken(rp.c, .RParen, ")"); |
| 1275 | 1758 | ||
| 1276 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { | 1759 | var loop_scope = Scope{ |
| 1277 | try c.tree.root_node.decls.push(decl_node); | 1760 | .parent = scope, |
| 1278 | _ = try c.global_scope.sym_table.put(name, decl_node); | 1761 | .id = .Loop, |
| 1762 | }; | ||
| 1763 | while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value); | ||
| 1764 | return &while_node.base; | ||
| 1279 | } | 1765 | } |
| 1280 | 1766 | ||
| 1281 | fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { | 1767 | fn transDoWhileLoop( |
| 1282 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); | 1768 | rp: RestorePoint, |
| 1283 | } | 1769 | scope: *Scope, |
| 1770 | stmt: *const ZigClangDoStmt, | ||
| 1771 | ) TransError!*ast.Node { | ||
| 1772 | const while_node = try transCreateNodeWhile(rp.c); | ||
| 1773 | |||
| 1774 | while_node.condition = try transCreateNodeBoolLiteral(rp.c, true); | ||
| 1775 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 1776 | var new = false; | ||
| 1777 | var loop_scope = Scope{ | ||
| 1778 | .parent = scope, | ||
| 1779 | .id = .Loop, | ||
| 1780 | }; | ||
| 1284 | 1781 | ||
| 1285 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node { | 1782 | const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: { |
| 1286 | const rp = makeRestorePoint(c); | 1783 | // there's already a block in C, so we'll append our condition to it. |
| 1784 | // c: do { | ||
| 1785 | // c: a; | ||
| 1786 | // c: b; | ||
| 1787 | // c: } while(c); | ||
| 1788 | // zig: while (true) { | ||
| 1789 | // zig: a; | ||
| 1790 | // zig: b; | ||
| 1791 | // zig: if (!cond) break; | ||
| 1792 | // zig: } | ||
| 1793 | break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; | ||
| 1794 | } else blk: { | ||
| 1795 | // the C statement is without a block, so we need to create a block to contain it. | ||
| 1796 | // c: do | ||
| 1797 | // c: a; | ||
| 1798 | // c: while(c); | ||
| 1799 | // zig: while (true) { | ||
| 1800 | // zig: a; | ||
| 1801 | // zig: if (!cond) break; | ||
| 1802 | // zig: } | ||
| 1803 | new = true; | ||
| 1804 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 1805 | try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); | ||
| 1806 | break :blk block; | ||
| 1807 | }; | ||
| 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; | 1822 | try body_node.statements.push(&if_node.base); |
| 1291 | var container_kind: std.zig.Token.Id = undefined; | 1823 | if (new) |
| 1824 | body_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 1825 | while_node.body = &body_node.base; | ||
| 1826 | return &while_node.base; | ||
| 1827 | } | ||
| 1292 | 1828 | ||
| 1293 | if (ZigClangRecordDecl_isUnion(record_decl)) { | 1829 | fn transForLoop( |
| 1294 | container_kind_name = "union"; | 1830 | rp: RestorePoint, |
| 1295 | container_kind = .Keyword_union; | 1831 | scope: *Scope, |
| 1296 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { | 1832 | stmt: *const ZigClangForStmt, |
| 1297 | container_kind_name = "struct"; | 1833 | ) TransError!*ast.Node { |
| 1298 | container_kind = .Keyword_struct; | 1834 | var loop_scope = Scope{ |
| 1299 | } else { | 1835 | .parent = scope, |
| 1300 | return revertAndWarn( | 1836 | .id = .Loop, |
| 1301 | rp, | 1837 | }; |
| 1302 | error.UnsupportedType, | 1838 | var block = false; |
| 1303 | record_loc, | 1839 | var block_scope: ?*Scope.Block = null; |
| 1304 | "unsupported record type", | 1840 | if (ZigClangForStmt_getInit(stmt)) |init| { |
| 1305 | .{}, | 1841 | block_scope = try Scope.Block.init(rp.c, scope, null); |
| 1306 | ); | 1842 | block_scope.?.block_node = try transCreateNodeBlock(rp.c, null); |
| 1843 | loop_scope.parent = &block_scope.?.base; | ||
| 1844 | _ = try transStmt(rp, &loop_scope, init, .unused, .r_value); | ||
| 1307 | } | 1845 | } |
| 1308 | 1846 | var cond_scope = Scope{ | |
| 1309 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { | 1847 | .parent = scope, |
| 1310 | return transCreateNodeOpaqueType(c); | 1848 | .id = .Condition, |
| 1311 | }; | 1849 | }; |
| 1312 | 1850 | ||
| 1313 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | 1851 | const while_node = try transCreateNodeWhile(rp.c); |
| 1314 | const container_tok = try appendToken(c, container_kind, container_kind_name); | 1852 | while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| |
| 1315 | const lbrace_token = try appendToken(c, .LBrace, "{"); | 1853 | try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false) |
| 1854 | else | ||
| 1855 | try transCreateNodeBoolLiteral(rp.c, true); | ||
| 1856 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 1857 | |||
| 1858 | if (ZigClangForStmt_getInc(stmt)) |incr| { | ||
| 1859 | _ = try appendToken(rp.c, .Colon, ":"); | ||
| 1860 | _ = try appendToken(rp.c, .LParen, "("); | ||
| 1861 | while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value); | ||
| 1862 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 1863 | } | ||
| 1864 | |||
| 1865 | while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); | ||
| 1866 | if (block_scope != null) { | ||
| 1867 | try block_scope.?.block_node.statements.push(&while_node.base); | ||
| 1868 | block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 1869 | return &block_scope.?.block_node.base; | ||
| 1870 | } else | ||
| 1871 | return &while_node.base; | ||
| 1872 | } | ||
| 1316 | 1873 | ||
| 1317 | const container_node = try c.a().create(ast.Node.ContainerDecl); | 1874 | fn transSwitch( |
| 1318 | container_node.* = .{ | 1875 | rp: RestorePoint, |
| 1319 | .layout_token = extern_tok, | 1876 | scope: *Scope, |
| 1320 | .kind_token = container_tok, | 1877 | stmt: *const ZigClangSwitchStmt, |
| 1321 | .init_arg_expr = .None, | 1878 | ) TransError!*ast.Node { |
| 1322 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | 1879 | const switch_node = try transCreateNodeSwitch(rp.c); |
| 1323 | .lbrace_token = lbrace_token, | 1880 | var switch_scope = Scope.Switch{ |
| 1324 | .rbrace_token = undefined, | 1881 | .base = .{ |
| 1882 | .id = .Switch, | ||
| 1883 | .parent = scope, | ||
| 1884 | }, | ||
| 1885 | .cases = &switch_node.cases, | ||
| 1886 | .pending_block = undefined, | ||
| 1325 | }; | 1887 | }; |
| 1326 | 1888 | ||
| 1327 | var it = ZigClangRecordDecl_field_begin(record_def); | 1889 | var cond_scope = Scope{ |
| 1328 | const end_it = ZigClangRecordDecl_field_end(record_def); | 1890 | .parent = scope, |
| 1329 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { | 1891 | .id = .Condition, |
| 1330 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); | 1892 | }; |
| 1331 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); | 1893 | switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); |
| 1894 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 1895 | _ = try appendToken(rp.c, .LBrace, "{"); | ||
| 1896 | switch_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 1332 | 1897 | ||
| 1333 | if (ZigClangFieldDecl_isBitField(field_decl)) { | 1898 | const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); |
| 1334 | rp.activate(); | 1899 | // tmp block that all statements will go before being picked up by a case or default |
| 1335 | const node = try transCreateNodeOpaqueType(c); | 1900 | const block = try transCreateNodeBlock(rp.c, null); |
| 1336 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); | 1901 | block_scope.block_node = block; |
| 1337 | return node; | ||
| 1338 | } | ||
| 1339 | 1902 | ||
| 1340 | const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); | 1903 | const switch_block = try transCreateNodeBlock(rp.c, null); |
| 1341 | _ = try appendToken(c, .Colon, ":"); | 1904 | try switch_block.statements.push(&switch_node.base); |
| 1342 | const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); | 1905 | switch_scope.pending_block = switch_block; |
| 1343 | 1906 | ||
| 1344 | const field_node = try c.a().create(ast.Node.ContainerField); | 1907 | const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); |
| 1345 | field_node.* = .{ | 1908 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1346 | .doc_comments = null, | ||
| 1347 | .comptime_token = null, | ||
| 1348 | .name_token = field_name, | ||
| 1349 | .type_expr = field_type, | ||
| 1350 | .value_expr = null, | ||
| 1351 | .align_expr = null, | ||
| 1352 | }; | ||
| 1353 | 1909 | ||
| 1354 | try container_node.fields_and_decls.push(&field_node.base); | 1910 | // take all pending statements |
| 1355 | _ = try appendToken(c, .Comma, ","); | 1911 | var it = last.cast(ast.Node.Block).?.statements.iterator(0); |
| 1912 | while (it.next()) |n| { | ||
| 1913 | try switch_scope.pending_block.statements.push(n.*); | ||
| 1356 | } | 1914 | } |
| 1357 | 1915 | ||
| 1358 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | 1916 | switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); |
| 1359 | return &container_node.base; | 1917 | _ = try appendToken(rp.c, .Colon, ":"); |
| 1918 | if (!switch_scope.has_default) { | ||
| 1919 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | ||
| 1920 | else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base; | ||
| 1921 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1922 | try switch_node.cases.push(&else_prong.base); | ||
| 1923 | } | ||
| 1924 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 1925 | return &switch_scope.pending_block.base; | ||
| 1360 | } | 1926 | } |
| 1361 | 1927 | ||
| 1362 | fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { | 1928 | fn transCase( |
| 1363 | if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| | 1929 | rp: RestorePoint, |
| 1364 | return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice | 1930 | scope: *Scope, |
| 1365 | const rp = makeRestorePoint(c); | 1931 | stmt: *const ZigClangCaseStmt, |
| 1366 | const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); | 1932 | ) TransError!*ast.Node { |
| 1933 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | ||
| 1934 | const switch_scope = scope.getSwitch(); | ||
| 1935 | const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)}); | ||
| 1936 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 1367 | 1937 | ||
| 1368 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 1938 | const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: { |
| 1369 | const const_tok = try appendToken(c, .Keyword_const, "const"); | 1939 | const lhs_node = try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value); |
| 1940 | const ellips = try appendToken(rp.c, .Ellipsis3, "..."); | ||
| 1941 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | ||
| 1370 | 1942 | ||
| 1371 | var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); | 1943 | const node = try rp.c.a().create(ast.Node.InfixOp); |
| 1372 | var is_unnamed = false; | 1944 | node.* = .{ |
| 1373 | if (bare_name.len == 0) { | 1945 | .op_token = ellips, |
| 1374 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | 1946 | .lhs = lhs_node, |
| 1375 | is_unnamed = true; | 1947 | .op = .Range, |
| 1948 | .rhs = rhs_node, | ||
| 1949 | }; | ||
| 1950 | break :blk &node.base; | ||
| 1951 | } else | ||
| 1952 | try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value); | ||
| 1953 | |||
| 1954 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); | ||
| 1955 | switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; | ||
| 1956 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 1957 | try switch_scope.cases.push(&switch_prong.base); | ||
| 1958 | |||
| 1959 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 1960 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | ||
| 1961 | _ = try appendToken(rp.c, .Colon, ":"); | ||
| 1962 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 1963 | try block.statements.push(&switch_scope.pending_block.base); | ||
| 1964 | |||
| 1965 | // take all pending statements | ||
| 1966 | var it = block_scope.block_node.statements.iterator(0); | ||
| 1967 | while (it.next()) |n| { | ||
| 1968 | try switch_scope.pending_block.statements.push(n.*); | ||
| 1376 | } | 1969 | } |
| 1970 | block_scope.block_node.statements.shrink(0); | ||
| 1377 | 1971 | ||
| 1378 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); | 1972 | switch_scope.pending_block = block; |
| 1379 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); | ||
| 1380 | const name_tok = try appendIdentifier(c, name); | ||
| 1381 | const eq_tok = try appendToken(c, .Equal, "="); | ||
| 1382 | 1973 | ||
| 1383 | const init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { | 1974 | return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value); |
| 1384 | var pure_enum = true; | 1975 | } |
| 1385 | var it = ZigClangEnumDecl_enumerator_begin(enum_def); | ||
| 1386 | var end_it = ZigClangEnumDecl_enumerator_end(enum_def); | ||
| 1387 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | ||
| 1388 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | ||
| 1389 | if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { | ||
| 1390 | pure_enum = false; | ||
| 1391 | break; | ||
| 1392 | } | ||
| 1393 | } | ||
| 1394 | 1976 | ||
| 1395 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | 1977 | fn transDefault( |
| 1396 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); | 1978 | rp: RestorePoint, |
| 1979 | scope: *Scope, | ||
| 1980 | stmt: *const ZigClangDefaultStmt, | ||
| 1981 | ) TransError!*ast.Node { | ||
| 1982 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | ||
| 1983 | const switch_scope = scope.getSwitch(); | ||
| 1984 | const label = "__default"; | ||
| 1985 | switch_scope.has_default = true; | ||
| 1986 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 1397 | 1987 | ||
| 1398 | const container_node = try c.a().create(ast.Node.ContainerDecl); | 1988 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); |
| 1399 | container_node.* = .{ | 1989 | else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; |
| 1400 | .layout_token = extern_tok, | 1990 | _ = try appendToken(rp.c, .Comma, ","); |
| 1401 | .kind_token = container_tok, | 1991 | try switch_scope.cases.push(&else_prong.base); |
| 1402 | .init_arg_expr = .None, | 1992 | |
| 1403 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | 1993 | const block = try transCreateNodeBlock(rp.c, null); |
| 1404 | .lbrace_token = undefined, | 1994 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); |
| 1405 | .rbrace_token = undefined, | 1995 | _ = try appendToken(rp.c, .Colon, ":"); |
| 1406 | }; | 1996 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 1997 | try block.statements.push(&switch_scope.pending_block.base); | ||
| 1998 | |||
| 1999 | // take all pending statements | ||
| 2000 | var it = block_scope.block_node.statements.iterator(0); | ||
| 2001 | while (it.next()) |n| { | ||
| 2002 | try switch_scope.pending_block.statements.push(n.*); | ||
| 2003 | } | ||
| 2004 | block_scope.block_node.statements.shrink(0); | ||
| 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. | 2010 | fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, used: ResultUsed) TransError!*ast.Node { |
| 1411 | // I don't know what the default is, need to figure out how clang is deciding. | 2011 | var result: ZigClangExprEvalResult = undefined; |
| 1412 | // it appears to at least be different across gcc/msvc | 2012 | if (!ZigClangExpr_EvaluateAsConstantExpr(expr, &result, .EvaluateForCodeGen, rp.c.clang_context)) |
| 1413 | if (!isCBuiltinType(int_type, .UInt) and | 2013 | return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangExpr_getBeginLoc(expr), "invalid constant expression", .{}); |
| 1414 | !isCBuiltinType(int_type, .Int)) | 2014 | return maybeSuppressResult(rp, scope, used, try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val))); |
| 1415 | { | 2015 | } |
| 1416 | _ = try appendToken(c, .LParen, "("); | 2016 | |
| 1417 | container_node.init_arg_expr = .{ | 2017 | fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPredefinedExpr, used: ResultUsed) TransError!*ast.Node { |
| 1418 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { | 2018 | return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used); |
| 1419 | error.UnsupportedType => { | 2019 | } |
| 1420 | if (is_unnamed) { | 2020 | |
| 1421 | try emitWarning(c, enum_loc, "unable to translate enum tag type", .{}); | 2021 | fn transCharLiteral( |
| 1422 | } else { | 2022 | rp: RestorePoint, |
| 1423 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); | 2023 | scope: *Scope, |
| 1424 | } | 2024 | stmt: *const ZigClangCharacterLiteral, |
| 1425 | return null; | 2025 | result_used: ResultUsed, |
| 1426 | }, | 2026 | ) TransError!*ast.Node { |
| 1427 | else => |e| return e, | 2027 | const kind = ZigClangCharacterLiteral_getKind(stmt); |
| 1428 | }, | 2028 | switch (kind) { |
| 2029 | .Ascii, .UTF8 => { | ||
| 2030 | const val = ZigClangCharacterLiteral_getValue(stmt); | ||
| 2031 | if (kind == .Ascii) { | ||
| 2032 | // C has a somewhat obscure feature called multi-character character | ||
| 2033 | // constant | ||
| 2034 | if (val > 255) | ||
| 2035 | return transCreateNodeInt(rp.c, val); | ||
| 2036 | } | ||
| 2037 | var char_buf: [4]u8 = undefined; | ||
| 2038 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); | ||
| 2039 | const node = try rp.c.a().create(ast.Node.CharLiteral); | ||
| 2040 | node.* = .{ | ||
| 2041 | .token = token, | ||
| 1429 | }; | 2042 | }; |
| 1430 | _ = try appendToken(c, .RParen, ")"); | 2043 | return maybeSuppressResult(rp, scope, result_used, &node.base); |
| 2044 | }, | ||
| 2045 | .UTF16, .UTF32, .Wide => return revertAndWarn( | ||
| 2046 | rp, | ||
| 2047 | error.UnsupportedTranslation, | ||
| 2048 | ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), | ||
| 2049 | "TODO: support character literal kind {}", | ||
| 2050 | .{kind}, | ||
| 2051 | ), | ||
| 2052 | else => unreachable, | ||
| 2053 | } | ||
| 2054 | } | ||
| 2055 | |||
| 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); | 2147 | if (fn_ty) |ty| { |
| 1436 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); | 2148 | const canon = ZigClangQualType_getCanonicalType(ZigClangFunctionProtoType_getReturnType(ty)); |
| 1437 | while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { | 2149 | const ret_ty = ZigClangQualType_getTypePtr(canon); |
| 1438 | const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); | 2150 | if (ZigClangType_isVoidType(ret_ty)) { |
| 2151 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2152 | return &node.base; | ||
| 2153 | } | ||
| 2154 | } | ||
| 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)) | 2159 | fn qualTypeGetFnProto(qt: ZigClangQualType, is_ptr: *bool) ?*const ZigClangFunctionProtoType { |
| 1443 | enum_val_name[bare_name.len..] | 2160 | const canon = ZigClangQualType_getCanonicalType(qt); |
| 1444 | else | 2161 | var ty = ZigClangQualType_getTypePtr(canon); |
| 1445 | enum_val_name; | 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: { | 2175 | fn transUnaryExprOrTypeTraitExpr( |
| 1450 | _ = try appendToken(c, .Colon, "="); | 2176 | rp: RestorePoint, |
| 1451 | break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); | 2177 | scope: *Scope, |
| 2178 | stmt: *const ZigClangUnaryExprOrTypeTraitExpr, | ||
| 2179 | result_used: ResultUsed, | ||
| 2180 | ) TransError!*ast.Node { | ||
| 2181 | const type_node = try transQualType( | ||
| 2182 | rp, | ||
| 2183 | ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(stmt), | ||
| 2184 | ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt), | ||
| 2185 | ); | ||
| 2186 | |||
| 2187 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf"); | ||
| 2188 | try builtin_node.params.push(type_node); | ||
| 2189 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 2190 | return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); | ||
| 2191 | } | ||
| 2192 | |||
| 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 | } else | 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); | 2268 | fn transCreatePreCrement( |
| 1456 | field_node.* = .{ | 2269 | rp: RestorePoint, |
| 1457 | .doc_comments = null, | 2270 | scope: *Scope, |
| 1458 | .comptime_token = null, | 2271 | stmt: *const ZigClangUnaryOperator, |
| 1459 | .name_token = field_name_tok, | 2272 | op: ast.Node.InfixOp.Op, |
| 1460 | .type_expr = null, | 2273 | op_tok_id: std.zig.Token.Id, |
| 1461 | .value_expr = int_node, | 2274 | bytes: []const u8, |
| 1462 | .align_expr = null, | 2275 | used: ResultUsed, |
| 1463 | }; | 2276 | ) TransError!*ast.Node { |
| 2277 | const op_expr = ZigClangUnaryOperator_getSubExpr(stmt); | ||
| 2278 | |||
| 2279 | if (used == .unused) { | ||
| 2280 | // common case | ||
| 2281 | // c: ++expr | ||
| 2282 | // zig: expr += 1 | ||
| 2283 | const expr = try transExpr(rp, scope, op_expr, .used, .r_value); | ||
| 2284 | const token = try appendToken(rp.c, op_tok_id, bytes); | ||
| 2285 | const one = try transCreateNodeInt(rp.c, 1); | ||
| 2286 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2287 | return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false); | ||
| 2288 | } | ||
| 2289 | // worst case | ||
| 2290 | // c: ++expr | ||
| 2291 | // zig: (blk: { | ||
| 2292 | // zig: const _ref = &expr; | ||
| 2293 | // zig: _ref.* += 1; | ||
| 2294 | // zig: break :blk _ref.* | ||
| 2295 | // zig: }) | ||
| 2296 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | ||
| 2297 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | ||
| 2298 | const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); | ||
| 2299 | |||
| 2300 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | ||
| 2301 | node.eq_token = try appendToken(rp.c, .Equal, "="); | ||
| 2302 | const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | ||
| 2303 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | ||
| 2304 | node.init_node = &rhs_node.base; | ||
| 2305 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2306 | try block_scope.block_node.statements.push(&node.base); | ||
| 2307 | |||
| 2308 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | ||
| 2309 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | ||
| 2310 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2311 | const token = try appendToken(rp.c, op_tok_id, bytes); | ||
| 2312 | const one = try transCreateNodeInt(rp.c, 1); | ||
| 2313 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2314 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | ||
| 2315 | try block_scope.block_node.statements.push(assign); | ||
| 2316 | |||
| 2317 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | ||
| 2318 | break_node.rhs = ref_node; | ||
| 2319 | try block_scope.block_node.statements.push(&break_node.base); | ||
| 2320 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2321 | // semicolon must immediately follow rbrace because it is the last token in a block | ||
| 2322 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2323 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | ||
| 2324 | grouped_expr.* = .{ | ||
| 2325 | .lparen = try appendToken(rp.c, .LParen, "("), | ||
| 2326 | .expr = &block_scope.block_node.base, | ||
| 2327 | .rparen = try appendToken(rp.c, .RParen, ")"), | ||
| 2328 | }; | ||
| 2329 | return &grouped_expr.base; | ||
| 2330 | } | ||
| 1464 | 2331 | ||
| 1465 | try container_node.fields_and_decls.push(&field_node.base); | 2332 | fn transCreatePostCrement( |
| 1466 | _ = try appendToken(c, .Comma, ","); | 2333 | rp: RestorePoint, |
| 1467 | // In C each enum value is in the global namespace. So we put them there too. | 2334 | scope: *Scope, |
| 1468 | // At this point we can rely on the enum emitting successfully. | 2335 | stmt: *const ZigClangUnaryOperator, |
| 1469 | try addEnumTopLevel(c, name, field_name, enum_val_name); | 2336 | op: ast.Node.InfixOp.Op, |
| 2337 | op_tok_id: std.zig.Token.Id, | ||
| 2338 | bytes: []const u8, | ||
| 2339 | used: ResultUsed, | ||
| 2340 | ) TransError!*ast.Node { | ||
| 2341 | const op_expr = ZigClangUnaryOperator_getSubExpr(stmt); | ||
| 2342 | |||
| 2343 | if (used == .unused) { | ||
| 2344 | // common case | ||
| 2345 | // c: ++expr | ||
| 2346 | // zig: expr += 1 | ||
| 2347 | const expr = try transExpr(rp, scope, op_expr, .used, .r_value); | ||
| 2348 | const token = try appendToken(rp.c, op_tok_id, bytes); | ||
| 2349 | const one = try transCreateNodeInt(rp.c, 1); | ||
| 2350 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2351 | return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false); | ||
| 2352 | } | ||
| 2353 | // worst case | ||
| 2354 | // c: expr++ | ||
| 2355 | // zig: (blk: { | ||
| 2356 | // zig: const _ref = &expr; | ||
| 2357 | // zig: const _tmp = _ref.*; | ||
| 2358 | // zig: _ref.* += 1; | ||
| 2359 | // zig: break :blk _tmp | ||
| 2360 | // zig: }) | ||
| 2361 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | ||
| 2362 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | ||
| 2363 | const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()}); | ||
| 2364 | |||
| 2365 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | ||
| 2366 | node.eq_token = try appendToken(rp.c, .Equal, "="); | ||
| 2367 | const rhs_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); | ||
| 2368 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | ||
| 2369 | node.init_node = &rhs_node.base; | ||
| 2370 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2371 | try block_scope.block_node.statements.push(&node.base); | ||
| 2372 | |||
| 2373 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | ||
| 2374 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | ||
| 2375 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2376 | |||
| 2377 | const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); | ||
| 2378 | const tmp_node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | ||
| 2379 | tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); | ||
| 2380 | tmp_node.init_node = ref_node; | ||
| 2381 | tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2382 | try block_scope.block_node.statements.push(&tmp_node.base); | ||
| 2383 | |||
| 2384 | const token = try appendToken(rp.c, op_tok_id, bytes); | ||
| 2385 | const one = try transCreateNodeInt(rp.c, 1); | ||
| 2386 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2387 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | ||
| 2388 | try block_scope.block_node.statements.push(assign); | ||
| 2389 | |||
| 2390 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | ||
| 2391 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | ||
| 2392 | try block_scope.block_node.statements.push(&break_node.base); | ||
| 2393 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2394 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2395 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | ||
| 2396 | grouped_expr.* = .{ | ||
| 2397 | .lparen = try appendToken(rp.c, .LParen, "("), | ||
| 2398 | .expr = &block_scope.block_node.base, | ||
| 2399 | .rparen = try appendToken(rp.c, .RParen, ")"), | ||
| 2400 | }; | ||
| 2401 | return &grouped_expr.base; | ||
| 2402 | } | ||
| 2403 | |||
| 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; | 2505 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1474 | } else | ||
| 1475 | try transCreateNodeOpaqueType(c); | ||
| 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); | 2511 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); |
| 1480 | node.* = ast.Node.VarDecl{ | 2512 | break_node.rhs = ref_node; |
| 1481 | .visib_token = visib_tok, | 2513 | try block_scope.block_node.statements.push(&break_node.base); |
| 1482 | .mut_token = const_tok, | 2514 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 1483 | .name_token = name_tok, | 2515 | // semicolon must immediately follow rbrace because it is the last token in a block |
| 1484 | .eq_token = eq_tok, | 2516 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1485 | .init_node = init_node, | 2517 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 1486 | .semicolon_token = semicolon_token, | 2518 | grouped_expr.* = .{ |
| 1487 | .doc_comments = null, | 2519 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 1488 | .comptime_token = null, | 2520 | .expr = &block_scope.block_node.base, |
| 1489 | .extern_export_token = null, | 2521 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 1490 | .thread_local_token = null, | ||
| 1491 | .lib_name = null, | ||
| 1492 | .type_node = null, | ||
| 1493 | .align_node = null, | ||
| 1494 | .section_node = null, | ||
| 1495 | }; | 2522 | }; |
| 2523 | return &grouped_expr.base; | ||
| 2524 | } | ||
| 1496 | 2525 | ||
| 1497 | try addTopLevelDecl(c, name, &node.base); | 2526 | fn transCPtrCast( |
| 1498 | if (!is_unnamed) | 2527 | rp: RestorePoint, |
| 1499 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | 2528 | loc: ZigClangSourceLocation, |
| 1500 | return transCreateNodeIdentifier(c, name); | 2529 | dst_type: ZigClangQualType, |
| 2530 | src_type: ZigClangQualType, | ||
| 2531 | expr: *ast.Node, | ||
| 2532 | ) !*ast.Node { | ||
| 2533 | const ty = ZigClangQualType_getTypePtr(dst_type); | ||
| 2534 | const child_type = ZigClangType_getPointeeType(ty); | ||
| 2535 | |||
| 2536 | // Implicit downcasting from higher to lower alignment values is forbidden, | ||
| 2537 | // use @alignCast to side-step this problem | ||
| 2538 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); | ||
| 2539 | const dst_type_node = try transType(rp, ty, loc); | ||
| 2540 | try ptrcast_node.params.push(dst_type_node); | ||
| 2541 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 2542 | |||
| 2543 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { | ||
| 2544 | // void has 1-byte alignment, so @alignCast is not needed | ||
| 2545 | try ptrcast_node.params.push(expr); | ||
| 2546 | } else { | ||
| 2547 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); | ||
| 2548 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); | ||
| 2549 | const child_type_node = try transQualType(rp, child_type, loc); | ||
| 2550 | try alignof_node.params.push(child_type_node); | ||
| 2551 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 2552 | try aligncast_node.params.push(&alignof_node.base); | ||
| 2553 | _ = try appendToken(rp.c, .Comma, ","); | ||
| 2554 | try aligncast_node.params.push(expr); | ||
| 2555 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 2556 | try ptrcast_node.params.push(&aligncast_node.base); | ||
| 2557 | } | ||
| 2558 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 2559 | |||
| 2560 | return &ptrcast_node.base; | ||
| 1501 | } | 2561 | } |
| 1502 | 2562 | ||
| 1503 | fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { | 2563 | fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { |
| 1504 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 2564 | const break_scope = scope.getBreakableScope(); |
| 1505 | const const_tok = try appendToken(c, .Keyword_const, "const"); | 2565 | const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch) |
| 1506 | const name_tok = try appendIdentifier(c, enum_val_name); | 2566 | "__switch" |
| 1507 | const eq_tok = try appendToken(c, .Equal, "="); | 2567 | else |
| 2568 | null); | ||
| 2569 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2570 | return &br.base; | ||
| 2571 | } | ||
| 1508 | 2572 | ||
| 1509 | const enum_ident = try transCreateNodeIdentifier(c, enum_name); | 2573 | fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node { |
| 1510 | const period_tok = try appendToken(c, .Period, "."); | 2574 | // TODO use something more accurate |
| 1511 | const field_ident = try transCreateNodeIdentifier(c, field_name); | 2575 | const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt); |
| 2576 | const node = try rp.c.a().create(ast.Node.FloatLiteral); | ||
| 2577 | node.* = .{ | ||
| 2578 | .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}), | ||
| 2579 | }; | ||
| 2580 | return maybeSuppressResult(rp, scope, used, &node.base); | ||
| 2581 | } | ||
| 1512 | 2582 | ||
| 1513 | const field_access_node = try c.a().create(ast.Node.InfixOp); | 2583 | fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node { |
| 1514 | field_access_node.* = .{ | 2584 | const grouped = scope.id == .Condition; |
| 1515 | .op_token = period_tok, | 2585 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; |
| 1516 | .lhs = enum_ident, | 2586 | const if_node = try transCreateNodeIf(rp.c); |
| 1517 | .op = .Period, | 2587 | var cond_scope = Scope{ |
| 1518 | .rhs = field_ident, | 2588 | .parent = scope, |
| 2589 | .id = .Condition, | ||
| 1519 | }; | 2590 | }; |
| 1520 | const semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 1521 | 2591 | ||
| 1522 | const node = try c.a().create(ast.Node.VarDecl); | 2592 | const cond_expr = ZigClangConditionalOperator_getCond(stmt); |
| 1523 | node.* = ast.Node.VarDecl{ | 2593 | const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt); |
| 1524 | .visib_token = visib_tok, | 2594 | const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt); |
| 1525 | .mut_token = const_tok, | 2595 | |
| 1526 | .name_token = name_tok, | 2596 | if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); |
| 1527 | .eq_token = eq_tok, | 2597 | _ = try appendToken(rp.c, .RParen, ")"); |
| 1528 | .init_node = &field_access_node.base, | 2598 | |
| 1529 | .semicolon_token = semicolon_token, | 2599 | if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); |
| 1530 | .thread_local_token = null, | 2600 | |
| 1531 | .doc_comments = null, | 2601 | if_node.@"else" = try transCreateNodeElse(rp.c); |
| 1532 | .comptime_token = null, | 2602 | if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value); |
| 1533 | .extern_export_token = null, | 2603 | |
| 1534 | .lib_name = null, | 2604 | if (grouped) { |
| 1535 | .type_node = null, | 2605 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1536 | .align_node = null, | 2606 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 1537 | .section_node = null, | 2607 | grouped_expr.* = .{ |
| 2608 | .lparen = lparen, | ||
| 2609 | .expr = &if_node.base, | ||
| 2610 | .rparen = rparen, | ||
| 2611 | }; | ||
| 2612 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | ||
| 2613 | } else { | ||
| 2614 | return maybeSuppressResult(rp, scope, used, &if_node.base); | ||
| 2615 | } | ||
| 2616 | } | ||
| 2617 | |||
| 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 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { | 2656 | fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { |
| ... | @@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool { | ... | @@ -1552,6 +2665,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool { |
| 1552 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; | 2665 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; |
| 1553 | } | 2666 | } |
| 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 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { | 2757 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { |
| 1556 | const ty = ZigClangQualType_getTypePtr(qt); | 2758 | const ty = ZigClangQualType_getTypePtr(qt); |
| 1557 | 2759 | ||
| ... | @@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { | ... | @@ -1601,6 +2803,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { |
| 1601 | return ZigClangExpr_getType(expr); | 2803 | return ZigClangExpr_getType(expr); |
| 1602 | } | 2804 | } |
| 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 | fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { | 2814 | fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { |
| 1605 | switch (ZigClangType_getTypeClass(ty)) { | 2815 | switch (ZigClangType_getTypeClass(ty)) { |
| 1606 | .Builtin => { | 2816 | .Builtin => { |
| ... | @@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool { | ... | @@ -1657,53 +2867,109 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool { |
| 1657 | }; | 2867 | }; |
| 1658 | } | 2868 | } |
| 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 | fn transCreateNodeAssign( | 2901 | fn transCreateNodeAssign( |
| 1661 | rp: RestorePoint, | 2902 | rp: RestorePoint, |
| 1662 | scope: *Scope, | 2903 | scope: *Scope, |
| 1663 | result_used: ResultUsed, | 2904 | result_used: ResultUsed, |
| 1664 | lhs: *const ZigClangExpr, | 2905 | lhs: *const ZigClangExpr, |
| 1665 | rhs: *const ZigClangExpr, | 2906 | rhs: *const ZigClangExpr, |
| 1666 | ) !*ast.Node.InfixOp { | 2907 | ) !*ast.Node { |
| 1667 | // common case | 2908 | // common case |
| 1668 | // c: lhs = rhs | 2909 | // c: lhs = rhs |
| 1669 | // zig: lhs = rhs | 2910 | // zig: lhs = rhs |
| 1670 | if (result_used == .unused) { | 2911 | if (result_used == .unused) { |
| 1671 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | 2912 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 1672 | const eq_token = try appendToken(rp.c, .Equal, "="); | 2913 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 1673 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | 2914 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 1674 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2915 | if (isBoolRes(rhs_node)) { |
| 1675 | 2916 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | |
| 1676 | const node = try rp.c.a().create(ast.Node.InfixOp); | 2917 | try builtin_node.params.push(rhs_node); |
| 1677 | node.* = .{ | 2918 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1678 | .op_token = eq_token, | 2919 | rhs_node = &builtin_node.base; |
| 1679 | .lhs = lhs_node, | 2920 | } |
| 1680 | .op = .Assign, | 2921 | if (scope.id != .Condition) |
| 1681 | .rhs = rhs_node, | 2922 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1682 | }; | 2923 | return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false); |
| 1683 | return node; | ||
| 1684 | } | 2924 | } |
| 1685 | 2925 | ||
| 1686 | // worst case | 2926 | // worst case |
| 1687 | // c: lhs = rhs | 2927 | // c: lhs = rhs |
| 1688 | // zig: (x: { | 2928 | // zig: (blk: { |
| 1689 | // zig: const _tmp = rhs; | 2929 | // zig: const _tmp = rhs; |
| 1690 | // zig: lhs = _tmp; | 2930 | // zig: lhs = _tmp; |
| 1691 | // zig: break :x _tmp | 2931 | // zig: break :blk _tmp |
| 1692 | // zig: }) | 2932 | // zig: }) |
| 1693 | return revertAndWarn( | 2933 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 1694 | rp, | 2934 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); |
| 1695 | error.UnsupportedTranslation, | 2935 | const tmp = try std.fmt.allocPrint(rp.c.a(), "_tmp_{}", .{rp.c.getMangle()}); |
| 1696 | ZigClangExpr_getBeginLoc(lhs), | 2936 | |
| 1697 | "TODO: worst case assign op expr", | 2937 | const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); |
| 1698 | .{}, | 2938 | node.eq_token = try appendToken(rp.c, .Equal, "="); |
| 1699 | ); | 2939 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 2940 | if (isBoolRes(rhs_node)) { | ||
| 2941 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | ||
| 2942 | try builtin_node.params.push(rhs_node); | ||
| 2943 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 2944 | rhs_node = &builtin_node.base; | ||
| 2945 | } | ||
| 2946 | node.init_node = rhs_node; | ||
| 2947 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2948 | try block_scope.block_node.statements.push(&node.base); | ||
| 2949 | |||
| 2950 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | ||
| 2951 | const eq_token = try appendToken(rp.c, .Equal, "="); | ||
| 2952 | const ident = try transCreateNodeIdentifier(rp.c, tmp); | ||
| 2953 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2954 | |||
| 2955 | const assign = try transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, ident, .used, false); | ||
| 2956 | try block_scope.block_node.statements.push(assign); | ||
| 2957 | |||
| 2958 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | ||
| 2959 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | ||
| 2960 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2961 | try block_scope.block_node.statements.push(&break_node.base); | ||
| 2962 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2963 | // semicolon must immediately follow rbrace because it is the last token in a block | ||
| 2964 | _ = try appendToken(rp.c, .Semicolon, ";"); | ||
| 2965 | return &block_scope.block_node.base; | ||
| 1700 | } | 2966 | } |
| 1701 | 2967 | ||
| 1702 | fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { | 2968 | fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { |
| 1703 | const builtin_token = try appendToken(c, .Builtin, name); | 2969 | const builtin_token = try appendToken(c, .Builtin, name); |
| 1704 | _ = try appendToken(c, .LParen, "("); | 2970 | _ = try appendToken(c, .LParen, "("); |
| 1705 | const node = try c.a().create(ast.Node.BuiltinCall); | 2971 | const node = try c.a().create(ast.Node.BuiltinCall); |
| 1706 | node.* = ast.Node.BuiltinCall{ | 2972 | node.* = .{ |
| 1707 | .builtin_token = builtin_token, | 2973 | .builtin_token = builtin_token, |
| 1708 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), | 2974 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), |
| 1709 | .rparen_token = undefined, // set after appending args | 2975 | .rparen_token = undefined, // set after appending args |
| ... | @@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti | ... | @@ -1714,10 +2980,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti |
| 1714 | fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { | 2980 | fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1715 | _ = try appendToken(c, .LParen, "("); | 2981 | _ = try appendToken(c, .LParen, "("); |
| 1716 | const node = try c.a().create(ast.Node.SuffixOp); | 2982 | const node = try c.a().create(ast.Node.SuffixOp); |
| 1717 | node.* = ast.Node.SuffixOp{ | 2983 | node.* = .{ |
| 1718 | .lhs = .{ .node = fn_expr }, | 2984 | .lhs = .{ .node = fn_expr }, |
| 1719 | .op = ast.Node.SuffixOp.Op{ | 2985 | .op = .{ |
| 1720 | .Call = ast.Node.SuffixOp.Op.Call{ | 2986 | .Call = .{ |
| 1721 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), | 2987 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), |
| 1722 | .async_token = null, | 2988 | .async_token = null, |
| 1723 | }, | 2989 | }, |
| ... | @@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { | ... | @@ -1727,6 +2993,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 1727 | return node; | 2993 | return node; |
| 1728 | } | 2994 | } |
| 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 | fn transCreateNodePrefixOp( | 3007 | fn transCreateNodePrefixOp( |
| 1731 | c: *Context, | 3008 | c: *Context, |
| 1732 | op: ast.Node.PrefixOp.Op, | 3009 | op: ast.Node.PrefixOp.Op, |
| ... | @@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp( | ... | @@ -1745,32 +3022,62 @@ fn transCreateNodePrefixOp( |
| 1745 | fn transCreateNodeInfixOp( | 3022 | fn transCreateNodeInfixOp( |
| 1746 | rp: RestorePoint, | 3023 | rp: RestorePoint, |
| 1747 | scope: *Scope, | 3024 | scope: *Scope, |
| 1748 | stmt: *const ZigClangBinaryOperator, | 3025 | lhs_node: *ast.Node, |
| 1749 | op: ast.Node.InfixOp.Op, | 3026 | op: ast.Node.InfixOp.Op, |
| 1750 | op_tok_id: std.zig.Token.Id, | 3027 | op_token: ast.TokenIndex, |
| 1751 | bytes: []const u8, | 3028 | rhs_node: *ast.Node, |
| 3029 | used: ResultUsed, | ||
| 1752 | grouped: bool, | 3030 | grouped: bool, |
| 1753 | ) !*ast.Node { | 3031 | ) !*ast.Node { |
| 1754 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; | 3032 | var lparen = if (grouped) |
| 1755 | const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); | 3033 | try appendToken(rp.c, .LParen, "(") |
| 1756 | const op_token = try appendToken(rp.c, op_tok_id, bytes); | 3034 | else |
| 1757 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 3035 | null; |
| 1758 | const node = try rp.c.a().create(ast.Node.InfixOp); | 3036 | const node = try rp.c.a().create(ast.Node.InfixOp); |
| 1759 | node.* = ast.Node.InfixOp{ | 3037 | node.* = .{ |
| 1760 | .op_token = op_token, | 3038 | .op_token = op_token, |
| 1761 | .lhs = lhs, | 3039 | .lhs = lhs_node, |
| 1762 | .op = op, | 3040 | .op = op, |
| 1763 | .rhs = rhs, | 3041 | .rhs = rhs_node, |
| 1764 | }; | 3042 | }; |
| 1765 | if (!grouped) return &node.base; | 3043 | if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base); |
| 1766 | const rparen = try appendToken(rp.c, .RParen, ")"); | 3044 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1767 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3045 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 1768 | grouped_expr.* = ast.Node.GroupedExpression{ | 3046 | grouped_expr.* = .{ |
| 1769 | .lparen = lparen, | 3047 | .lparen = lparen.?, |
| 1770 | .expr = &node.base, | 3048 | .expr = &node.base, |
| 1771 | .rparen = rparen, | 3049 | .rparen = rparen, |
| 1772 | }; | 3050 | }; |
| 1773 | return &grouped_expr.base; | 3051 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| 3052 | } | ||
| 3053 | |||
| 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 | fn transCreateNodePtrType( | 3083 | fn transCreateNodePtrType( |
| ... | @@ -1797,9 +3104,9 @@ fn transCreateNodePtrType( | ... | @@ -1797,9 +3104,9 @@ fn transCreateNodePtrType( |
| 1797 | .Asterisk => try appendToken(c, .Asterisk, "*"), | 3104 | .Asterisk => try appendToken(c, .Asterisk, "*"), |
| 1798 | else => unreachable, | 3105 | else => unreachable, |
| 1799 | }; | 3106 | }; |
| 1800 | node.* = ast.Node.PrefixOp{ | 3107 | node.* = .{ |
| 1801 | .op_token = op_token, | 3108 | .op_token = op_token, |
| 1802 | .op = ast.Node.PrefixOp.Op{ | 3109 | .op = .{ |
| 1803 | .PtrType = .{ | 3110 | .PtrType = .{ |
| 1804 | .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, | 3111 | .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, |
| 1805 | .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, | 3112 | .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, |
| ... | @@ -1810,11 +3117,17 @@ fn transCreateNodePtrType( | ... | @@ -1810,11 +3117,17 @@ fn transCreateNodePtrType( |
| 1810 | return node; | 3117 | return node; |
| 1811 | } | 3118 | } |
| 1812 | 3119 | ||
| 1813 | fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { | 3120 | fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { |
| 1814 | const num_limbs = ZigClangAPSInt_getNumWords(int.?); | 3121 | const num_limbs = ZigClangAPSInt_getNumWords(int); |
| 3122 | var aps_int = int; | ||
| 3123 | const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int); | ||
| 3124 | if (is_negative) | ||
| 3125 | aps_int = ZigClangAPSInt_negate(aps_int); | ||
| 1815 | var big = try std.math.big.Int.initCapacity(c.a(), num_limbs); | 3126 | var big = try std.math.big.Int.initCapacity(c.a(), num_limbs); |
| 3127 | if (is_negative) | ||
| 3128 | big.negate(); | ||
| 1816 | defer big.deinit(); | 3129 | defer big.deinit(); |
| 1817 | const data = ZigClangAPSInt_getRawData(int.?); | 3130 | const data = ZigClangAPSInt_getRawData(aps_int); |
| 1818 | var i: @TypeOf(num_limbs) = 0; | 3131 | var i: @TypeOf(num_limbs) = 0; |
| 1819 | while (i < num_limbs) : (i += 1) big.limbs[i] = data[i]; | 3132 | while (i < num_limbs) : (i += 1) big.limbs[i] = data[i]; |
| 1820 | const str = big.toString(c.a(), 10) catch |err| switch (err) { | 3133 | const str = big.toString(c.a(), 10) catch |err| switch (err) { |
| ... | @@ -1823,16 +3136,18 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { | ... | @@ -1823,16 +3136,18 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { |
| 1823 | }; | 3136 | }; |
| 1824 | const token = try appendToken(c, .IntegerLiteral, str); | 3137 | const token = try appendToken(c, .IntegerLiteral, str); |
| 1825 | const node = try c.a().create(ast.Node.IntegerLiteral); | 3138 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| 1826 | node.* = ast.Node.IntegerLiteral{ | 3139 | node.* = .{ |
| 1827 | .token = token, | 3140 | .token = token, |
| 1828 | }; | 3141 | }; |
| 3142 | if (is_negative) | ||
| 3143 | ZigClangAPSInt_free(aps_int); | ||
| 1829 | return &node.base; | 3144 | return &node.base; |
| 1830 | } | 3145 | } |
| 1831 | 3146 | ||
| 1832 | fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { | 3147 | fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 1833 | const ltoken = try appendToken(c, .Keyword_return, "return"); | 3148 | const ltoken = try appendToken(c, .Keyword_return, "return"); |
| 1834 | const node = try c.a().create(ast.Node.ControlFlowExpression); | 3149 | const node = try c.a().create(ast.Node.ControlFlowExpression); |
| 1835 | node.* = ast.Node.ControlFlowExpression{ | 3150 | node.* = .{ |
| 1836 | .ltoken = ltoken, | 3151 | .ltoken = ltoken, |
| 1837 | .kind = .Return, | 3152 | .kind = .Return, |
| 1838 | .rhs = null, | 3153 | .rhs = null, |
| ... | @@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { | ... | @@ -1843,7 +3158,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 1843 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { | 3158 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 1844 | const token = try appendToken(c, .Keyword_undefined, "undefined"); | 3159 | const token = try appendToken(c, .Keyword_undefined, "undefined"); |
| 1845 | const node = try c.a().create(ast.Node.UndefinedLiteral); | 3160 | const node = try c.a().create(ast.Node.UndefinedLiteral); |
| 1846 | node.* = ast.Node.UndefinedLiteral{ | 3161 | node.* = .{ |
| 1847 | .token = token, | 3162 | .token = token, |
| 1848 | }; | 3163 | }; |
| 1849 | return &node.base; | 3164 | return &node.base; |
| ... | @@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { | ... | @@ -1852,7 +3167,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 1852 | fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { | 3167 | fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { |
| 1853 | const token = try appendToken(c, .Keyword_null, "null"); | 3168 | const token = try appendToken(c, .Keyword_null, "null"); |
| 1854 | const node = try c.a().create(ast.Node.NullLiteral); | 3169 | const node = try c.a().create(ast.Node.NullLiteral); |
| 1855 | node.* = ast.Node.NullLiteral{ | 3170 | node.* = .{ |
| 1856 | .token = token, | 3171 | .token = token, |
| 1857 | }; | 3172 | }; |
| 1858 | return &node.base; | 3173 | return &node.base; |
| ... | @@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { | ... | @@ -1864,13 +3179,13 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { |
| 1864 | else | 3179 | else |
| 1865 | try appendToken(c, .Keyword_false, "false"); | 3180 | try appendToken(c, .Keyword_false, "false"); |
| 1866 | const node = try c.a().create(ast.Node.BoolLiteral); | 3181 | const node = try c.a().create(ast.Node.BoolLiteral); |
| 1867 | node.* = ast.Node.BoolLiteral{ | 3182 | node.* = .{ |
| 1868 | .token = token, | 3183 | .token = token, |
| 1869 | }; | 3184 | }; |
| 1870 | return &node.base; | 3185 | return &node.base; |
| 1871 | } | 3186 | } |
| 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 | _ = try appendToken(c, .LBrace, "{"); | 3189 | _ = try appendToken(c, .LBrace, "{"); |
| 1875 | const node = try c.a().create(ast.Node.SuffixOp); | 3190 | const node = try c.a().create(ast.Node.SuffixOp); |
| 1876 | node.* = ast.Node.SuffixOp{ | 3191 | node.* = ast.Node.SuffixOp{ |
| ... | @@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N | ... | @@ -1886,7 +3201,7 @@ fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.N |
| 1886 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { | 3201 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 1887 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); | 3202 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); |
| 1888 | const node = try c.a().create(ast.Node.IntegerLiteral); | 3203 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| 1889 | node.* = ast.Node.IntegerLiteral{ | 3204 | node.* = .{ |
| 1890 | .token = token, | 3205 | .token = token, |
| 1891 | }; | 3206 | }; |
| 1892 | return &node.base; | 3207 | return &node.base; |
| ... | @@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { | ... | @@ -1907,7 +3222,7 @@ fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { |
| 1907 | return &call_node.base; | 3222 | return &call_node.base; |
| 1908 | } | 3223 | } |
| 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 | const scope = &c.global_scope.base; | 3226 | const scope = &c.global_scope.base; |
| 1912 | 3227 | ||
| 1913 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); | 3228 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| ... | @@ -1916,8 +3231,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a | ... | @@ -1916,8 +3231,6 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 1916 | const name_tok = try appendIdentifier(c, name); | 3231 | const name_tok = try appendIdentifier(c, name); |
| 1917 | _ = try appendToken(c, .LParen, "("); | 3232 | _ = try appendToken(c, .LParen, "("); |
| 1918 | 3233 | ||
| 1919 | const proto_alias = proto_alias_node.cast(ast.Node.FnProto).?; | ||
| 1920 | |||
| 1921 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); | 3234 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); |
| 1922 | var it = proto_alias.params.iterator(0); | 3235 | var it = proto_alias.params.iterator(0); |
| 1923 | while (it.next()) |pn| { | 3236 | while (it.next()) |pn| { |
| ... | @@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { | ... | @@ -2046,6 +3359,172 @@ fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { |
| 2046 | return block_node; | 3359 | return block_node; |
| 2047 | } | 3360 | } |
| 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 | const RestorePoint = struct { | 3528 | const RestorePoint = struct { |
| 2050 | c: *Context, | 3529 | c: *Context, |
| 2051 | token_index: ast.TokenIndex, | 3530 | token_index: ast.TokenIndex, |
| ... | @@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2092,7 +3571,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2092 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), | 3571 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2093 | }); | 3572 | }); |
| 2094 | }, | 3573 | }, |
| 2095 | .FunctionProto => { | 3574 | .FunctionProto, .FunctionNoProto => { |
| 2096 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); | 3575 | const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); |
| 2097 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); | 3576 | const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); |
| 2098 | return &fn_proto.base; | 3577 | return &fn_proto.base; |
| ... | @@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2167,24 +3646,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2167 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); | 3646 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 2168 | 3647 | ||
| 2169 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); | 3648 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| 2170 | const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); | 3649 | return (try transTypeDef(rp.c, typedef_decl)) orelse |
| 2171 | return transCreateNodeIdentifier(rp.c, typedef_name); | 3650 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); |
| 2172 | }, | 3651 | }, |
| 2173 | .Record => { | 3652 | .Record => { |
| 2174 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); | 3653 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| 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 | const record_decl = ZigClangRecordType_getDecl(record_ty); | 3655 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 2184 | if (try getContainerName(rp, record_decl)) |name| | 3656 | return (try transRecordDecl(rp.c, record_decl)) orelse |
| 2185 | return transCreateNodeIdentifier(rp.c, name) | 3657 | revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); |
| 2186 | else | ||
| 2187 | return transRecordDecl(rp.c, record_decl); | ||
| 2188 | }, | 3658 | }, |
| 2189 | .Enum => { | 3659 | .Enum => { |
| 2190 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); | 3660 | const enum_ty = @ptrCast(*const ZigClangEnumType, ty); |
| ... | @@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2205,6 +3675,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2205 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); | 3675 | const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); |
| 2206 | return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); | 3676 | return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); |
| 2207 | }, | 3677 | }, |
| 3678 | .MacroQualified => { | ||
| 3679 | const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty); | ||
| 3680 | return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc); | ||
| 3681 | }, | ||
| 2208 | else => { | 3682 | else => { |
| 2209 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); | 3683 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 2210 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); | 3684 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); |
| ... | @@ -2212,22 +3686,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour | ... | @@ -2212,22 +3686,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 2212 | } | 3686 | } |
| 2213 | } | 3687 | } |
| 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 | fn isCVoid(qt: ZigClangQualType) bool { | 3689 | fn isCVoid(qt: ZigClangQualType) bool { |
| 2232 | const ty = ZigClangQualType_getTypePtr(qt); | 3690 | const ty = ZigClangQualType_getTypePtr(qt); |
| 2233 | if (ZigClangType_getTypeClass(ty) == .Builtin) { | 3691 | if (ZigClangType_getTypeClass(ty) == .Builtin) { |
| ... | @@ -2241,7 +3699,6 @@ const FnDeclContext = struct { | ... | @@ -2241,7 +3699,6 @@ const FnDeclContext = struct { |
| 2241 | fn_name: []const u8, | 3699 | fn_name: []const u8, |
| 2242 | has_body: bool, | 3700 | has_body: bool, |
| 2243 | storage_class: ZigClangStorageClass, | 3701 | storage_class: ZigClangStorageClass, |
| 2244 | scope: **Scope, | ||
| 2245 | is_export: bool, | 3702 | is_export: bool, |
| 2246 | }; | 3703 | }; |
| 2247 | 3704 | ||
| ... | @@ -2307,9 +3764,6 @@ fn finishTransFnProto( | ... | @@ -2307,9 +3764,6 @@ fn finishTransFnProto( |
| 2307 | // TODO check for always_inline attribute | 3764 | // TODO check for always_inline attribute |
| 2308 | // TODO check for align attribute | 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 | // pub extern fn name(...) T | 3767 | // pub extern fn name(...) T |
| 2314 | const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; | 3768 | const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; |
| 2315 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; | 3769 | const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; |
| ... | @@ -2335,15 +3789,11 @@ fn finishTransFnProto( | ... | @@ -2335,15 +3789,11 @@ fn finishTransFnProto( |
| 2335 | const param_name_tok: ?ast.TokenIndex = blk: { | 3789 | const param_name_tok: ?ast.TokenIndex = blk: { |
| 2336 | if (fn_decl != null) { | 3790 | if (fn_decl != null) { |
| 2337 | const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i)); | 3791 | const param = ZigClangFunctionDecl_getParamDecl(fn_decl.?, @intCast(c_uint, i)); |
| 2338 | var param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); | 3792 | const param_name: []const u8 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, param))); |
| 2339 | if (param_name.len < 1) | 3793 | if (param_name.len < 1) |
| 2340 | param_name = "arg"[0..]; | 3794 | break :blk null; |
| 2341 | const checked_param_name = if (try scope.createAlias(rp.c, param_name)) |a| blk: { | ||
| 2342 | try fndef_scope.params.push(.{ .name = param_name, .alias = a }); | ||
| 2343 | break :blk a; | ||
| 2344 | } else param_name; | ||
| 2345 | 3795 | ||
| 2346 | const result = try appendIdentifier(rp.c, checked_param_name); | 3796 | const result = try appendIdentifier(rp.c, param_name); |
| 2347 | _ = try appendToken(rp.c, .Colon, ":"); | 3797 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2348 | break :blk result; | 3798 | break :blk result; |
| 2349 | } | 3799 | } |
| ... | @@ -2410,14 +3860,13 @@ fn finishTransFnProto( | ... | @@ -2410,14 +3860,13 @@ fn finishTransFnProto( |
| 2410 | }; | 3860 | }; |
| 2411 | 3861 | ||
| 2412 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); | 3862 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); |
| 2413 | fn_proto.* = ast.Node.FnProto{ | 3863 | fn_proto.* = .{ |
| 2414 | .base = ast.Node{ .id = ast.Node.Id.FnProto }, | ||
| 2415 | .doc_comments = null, | 3864 | .doc_comments = null, |
| 2416 | .visib_token = pub_tok, | 3865 | .visib_token = pub_tok, |
| 2417 | .fn_token = fn_tok, | 3866 | .fn_token = fn_tok, |
| 2418 | .name_token = name_tok, | 3867 | .name_token = name_tok, |
| 2419 | .params = fn_params, | 3868 | .params = fn_params, |
| 2420 | .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, | 3869 | .return_type = .{ .Explicit = return_type_node }, |
| 2421 | .var_args_token = null, // TODO this field is broken in the AST data model | 3870 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 2422 | .extern_export_inline_token = extern_export_inline_tok, | 3871 | .extern_export_inline_token = extern_export_inline_tok, |
| 2423 | .cc_token = cc_tok, | 3872 | .cc_token = cc_tok, |
| ... | @@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, | ... | @@ -2523,6 +3972,41 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, |
| 2523 | return token_index; | 3972 | return token_index; |
| 2524 | } | 3973 | } |
| 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 | fn isValidZigIdentifier(name: []const u8) bool { | 4010 | fn isValidZigIdentifier(name: []const u8) bool { |
| 2527 | for (name) |c, i| { | 4011 | for (name) |c, i| { |
| 2528 | switch (c) { | 4012 | switch (c) { |
| ... | @@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -2573,27 +4057,31 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2573 | const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); | 4057 | const begin_loc = ZigClangMacroDefinitionRecord_getSourceRange_getBegin(macro); |
| 2574 | 4058 | ||
| 2575 | const name = try c.str(raw_name); | 4059 | const name = try c.str(raw_name); |
| 2576 | if (scope.contains(name)) { | 4060 | |
| 4061 | // TODO https://github.com/ziglang/zig/issues/3756 | ||
| 4062 | // TODO https://github.com/ziglang/zig/issues/1802 | ||
| 4063 | const checked_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name; | ||
| 4064 | if (scope.contains(checked_name)) { | ||
| 2577 | continue; | 4065 | continue; |
| 2578 | } | 4066 | } |
| 2579 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); | 4067 | const begin_c = ZigClangSourceManager_getCharacterData(c.source_manager, begin_loc); |
| 2580 | ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { | 4068 | ctok.tokenizeCMacro(&tok_list, begin_c) catch |err| switch (err) { |
| 2581 | error.OutOfMemory => |e| return e, | 4069 | error.OutOfMemory => |e| return e, |
| 2582 | else => { | 4070 | else => { |
| 2583 | try failDecl(c, begin_loc, name, "unable to tokenize macro definition", .{}); | 4071 | try failDecl(c, begin_loc, checked_name, "unable to tokenize macro definition", .{}); |
| 2584 | continue; | 4072 | continue; |
| 2585 | }, | 4073 | }, |
| 2586 | }; | 4074 | }; |
| 2587 | 4075 | ||
| 2588 | var tok_it = tok_list.iterator(0); | 4076 | var tok_it = tok_list.iterator(0); |
| 2589 | const first_tok = tok_it.next().?; | 4077 | const first_tok = tok_it.next().?; |
| 2590 | assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); | 4078 | assert(first_tok.id == .Identifier and mem.eql(u8, first_tok.bytes, name)); |
| 2591 | const next = tok_it.peek().?; | 4079 | const next = tok_it.peek().?; |
| 2592 | switch (next.id) { | 4080 | switch (next.id) { |
| 2593 | .Identifier => { | 4081 | .Identifier => { |
| 2594 | // if it equals itself, ignore. for example, from stdio.h: | 4082 | // if it equals itself, ignore. for example, from stdio.h: |
| 2595 | // #define stdin stdin | 4083 | // #define stdin stdin |
| 2596 | if (std.mem.eql(u8, name, next.bytes)) { | 4084 | if (mem.eql(u8, checked_name, next.bytes)) { |
| 2597 | continue; | 4085 | continue; |
| 2598 | } | 4086 | } |
| 2599 | }, | 4087 | }, |
| ... | @@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -2610,12 +4098,12 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 2610 | } else false; | 4098 | } else false; |
| 2611 | 4099 | ||
| 2612 | (if (macro_fn) | 4100 | (if (macro_fn) |
| 2613 | transMacroFnDefine(c, &tok_it, name, begin_loc) | 4101 | transMacroFnDefine(c, &tok_it, checked_name, begin_loc) |
| 2614 | else | 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 | error.UnsupportedTranslation, | 4104 | error.UnsupportedTranslation, |
| 2617 | error.ParseError, | 4105 | error.ParseError, |
| 2618 | => try failDecl(c, begin_loc, name, "unable to translate macro", .{}), | 4106 | => try failDecl(c, begin_loc, checked_name, "unable to translate macro", .{}), |
| 2619 | error.OutOfMemory => |e| return e, | 4107 | error.OutOfMemory => |e| return e, |
| 2620 | }; | 4108 | }; |
| 2621 | }, | 4109 | }, |
| ... | @@ -2628,37 +4116,28 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, | ... | @@ -2628,37 +4116,28 @@ fn transMacroDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, |
| 2628 | const rp = makeRestorePoint(c); | 4116 | const rp = makeRestorePoint(c); |
| 2629 | const scope = &c.global_scope.base; | 4117 | const scope = &c.global_scope.base; |
| 2630 | 4118 | ||
| 2631 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); | 4119 | const node = try transCreateNodeVarDecl(c, true, true, name); |
| 2632 | const mut_tok = try appendToken(c, .Keyword_const, "const"); | 4120 | node.eq_token = try appendToken(c, .Equal, "="); |
| 2633 | const name_tok = try appendIdentifier(c, name); | ||
| 2634 | const eq_tok = try appendToken(c, .Equal, "="); | ||
| 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); | 4133 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 2639 | node.* = ast.Node.VarDecl{ | ||
| 2640 | .doc_comments = null, | ||
| 2641 | .visib_token = visib_tok, | ||
| 2642 | .thread_local_token = null, | ||
| 2643 | .name_token = name_tok, | ||
| 2644 | .eq_token = eq_tok, | ||
| 2645 | .mut_token = mut_tok, | ||
| 2646 | .comptime_token = null, | ||
| 2647 | .extern_export_token = null, | ||
| 2648 | .lib_name = null, | ||
| 2649 | .type_node = null, | ||
| 2650 | .align_node = null, | ||
| 2651 | .section_node = null, | ||
| 2652 | .init_node = init_node, | ||
| 2653 | .semicolon_token = try appendToken(c, .Semicolon, ";"), | ||
| 2654 | }; | ||
| 2655 | _ = try c.global_scope.macro_table.put(name, &node.base); | 4134 | _ = try c.global_scope.macro_table.put(name, &node.base); |
| 2656 | } | 4135 | } |
| 2657 | 4136 | ||
| 2658 | fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { | 4137 | fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 2659 | const rp = makeRestorePoint(c); | 4138 | const rp = makeRestorePoint(c); |
| 2660 | var fndef_scope = Scope.FnDef.init(c); | 4139 | const block_scope = try Scope.Block.init(c, &c.global_scope.base, null); |
| 2661 | const scope = &fndef_scope.base; | 4140 | const scope = &block_scope.base; |
| 2662 | 4141 | ||
| 2663 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); | 4142 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 2664 | const inline_tok = try appendToken(c, .Keyword_inline, "inline"); | 4143 | const inline_tok = try appendToken(c, .Keyword_inline, "inline"); |
| ... | @@ -2676,7 +4155,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u | ... | @@ -2676,7 +4155,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u |
| 2676 | return error.ParseError; | 4155 | return error.ParseError; |
| 2677 | 4156 | ||
| 2678 | const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: { | 4157 | const checked_name = if (try scope.createAlias(c, param_tok.bytes)) |alias| blk: { |
| 2679 | try fndef_scope.params.push(.{ .name = param_tok.bytes, .alias = alias }); | 4158 | try block_scope.variables.push(.{ .name = param_tok.bytes, .alias = alias }); |
| 2680 | break :blk alias; | 4159 | break :blk alias; |
| 2681 | } else param_tok.bytes; | 4160 | } else param_tok.bytes; |
| 2682 | 4161 | ||
| ... | @@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u | ... | @@ -2737,6 +4216,15 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u |
| 2737 | 4216 | ||
| 2738 | const return_expr = try transCreateNodeReturnExpr(c); | 4217 | const return_expr = try transCreateNodeReturnExpr(c); |
| 2739 | const expr = try parseCExpr(rp, it, source_loc, scope); | 4218 | const expr = try parseCExpr(rp, it, source_loc, scope); |
| 4219 | const last = it.next().?; | ||
| 4220 | if (last.id != .Eof) | ||
| 4221 | return revertAndWarn( | ||
| 4222 | rp, | ||
| 4223 | error.UnsupportedTranslation, | ||
| 4224 | source_loc, | ||
| 4225 | "unable to translate C expr, unexpected token: {}", | ||
| 4226 | .{last.id}, | ||
| 4227 | ); | ||
| 2740 | _ = try appendToken(c, .Semicolon, ";"); | 4228 | _ = try appendToken(c, .Semicolon, ";"); |
| 2741 | try type_of.params.push(expr); | 4229 | try type_of.params.push(expr); |
| 2742 | return_expr.rhs = expr; | 4230 | return_expr.rhs = expr; |
| ... | @@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: | ... | @@ -2838,7 +4326,10 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: |
| 2838 | 4326 | ||
| 2839 | if (it.peek().?.id == .RParen) { | 4327 | if (it.peek().?.id == .RParen) { |
| 2840 | _ = it.next(); | 4328 | _ = it.next(); |
| 2841 | return inner_node; | 4329 | if (it.peek().?.id != .LParen) { |
| 4330 | return inner_node; | ||
| 4331 | } | ||
| 4332 | _ = it.next(); | ||
| 2842 | } | 4333 | } |
| 2843 | 4334 | ||
| 2844 | // hack to get zig fmt to render a comma in builtin calls | 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,8 +4421,8 @@ fn parseCPrimaryExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc: |
| 2930 | rp, | 4421 | rp, |
| 2931 | error.UnsupportedTranslation, | 4422 | error.UnsupportedTranslation, |
| 2932 | source_loc, | 4423 | source_loc, |
| 2933 | "unable to translate C expr", | 4424 | "unable to translate C expr, unexpected token: {}", |
| 2934 | .{}, | 4425 | .{tok.id}, |
| 2935 | ), | 4426 | ), |
| 2936 | } | 4427 | } |
| 2937 | } | 4428 | } |
| ... | @@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -2944,24 +4435,17 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2944 | .Dot => { | 4435 | .Dot => { |
| 2945 | const name_tok = it.next().?; | 4436 | const name_tok = it.next().?; |
| 2946 | if (name_tok.id != .Identifier) | 4437 | if (name_tok.id != .Identifier) |
| 2947 | return revertAndWarn( | 4438 | return error.ParseError; |
| 2948 | rp, | 4439 | |
| 2949 | error.ParseError, | 4440 | node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes); |
| 2950 | source_loc, | 4441 | }, |
| 2951 | "unable to translate C expr", | 4442 | .Arrow => { |
| 2952 | .{}, | 4443 | const name_tok = it.next().?; |
| 2953 | ); | 4444 | if (name_tok.id != .Identifier) |
| 2954 | 4445 | return error.ParseError; | |
| 2955 | const op_token = try appendToken(rp.c, .Period, "."); | 4446 | |
| 2956 | const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); | 4447 | const deref = try transCreateNodePtrDeref(rp.c, node); |
| 2957 | const access_node = try rp.c.a().create(ast.Node.InfixOp); | 4448 | node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes); |
| 2958 | access_node.* = .{ | ||
| 2959 | .op_token = op_token, | ||
| 2960 | .lhs = node, | ||
| 2961 | .op = .Period, | ||
| 2962 | .rhs = rhs, | ||
| 2963 | }; | ||
| 2964 | node = &access_node.base; | ||
| 2965 | }, | 4449 | }, |
| 2966 | .Asterisk => { | 4450 | .Asterisk => { |
| 2967 | if (it.peek().?.id == .RParen) { | 4451 | if (it.peek().?.id == .RParen) { |
| ... | @@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -2977,19 +4461,19 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2977 | // expr * expr | 4461 | // expr * expr |
| 2978 | const op_token = try appendToken(rp.c, .Asterisk, "*"); | 4462 | const op_token = try appendToken(rp.c, .Asterisk, "*"); |
| 2979 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); | 4463 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); |
| 2980 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); | 4464 | const mul_node = try rp.c.a().create(ast.Node.InfixOp); |
| 2981 | bitshift_node.* = .{ | 4465 | mul_node.* = .{ |
| 2982 | .op_token = op_token, | 4466 | .op_token = op_token, |
| 2983 | .lhs = node, | 4467 | .lhs = node, |
| 2984 | .op = .BitShiftLeft, | 4468 | .op = .BitShiftLeft, |
| 2985 | .rhs = rhs, | 4469 | .rhs = rhs, |
| 2986 | }; | 4470 | }; |
| 2987 | node = &bitshift_node.base; | 4471 | node = &mul_node.base; |
| 2988 | } | 4472 | } |
| 2989 | }, | 4473 | }, |
| 2990 | .Shl => { | 4474 | .Shl => { |
| 2991 | const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); | 4475 | const op_token = try appendToken(rp.c, .AngleBracketAngleBracketLeft, "<<"); |
| 2992 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); | 4476 | const rhs = try parseCExpr(rp, it, source_loc, scope); |
| 2993 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); | 4477 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); |
| 2994 | bitshift_node.* = .{ | 4478 | bitshift_node.* = .{ |
| 2995 | .op_token = op_token, | 4479 | .op_token = op_token, |
| ... | @@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -2999,6 +4483,42 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 2999 | }; | 4483 | }; |
| 3000 | node = &bitshift_node.base; | 4484 | node = &bitshift_node.base; |
| 3001 | }, | 4485 | }, |
| 4486 | .Pipe => { | ||
| 4487 | const op_token = try appendToken(rp.c, .Pipe, "|"); | ||
| 4488 | const rhs = try parseCExpr(rp, it, source_loc, scope); | ||
| 4489 | const or_node = try rp.c.a().create(ast.Node.InfixOp); | ||
| 4490 | or_node.* = .{ | ||
| 4491 | .op_token = op_token, | ||
| 4492 | .lhs = node, | ||
| 4493 | .op = .BitOr, | ||
| 4494 | .rhs = rhs, | ||
| 4495 | }; | ||
| 4496 | node = &or_node.base; | ||
| 4497 | }, | ||
| 4498 | .LBrace => { | ||
| 4499 | const arr_node = try transCreateNodeArrayAccess(rp.c, node); | ||
| 4500 | arr_node.op.ArrayAccess = try parseCExpr(rp, it, source_loc, scope); | ||
| 4501 | arr_node.rtoken = try appendToken(rp.c, .RBrace, "]"); | ||
| 4502 | node = &arr_node.base; | ||
| 4503 | if (it.next().?.id != .RBrace) | ||
| 4504 | return error.ParseError; | ||
| 4505 | }, | ||
| 4506 | .LParen => { | ||
| 4507 | const call_node = try transCreateNodeFnCall(rp.c, node); | ||
| 4508 | while (true) { | ||
| 4509 | const arg = try parseCExpr(rp, it, source_loc, scope); | ||
| 4510 | try call_node.op.Call.params.push(arg); | ||
| 4511 | const next = it.next().?; | ||
| 4512 | if (next.id == .Comma) | ||
| 4513 | _ = try appendToken(rp.c, .Comma, ",") | ||
| 4514 | else if (next.id == .RParen) | ||
| 4515 | break | ||
| 4516 | else | ||
| 4517 | return error.ParseError; | ||
| 4518 | } | ||
| 4519 | call_node.rtoken = try appendToken(rp.c, .RParen, ")"); | ||
| 4520 | node = &call_node.base; | ||
| 4521 | }, | ||
| 3002 | else => { | 4522 | else => { |
| 3003 | _ = it.prev(); | 4523 | _ = it.prev(); |
| 3004 | return node; | 4524 | return node; |
| ... | @@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -3028,13 +4548,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3028 | }, | 4548 | }, |
| 3029 | .Asterisk => { | 4549 | .Asterisk => { |
| 3030 | const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); | 4550 | const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); |
| 3031 | const node = try rp.c.a().create(ast.Node.SuffixOp); | 4551 | return try transCreateNodePtrDeref(rp.c, prefix_op_expr); |
| 3032 | node.* = .{ | ||
| 3033 | .lhs = .{ .node = prefix_op_expr }, | ||
| 3034 | .op = .Deref, | ||
| 3035 | .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"), | ||
| 3036 | }; | ||
| 3037 | return &node.base; | ||
| 3038 | }, | 4552 | }, |
| 3039 | else => { | 4553 | else => { |
| 3040 | _ = it.prev(); | 4554 | _ = it.prev(); |
| ... | @@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -3043,26 +4557,76 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3043 | } | 4557 | } |
| 3044 | } | 4558 | } |
| 3045 | 4559 | ||
| 3046 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []const u8 { | 4560 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { |
| 3047 | const tok = c.tree.tokens.at(token); | 4561 | const tok = c.tree.tokens.at(token); |
| 3048 | return c.source_buffer.toSliceConst()[tok.start..tok.end]; | 4562 | return c.source_buffer.toSlice()[tok.start..tok.end]; |
| 3049 | } | 4563 | } |
| 3050 | 4564 | ||
| 3051 | fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { | 4565 | fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { |
| 3052 | const init = if (ref.cast(ast.Node.VarDecl)) |v| v.init_node.? else return null; | 4566 | if (node.id == .ContainerDecl) { |
| 3053 | const name = if (init.cast(ast.Node.Identifier)) |id| | 4567 | return node; |
| 3054 | tokenSlice(c, id.token) | 4568 | } else if (node.id == .PrefixOp) { |
| 3055 | else | 4569 | return node; |
| 3056 | return null; | 4570 | } else if (node.cast(ast.Node.Identifier)) |ident| { |
| 3057 | // TODO a.b.c | 4571 | if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| { |
| 3058 | if (c.global_scope.sym_table.get(name)) |kv| { | 4572 | if (kv.value.cast(ast.Node.VarDecl)) |var_decl| |
| 3059 | if (kv.value.cast(ast.Node.VarDecl)) |val| { | 4573 | return getContainer(c, var_decl.init_node.?); |
| 3060 | if (val.type_node) |type_node| { | 4574 | } |
| 3061 | if (type_node.cast(ast.Node.PrefixOp)) |casted| { | 4575 | } else if (node.cast(ast.Node.InfixOp)) |infix| { |
| 3062 | if (casted.rhs.id == .FnProto) { | 4576 | if (infix.op != .Period) |
| 3063 | return casted.rhs; | 4577 | return null; |
| 4578 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { | ||
| 4579 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { | ||
| 4580 | var it = container.fields_and_decls.iterator(0); | ||
| 4581 | while (it.next()) |field_ref| { | ||
| 4582 | const field = field_ref.*.cast(ast.Node.ContainerField).?; | ||
| 4583 | const ident = infix.rhs.cast(ast.Node.Identifier).?; | ||
| 4584 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { | ||
| 4585 | return getContainer(c, field.type_expr.?); | ||
| 4586 | } | ||
| 4587 | } | ||
| 4588 | } | ||
| 4589 | } | ||
| 4590 | } | ||
| 4591 | return null; | ||
| 4592 | } | ||
| 4593 | |||
| 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,7 +4636,7 @@ fn getFnDecl(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 3072 | fn addMacros(c: *Context) !void { | 4636 | fn addMacros(c: *Context) !void { |
| 3073 | var macro_it = c.global_scope.macro_table.iterator(); | 4637 | var macro_it = c.global_scope.macro_table.iterator(); |
| 3074 | while (macro_it.next()) |kv| { | 4638 | while (macro_it.next()) |kv| { |
| 3075 | if (getFnDecl(c, kv.value)) |proto_node| { | 4639 | if (getFnProto(c, kv.value)) |proto_node| { |
| 3076 | // If a macro aliases a global variable which is a function pointer, we conclude that | 4640 | // If a macro aliases a global variable which is a function pointer, we conclude that |
| 3077 | // the macro is intended to represent a function that assumes the function pointer | 4641 | // the macro is intended to represent a function that assumes the function pointer |
| 3078 | // variable is non-null and calls it. | 4642 | // variable is non-null and calls it. |
src/zig_clang.cpp+15| ... | @@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi | ... | @@ -1571,6 +1571,16 @@ const ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const Zi |
| 1571 | return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl); | 1571 | return reinterpret_cast<const ZigClangTypedefNameDecl *>(decl); |
| 1572 | } | 1572 | } |
| 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 | const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) { | 1584 | const ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const ZigClangRecordDecl *zig_record_decl) { |
| 1575 | const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); | 1585 | const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); |
| 1576 | const clang::RecordDecl *definition = record_decl->getDefinition(); | 1586 | const clang::RecordDecl *definition = record_decl->getDefinition(); |
| ... | @@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D | ... | @@ -2161,6 +2171,11 @@ unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *D |
| 2161 | return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM); | 2171 | return casted->convertToHexString(DST, HexDigits, UpperCase, (llvm::APFloat::roundingMode)RM); |
| 2162 | } | 2172 | } |
| 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 | enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { | 2179 | enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { |
| 2165 | auto casted = reinterpret_cast<const clang::StringLiteral *>(self); | 2180 | auto casted = reinterpret_cast<const clang::StringLiteral *>(self); |
| 2166 | return (ZigClangStringLiteral_StringKind)casted->getKind(); | 2181 | return (ZigClangStringLiteral_StringKind)casted->getKind(); |
src/zig_clang.h+3| ... | @@ -856,6 +856,8 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc | ... | @@ -856,6 +856,8 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc |
| 856 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl); | 856 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl); |
| 857 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *); | 857 | ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *); |
| 858 | ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *); | 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 | ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *); | 862 | ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordDecl_getDefinition(const struct ZigClangRecordDecl *); |
| 861 | ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumDecl_getDefinition(const struct ZigClangEnumDecl *); | 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,6 +987,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st |
| 985 | 987 | ||
| 986 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, | 988 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, |
| 987 | unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); | 989 | unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); |
| 990 | ZIG_EXTERN_C double ZigClangAPFloat_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); | ||
| 988 | 991 | ||
| 989 | ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); | 992 | ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); |
| 990 | ZIG_EXTERN_C const char *ZigClangStringLiteral_getString_bytes_begin_size(const struct ZigClangStringLiteral *self, | 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,16 +127,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 127 | }); | 127 | }); |
| 128 | 128 | ||
| 129 | cases.addC_both("add, sub, mul, div, rem", | 129 | cases.addC_both("add, sub, mul, div, rem", |
| 130 | \\int s(int a, int b) { | 130 | \\int s() { |
| 131 | \\ int c; | 131 | \\ int a, b, c; |
| 132 | \\ c = a + b; | 132 | \\ c = a + b; |
| 133 | \\ c = a - b; | 133 | \\ c = a - b; |
| 134 | \\ c = a * b; | 134 | \\ c = a * b; |
| 135 | \\ c = a / b; | 135 | \\ c = a / b; |
| 136 | \\ c = a % b; | 136 | \\ c = a % b; |
| 137 | \\} | 137 | \\} |
| 138 | \\unsigned u(unsigned a, unsigned b) { | 138 | \\unsigned u() { |
| 139 | \\ unsigned c; | 139 | \\ unsigned a, b, c; |
| 140 | \\ c = a + b; | 140 | \\ c = a + b; |
| 141 | \\ c = a - b; | 141 | \\ c = a - b; |
| 142 | \\ c = a * b; | 142 | \\ c = a * b; |
| ... | @@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -144,7 +144,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 144 | \\ c = a % b; | 144 | \\ c = a % b; |
| 145 | \\} | 145 | \\} |
| 146 | , &[_][]const u8{ | 146 | , &[_][]const u8{ |
| 147 | \\pub export fn s(a: c_int, b: c_int) c_int { | 147 | \\pub export fn s() c_int { |
| 148 | \\ var a: c_int = undefined; | ||
| 149 | \\ var b: c_int = undefined; | ||
| 148 | \\ var c: c_int = undefined; | 150 | \\ var c: c_int = undefined; |
| 149 | \\ c = (a + b); | 151 | \\ c = (a + b); |
| 150 | \\ c = (a - b); | 152 | \\ c = (a - b); |
| ... | @@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -152,7 +154,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 152 | \\ c = @divTrunc(a, b); | 154 | \\ c = @divTrunc(a, b); |
| 153 | \\ c = @rem(a, b); | 155 | \\ c = @rem(a, b); |
| 154 | \\} | 156 | \\} |
| 155 | \\pub export fn u(a: c_uint, b: c_uint) c_uint { | 157 | \\pub export fn u() c_uint { |
| 158 | \\ var a: c_uint = undefined; | ||
| 159 | \\ var b: c_uint = undefined; | ||
| 156 | \\ var c: c_uint = undefined; | 160 | \\ var c: c_uint = undefined; |
| 157 | \\ c = (a +% b); | 161 | \\ c = (a +% b); |
| 158 | \\ c = (a -% b); | 162 | \\ c = (a -% b); |
| ... | @@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -162,50 +166,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 162 | \\} | 166 | \\} |
| 163 | }); | 167 | }); |
| 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 | cases.add_both("typedef of function in struct field", | 169 | cases.add_both("typedef of function in struct field", |
| 210 | \\typedef void lws_callback_function(void); | 170 | \\typedef void lws_callback_function(void); |
| 211 | \\struct Foo { | 171 | \\struct Foo { |
| ... | @@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -228,7 +188,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 228 | \\ struct Foo *foo; | 188 | \\ struct Foo *foo; |
| 229 | \\}; | 189 | \\}; |
| 230 | , &[_][]const u8{ | 190 | , &[_][]const u8{ |
| 231 | \\pub const struct_Foo = @OpaqueType() | 191 | \\pub const struct_Foo = @OpaqueType(); |
| 232 | , | 192 | , |
| 233 | \\pub const struct_Bar = extern struct { | 193 | \\pub const struct_Bar = extern struct { |
| 234 | \\ foo: ?*struct_Foo, | 194 | \\ foo: ?*struct_Foo, |
| ... | @@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -426,1240 +386,2280 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 426 | }, | 386 | }, |
| 427 | ); | 387 | ); |
| 428 | 388 | ||
| 429 | /////////////// Cases that pass for only stage2 //////////////// | 389 | cases.addC_both("null statements", |
| 430 | 390 | \\void foo(void) { | |
| 431 | cases.add_2("Parameterless function prototypes", | 391 | \\ ;;;;; |
| 432 | \\void a() {} | 392 | \\} |
| 433 | \\void b(void) {} | ||
| 434 | \\void c(); | ||
| 435 | \\void d(void); | ||
| 436 | , &[_][]const u8{ | 393 | , &[_][]const u8{ |
| 437 | \\pub export fn a() void {} | 394 | \\pub export fn foo() void { |
| 438 | \\pub export fn b() void {} | 395 | \\ {} |
| 439 | \\pub extern fn c(...) void; | 396 | \\ {} |
| 440 | \\pub extern fn d() void; | 397 | \\ {} |
| 398 | \\ {} | ||
| 399 | \\ {} | ||
| 400 | \\} | ||
| 441 | }); | 401 | }); |
| 442 | 402 | ||
| 443 | cases.add_2("variable declarations", | 403 | if (builtin.os != builtin.Os.windows) { |
| 444 | \\extern char arr0[] = "hello"; | 404 | // Windows treats this as an enum with type c_int |
| 445 | \\static char arr1[] = "hello"; | 405 | cases.add_both("big negative enum init values when C ABI supports long long enums", |
| 446 | \\char arr2[] = "hello"; | 406 | \\enum EnumWithInits { |
| 447 | , &[_][]const u8{ | 407 | \\ VAL01 = 0, |
| 448 | \\pub extern var arr0: [*c]u8 = "hello"; | 408 | \\ VAL02 = 1, |
| 449 | \\pub var arr1: [*c]u8 = "hello"; | 409 | \\ VAL03 = 2, |
| 450 | \\pub export var arr2: [*c]u8 = "hello"; | 410 | \\ VAL04 = 3, |
| 451 | }); | 411 | \\ VAL05 = -1, |
| 412 | \\ VAL06 = -2, | ||
| 413 | \\ VAL07 = -3, | ||
| 414 | \\ VAL08 = -4, | ||
| 415 | \\ VAL09 = VAL02 + VAL08, | ||
| 416 | \\ VAL10 = -1000012000, | ||
| 417 | \\ VAL11 = -1000161000, | ||
| 418 | \\ VAL12 = -1000174001, | ||
| 419 | \\ VAL13 = VAL09, | ||
| 420 | \\ VAL14 = VAL10, | ||
| 421 | \\ VAL15 = VAL11, | ||
| 422 | \\ VAL16 = VAL13, | ||
| 423 | \\ VAL17 = (VAL16 - VAL10 + 1), | ||
| 424 | \\ VAL18 = 0x1000000000000000L, | ||
| 425 | \\ VAL19 = VAL18 + VAL18 + VAL18 - 1, | ||
| 426 | \\ VAL20 = VAL19 + VAL19, | ||
| 427 | \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF, | ||
| 428 | \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1, | ||
| 429 | \\ VAL23 = 0xFFFFFFFFFFFFFFFF, | ||
| 430 | \\}; | ||
| 431 | , &[_][]const u8{ | ||
| 432 | \\pub const enum_EnumWithInits = extern enum(c_longlong) { | ||
| 433 | \\ VAL01 = 0, | ||
| 434 | \\ VAL02 = 1, | ||
| 435 | \\ VAL03 = 2, | ||
| 436 | \\ VAL04 = 3, | ||
| 437 | \\ VAL05 = -1, | ||
| 438 | \\ VAL06 = -2, | ||
| 439 | \\ VAL07 = -3, | ||
| 440 | \\ VAL08 = -4, | ||
| 441 | \\ VAL09 = -3, | ||
| 442 | \\ VAL10 = -1000012000, | ||
| 443 | \\ VAL11 = -1000161000, | ||
| 444 | \\ VAL12 = -1000174001, | ||
| 445 | \\ VAL13 = -3, | ||
| 446 | \\ VAL14 = -1000012000, | ||
| 447 | \\ VAL15 = -1000161000, | ||
| 448 | \\ VAL16 = -3, | ||
| 449 | \\ VAL17 = 1000011998, | ||
| 450 | \\ VAL18 = 1152921504606846976, | ||
| 451 | \\ VAL19 = 3458764513820540927, | ||
| 452 | \\ VAL20 = 6917529027641081854, | ||
| 453 | \\ VAL21 = 6917529027641081853, | ||
| 454 | \\ VAL22 = 0, | ||
| 455 | \\ VAL23 = -1, | ||
| 456 | \\}; | ||
| 457 | }); | ||
| 458 | } | ||
| 452 | 459 | ||
| 453 | cases.add_2("array initializer expr", | 460 | cases.addC_both("predefined expressions", |
| 454 | \\static void foo(void){ | 461 | \\void foo(void) { |
| 455 | \\ char arr[10] ={1}; | 462 | \\ __func__; |
| 456 | \\ char *arr1[10] ={0}; | 463 | \\ __FUNCTION__; |
| 464 | \\ __PRETTY_FUNCTION__; | ||
| 457 | \\} | 465 | \\} |
| 458 | , &[_][]const u8{ | 466 | , &[_][]const u8{ |
| 459 | \\pub fn foo() void { | 467 | \\pub export fn foo() void { |
| 460 | \\ var arr: [10]u8 = .{ | 468 | \\ _ = "foo"; |
| 461 | \\ @as(u8, 1), | 469 | \\ _ = "foo"; |
| 462 | \\ } ++ .{0} ** 9; | 470 | \\ _ = "void foo(void)"; |
| 463 | \\ var arr1: [10][*c]u8 = .{ | ||
| 464 | \\ null, | ||
| 465 | \\ } ++ .{null} ** 9; | ||
| 466 | \\} | 471 | \\} |
| 467 | }); | 472 | }); |
| 468 | 473 | ||
| 469 | cases.add_2("enums", | 474 | cases.addC_both("ignore result, no function arguments", |
| 470 | \\typedef enum { | 475 | \\void foo() { |
| 471 | \\ a, | 476 | \\ int a; |
| 472 | \\ b, | 477 | \\ 1; |
| 473 | \\ c, | 478 | \\ "hey"; |
| 474 | \\} d; | 479 | \\ 1 + 1; |
| 475 | \\enum { | 480 | \\ 1 - 1; |
| 476 | \\ e, | 481 | \\ a = 1; |
| 477 | \\ f = 4, | 482 | \\} |
| 478 | \\ g, | ||
| 479 | \\} h = e; | ||
| 480 | \\struct Baz { | ||
| 481 | \\ enum { | ||
| 482 | \\ i, | ||
| 483 | \\ j, | ||
| 484 | \\ k, | ||
| 485 | \\ } l; | ||
| 486 | \\ d m; | ||
| 487 | \\}; | ||
| 488 | \\enum i { | ||
| 489 | \\ n, | ||
| 490 | \\ o, | ||
| 491 | \\ p, | ||
| 492 | \\}; | ||
| 493 | , &[_][]const u8{ | 483 | , &[_][]const u8{ |
| 494 | \\pub const a = enum_unnamed_1.a; | 484 | \\pub export fn foo() void { |
| 495 | \\pub const b = enum_unnamed_1.b; | 485 | \\ var a: c_int = undefined; |
| 496 | \\pub const c = enum_unnamed_1.c; | 486 | \\ _ = 1; |
| 497 | \\pub const enum_unnamed_1 = extern enum { | 487 | \\ _ = "hey"; |
| 498 | \\ a, | 488 | \\ _ = (1 + 1); |
| 499 | \\ b, | 489 | \\ _ = (1 - 1); |
| 500 | \\ c, | 490 | \\ a = 1; |
| 501 | \\}; | 491 | \\} |
| 502 | \\pub const d = enum_unnamed_1; | ||
| 503 | \\pub const e = enum_unnamed_2.e; | ||
| 504 | \\pub const f = enum_unnamed_2.f; | ||
| 505 | \\pub const g = enum_unnamed_2.g; | ||
| 506 | \\pub const enum_unnamed_2 = extern enum { | ||
| 507 | \\ e = 0, | ||
| 508 | \\ f = 4, | ||
| 509 | \\ g = 5, | ||
| 510 | \\}; | ||
| 511 | \\pub export var h: enum_unnamed_2 = @as(enum_unnamed_2, e); | ||
| 512 | \\pub const i = enum_unnamed_3.i; | ||
| 513 | \\pub const j = enum_unnamed_3.j; | ||
| 514 | \\pub const k = enum_unnamed_3.k; | ||
| 515 | \\pub const enum_unnamed_3 = extern enum { | ||
| 516 | \\ i, | ||
| 517 | \\ j, | ||
| 518 | \\ k, | ||
| 519 | \\}; | ||
| 520 | \\pub const struct_Baz = extern struct { | ||
| 521 | \\ l: enum_unnamed_3, | ||
| 522 | \\ m: d, | ||
| 523 | \\}; | ||
| 524 | \\pub const n = enum_i.n; | ||
| 525 | \\pub const o = enum_i.o; | ||
| 526 | \\pub const p = enum_i.p; | ||
| 527 | \\pub const enum_i = extern enum { | ||
| 528 | \\ n, | ||
| 529 | \\ o, | ||
| 530 | \\ p, | ||
| 531 | \\}; | ||
| 532 | , | ||
| 533 | \\pub const Baz = struct_Baz; | ||
| 534 | }); | 492 | }); |
| 535 | 493 | ||
| 536 | cases.add_2("#define a char literal", | 494 | cases.add_both("constant size array", |
| 537 | \\#define A_CHAR 'a' | 495 | \\void func(int array[20]); |
| 538 | , &[_][]const u8{ | 496 | , &[_][]const u8{ |
| 539 | \\pub const A_CHAR = 'a'; | 497 | \\pub extern fn func(array: [*c]c_int) void; |
| 540 | }); | 498 | }); |
| 541 | 499 | ||
| 542 | cases.add_2("comment after integer literal", | 500 | cases.add_both("__cdecl doesn't mess up function pointers", |
| 543 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | 501 | \\void foo(void (__cdecl *fn_ptr)(void)); |
| 544 | , &[_][]const u8{ | 502 | , &[_][]const u8{ |
| 545 | \\pub const SDL_INIT_VIDEO = 0x00000020; | 503 | \\pub extern fn foo(fn_ptr: ?extern fn () void) void; |
| 546 | }); | 504 | }); |
| 547 | 505 | ||
| 548 | cases.add_2("u integer suffix after hex literal", | 506 | cases.addC_both("void cast", |
| 549 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | 507 | \\void foo() { |
| 508 | \\ int a; | ||
| 509 | \\ (void) a; | ||
| 510 | \\} | ||
| 550 | , &[_][]const u8{ | 511 | , &[_][]const u8{ |
| 551 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); | 512 | \\pub export fn foo() void { |
| 513 | \\ var a: c_int = undefined; | ||
| 514 | \\ _ = a; | ||
| 515 | \\} | ||
| 552 | }); | 516 | }); |
| 553 | 517 | ||
| 554 | cases.add_2("l integer suffix after hex literal", | 518 | cases.addC_both("implicit cast to void *", |
| 555 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | 519 | \\void *foo() { |
| 520 | \\ unsigned short *x; | ||
| 521 | \\ return x; | ||
| 522 | \\} | ||
| 556 | , &[_][]const u8{ | 523 | , &[_][]const u8{ |
| 557 | \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); | 524 | \\pub export fn foo() ?*c_void { |
| 525 | \\ var x: [*c]c_ushort = undefined; | ||
| 526 | \\ return @ptrCast(?*c_void, x); | ||
| 527 | \\} | ||
| 558 | }); | 528 | }); |
| 559 | 529 | ||
| 560 | cases.add_2("ul integer suffix after hex literal", | 530 | cases.addC_both("null pointer implicit cast", |
| 561 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | 531 | \\int* foo(void) { |
| 532 | \\ return 0; | ||
| 533 | \\} | ||
| 562 | , &[_][]const u8{ | 534 | , &[_][]const u8{ |
| 563 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); | 535 | \\pub export fn foo() [*c]c_int { |
| 536 | \\ return null; | ||
| 537 | \\} | ||
| 564 | }); | 538 | }); |
| 565 | 539 | ||
| 566 | cases.add_2("lu integer suffix after hex literal", | 540 | cases.add_both("simple union", |
| 567 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | 541 | \\union Foo { |
| 542 | \\ int x; | ||
| 543 | \\ double y; | ||
| 544 | \\}; | ||
| 568 | , &[_][]const u8{ | 545 | , &[_][]const u8{ |
| 569 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); | 546 | \\pub const union_Foo = extern union { |
| 570 | }); | 547 | \\ x: c_int, |
| 571 | 548 | \\ y: f64, | |
| 572 | cases.add_2("ll integer suffix after hex literal", | ||
| 573 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 574 | , &[_][]const u8{ | ||
| 575 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); | ||
| 576 | }); | ||
| 577 | |||
| 578 | cases.add_2("ull integer suffix after hex literal", | ||
| 579 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 580 | , &[_][]const u8{ | ||
| 581 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | ||
| 582 | }); | ||
| 583 | |||
| 584 | cases.add_2("llu integer suffix after hex literal", | ||
| 585 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 586 | , &[_][]const u8{ | ||
| 587 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); | ||
| 588 | }); | ||
| 589 | |||
| 590 | cases.add_2("generate inline func for #define global extern fn", | ||
| 591 | \\extern void (*fn_ptr)(void); | ||
| 592 | \\#define foo fn_ptr | ||
| 593 | \\ | ||
| 594 | \\extern char (*fn_ptr2)(int, float); | ||
| 595 | \\#define bar fn_ptr2 | ||
| 596 | , &[_][]const u8{ | ||
| 597 | \\pub extern var fn_ptr: ?extern fn () void; | ||
| 598 | , | ||
| 599 | \\pub inline fn foo() void { | ||
| 600 | \\ return fn_ptr.?(); | ||
| 601 | \\} | ||
| 602 | , | ||
| 603 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | ||
| 604 | , | ||
| 605 | \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { | ||
| 606 | \\ return fn_ptr2.?(arg_1, arg_2); | ||
| 607 | \\} | ||
| 608 | }); | ||
| 609 | |||
| 610 | cases.add_2("macros with field targets", | ||
| 611 | \\typedef unsigned int GLbitfield; | ||
| 612 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | ||
| 613 | \\typedef void(*OpenGLProc)(void); | ||
| 614 | \\union OpenGLProcs { | ||
| 615 | \\ OpenGLProc ptr[1]; | ||
| 616 | \\ struct { | ||
| 617 | \\ PFNGLCLEARPROC Clear; | ||
| 618 | \\ } gl; | ||
| 619 | \\}; | ||
| 620 | \\extern union OpenGLProcs glProcs; | ||
| 621 | \\#define glClearUnion glProcs.gl.Clear | ||
| 622 | \\#define glClearPFN PFNGLCLEARPROC | ||
| 623 | , &[_][]const u8{ | ||
| 624 | \\pub const GLbitfield = c_uint; | ||
| 625 | , | ||
| 626 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | ||
| 627 | , | ||
| 628 | \\pub const OpenGLProc = ?extern fn () void; | ||
| 629 | , | ||
| 630 | \\pub const union_OpenGLProcs = extern union { | ||
| 631 | \\ ptr: [1]OpenGLProc, | ||
| 632 | \\ gl: extern struct { | ||
| 633 | \\ Clear: PFNGLCLEARPROC, | ||
| 634 | \\ }, | ||
| 635 | \\}; | 549 | \\}; |
| 636 | , | 550 | , |
| 637 | \\pub extern var glProcs: union_OpenGLProcs; | 551 | \\pub const Foo = union_Foo; |
| 638 | , | ||
| 639 | \\pub const glClearPFN = PFNGLCLEARPROC; | ||
| 640 | // , // TODO | ||
| 641 | // \\pub inline fn glClearUnion(arg_1: GLbitfield) void { | ||
| 642 | // \\ return glProcs.gl.Clear.?(arg_1); | ||
| 643 | // \\} | ||
| 644 | , | ||
| 645 | \\pub const OpenGLProcs = union_OpenGLProcs; | ||
| 646 | }); | ||
| 647 | |||
| 648 | cases.add_2("macro pointer cast", | ||
| 649 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | ||
| 650 | , &[_][]const u8{ | ||
| 651 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | ||
| 652 | }); | ||
| 653 | |||
| 654 | cases.add_2("basic macro function", | ||
| 655 | \\extern int c; | ||
| 656 | \\#define BASIC(c) (c*2) | ||
| 657 | , &[_][]const u8{ | ||
| 658 | \\pub extern var c: c_int; | ||
| 659 | , | ||
| 660 | \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) { | ||
| 661 | \\ return c_1 * 2; | ||
| 662 | \\} | ||
| 663 | }); | ||
| 664 | |||
| 665 | cases.add_2("macro escape sequences", | ||
| 666 | \\#define FOO "aoeu\xab derp" | ||
| 667 | \\#define FOO2 "aoeu\a derp" | ||
| 668 | , &[_][]const u8{ | ||
| 669 | \\pub const FOO = "aoeu\xab derp"; | ||
| 670 | , | ||
| 671 | \\pub const FOO2 = "aoeu\x07 derp"; | ||
| 672 | }); | 552 | }); |
| 673 | 553 | ||
| 674 | cases.add_2("variable aliasing", | 554 | cases.addC_both("string literal", |
| 675 | \\static long a = 2; | 555 | \\const char *foo(void) { |
| 676 | \\static long b = 2; | 556 | \\ return "bar"; |
| 677 | \\static int c = 4; | ||
| 678 | \\void foo(char c) { | ||
| 679 | \\ int a; | ||
| 680 | \\ char b = 123; | ||
| 681 | \\ b = (char) a; | ||
| 682 | \\ { | ||
| 683 | \\ int d = 5; | ||
| 684 | \\ } | ||
| 685 | \\ unsigned d = 440; | ||
| 686 | \\} | 557 | \\} |
| 687 | , &[_][]const u8{ | 558 | , &[_][]const u8{ |
| 688 | \\pub var a: c_long = @as(c_long, 2); | 559 | \\pub export fn foo() [*c]const u8 { |
| 689 | \\pub var b: c_long = @as(c_long, 2); | 560 | \\ return "bar"; |
| 690 | \\pub var c: c_int = 4; | ||
| 691 | \\pub export fn foo(c_1: u8) void { | ||
| 692 | \\ var a_2: c_int = undefined; | ||
| 693 | \\ var b_3: u8 = @as(u8, 123); | ||
| 694 | \\ b_3 = @as(u8, a_2); | ||
| 695 | \\ { | ||
| 696 | \\ var d: c_int = 5; | ||
| 697 | \\ } | ||
| 698 | \\ var d: c_uint = @as(c_uint, 440); | ||
| 699 | \\} | 561 | \\} |
| 700 | }); | 562 | }); |
| 701 | 563 | ||
| 702 | /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// | 564 | cases.addC_both("return void", |
| 703 | |||
| 704 | if (builtin.os != builtin.Os.windows) { | ||
| 705 | // Windows treats this as an enum with type c_int | ||
| 706 | cases.add("big negative enum init values when C ABI supports long long enums", | ||
| 707 | \\enum EnumWithInits { | ||
| 708 | \\ VAL01 = 0, | ||
| 709 | \\ VAL02 = 1, | ||
| 710 | \\ VAL03 = 2, | ||
| 711 | \\ VAL04 = 3, | ||
| 712 | \\ VAL05 = -1, | ||
| 713 | \\ VAL06 = -2, | ||
| 714 | \\ VAL07 = -3, | ||
| 715 | \\ VAL08 = -4, | ||
| 716 | \\ VAL09 = VAL02 + VAL08, | ||
| 717 | \\ VAL10 = -1000012000, | ||
| 718 | \\ VAL11 = -1000161000, | ||
| 719 | \\ VAL12 = -1000174001, | ||
| 720 | \\ VAL13 = VAL09, | ||
| 721 | \\ VAL14 = VAL10, | ||
| 722 | \\ VAL15 = VAL11, | ||
| 723 | \\ VAL16 = VAL13, | ||
| 724 | \\ VAL17 = (VAL16 - VAL10 + 1), | ||
| 725 | \\ VAL18 = 0x1000000000000000L, | ||
| 726 | \\ VAL19 = VAL18 + VAL18 + VAL18 - 1, | ||
| 727 | \\ VAL20 = VAL19 + VAL19, | ||
| 728 | \\ VAL21 = VAL20 + 0xFFFFFFFFFFFFFFFF, | ||
| 729 | \\ VAL22 = 0xFFFFFFFFFFFFFFFF + 1, | ||
| 730 | \\ VAL23 = 0xFFFFFFFFFFFFFFFF, | ||
| 731 | \\}; | ||
| 732 | , &[_][]const u8{ | ||
| 733 | \\pub const enum_EnumWithInits = extern enum(c_longlong) { | ||
| 734 | \\ VAL01 = 0, | ||
| 735 | \\ VAL02 = 1, | ||
| 736 | \\ VAL03 = 2, | ||
| 737 | \\ VAL04 = 3, | ||
| 738 | \\ VAL05 = -1, | ||
| 739 | \\ VAL06 = -2, | ||
| 740 | \\ VAL07 = -3, | ||
| 741 | \\ VAL08 = -4, | ||
| 742 | \\ VAL09 = -3, | ||
| 743 | \\ VAL10 = -1000012000, | ||
| 744 | \\ VAL11 = -1000161000, | ||
| 745 | \\ VAL12 = -1000174001, | ||
| 746 | \\ VAL13 = -3, | ||
| 747 | \\ VAL14 = -1000012000, | ||
| 748 | \\ VAL15 = -1000161000, | ||
| 749 | \\ VAL16 = -3, | ||
| 750 | \\ VAL17 = 1000011998, | ||
| 751 | \\ VAL18 = 1152921504606846976, | ||
| 752 | \\ VAL19 = 3458764513820540927, | ||
| 753 | \\ VAL20 = 6917529027641081854, | ||
| 754 | \\ VAL21 = 6917529027641081853, | ||
| 755 | \\ VAL22 = 0, | ||
| 756 | \\ VAL23 = -1, | ||
| 757 | \\}; | ||
| 758 | }); | ||
| 759 | } | ||
| 760 | |||
| 761 | cases.add("predefined expressions", | ||
| 762 | \\void foo(void) { | 565 | \\void foo(void) { |
| 763 | \\ __func__; | 566 | \\ return; |
| 764 | \\ __FUNCTION__; | ||
| 765 | \\ __PRETTY_FUNCTION__; | ||
| 766 | \\} | 567 | \\} |
| 767 | , &[_][]const u8{ | 568 | , &[_][]const u8{ |
| 768 | \\pub fn foo() void { | 569 | \\pub export fn foo() void { |
| 769 | \\ _ = "foo"; | 570 | \\ return; |
| 770 | \\ _ = "foo"; | ||
| 771 | \\ _ = "void foo(void)"; | ||
| 772 | \\} | 571 | \\} |
| 773 | }); | 572 | }); |
| 774 | 573 | ||
| 775 | cases.add("ignore result, no function arguments", | 574 | cases.addC_both("for loop", |
| 776 | \\void foo() { | 575 | \\void foo(void) { |
| 777 | \\ int a; | 576 | \\ for (int i = 0; i; i = i + 1) { } |
| 778 | \\ 1; | ||
| 779 | \\ "hey"; | ||
| 780 | \\ 1 + 1; | ||
| 781 | \\ 1 - 1; | ||
| 782 | \\ a = 1; | ||
| 783 | \\} | 577 | \\} |
| 784 | , &[_][]const u8{ | 578 | , &[_][]const u8{ |
| 785 | \\pub fn foo() void { | 579 | \\pub export fn foo() void { |
| 786 | \\ var a: c_int = undefined; | 580 | \\ { |
| 787 | \\ _ = 1; | 581 | \\ var i: c_int = 0; |
| 788 | \\ _ = "hey"; | 582 | \\ while (i != 0) : (i = (i + 1)) {} |
| 789 | \\ _ = (1 + 1); | 583 | \\ } |
| 790 | \\ _ = (1 - 1); | ||
| 791 | \\ a = 1; | ||
| 792 | \\} | 584 | \\} |
| 793 | }); | 585 | }); |
| 794 | 586 | ||
| 795 | cases.add("for loop with var init but empty body", | 587 | cases.addC_both("empty for loop", |
| 796 | \\void foo(void) { | 588 | \\void foo(void) { |
| 797 | \\ for (int x = 0; x < 10; x++); | 589 | \\ for (;;) { } |
| 798 | \\} | 590 | \\} |
| 799 | , &[_][]const u8{ | 591 | , &[_][]const u8{ |
| 800 | \\pub fn foo() void { | 592 | \\pub export fn foo() void { |
| 801 | \\ { | 593 | \\ while (true) {} |
| 802 | \\ var x: c_int = 0; | ||
| 803 | \\ while (x < 10) : (x += 1) {} | ||
| 804 | \\ } | ||
| 805 | \\} | 594 | \\} |
| 806 | }); | 595 | }); |
| 807 | 596 | ||
| 808 | cases.add("do while with empty body", | 597 | cases.addC_both("break statement", |
| 809 | \\void foo(void) { | 598 | \\void foo(void) { |
| 810 | \\ do ; while (1); | 599 | \\ for (;;) { |
| 600 | \\ break; | ||
| 601 | \\ } | ||
| 811 | \\} | 602 | \\} |
| 812 | , &[_][]const u8{ // TODO this should be if (1 != 0) break | 603 | , &[_][]const u8{ |
| 813 | \\pub fn foo() void { | 604 | \\pub export fn foo() void { |
| 814 | \\ while (true) { | 605 | \\ while (true) { |
| 815 | \\ {} | 606 | \\ break; |
| 816 | \\ if (!1) break; | ||
| 817 | \\ } | 607 | \\ } |
| 818 | \\} | 608 | \\} |
| 819 | }); | 609 | }); |
| 820 | 610 | ||
| 821 | cases.add("for with empty body", | 611 | cases.addC_both("continue statement", |
| 822 | \\void foo(void) { | 612 | \\void foo(void) { |
| 823 | \\ for (;;); | 613 | \\ for (;;) { |
| 614 | \\ continue; | ||
| 615 | \\ } | ||
| 824 | \\} | 616 | \\} |
| 825 | , &[_][]const u8{ | 617 | , &[_][]const u8{ |
| 826 | \\pub fn foo() void { | 618 | \\pub export fn foo() void { |
| 827 | \\ while (true) {} | 619 | \\ while (true) { |
| 620 | \\ continue; | ||
| 621 | \\ } | ||
| 828 | \\} | 622 | \\} |
| 829 | }); | 623 | }); |
| 830 | 624 | ||
| 831 | cases.add("while with empty body", | 625 | cases.addC_both("pointer casting", |
| 832 | \\void foo(void) { | 626 | \\float *ptrcast() { |
| 833 | \\ while (1); | 627 | \\ int *a; |
| 628 | \\ return (float *)a; | ||
| 834 | \\} | 629 | \\} |
| 835 | , &[_][]const u8{ | 630 | , &[_][]const u8{ |
| 836 | \\pub fn foo() void { | 631 | \\pub export fn ptrcast() [*c]f32 { |
| 837 | \\ while (1 != 0) {} | 632 | \\ var a: [*c]c_int = undefined; |
| 633 | \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); | ||
| 838 | \\} | 634 | \\} |
| 839 | }); | 635 | }); |
| 840 | 636 | ||
| 841 | cases.addAllowWarnings("simple data types", | 637 | cases.addC_both("pointer conversion with different alignment", |
| 842 | \\#include <stdint.h> | 638 | \\void test_ptr_cast() { |
| 843 | \\int foo(char a, unsigned char b, signed char c); | 639 | \\ void *p; |
| 844 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | 640 | \\ { |
| 845 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | 641 | \\ char *to_char = (char *)p; |
| 846 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | 642 | \\ short *to_short = (short *)p; |
| 847 | , &[_][]const u8{ | 643 | \\ int *to_int = (int *)p; |
| 848 | \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; | 644 | \\ long long *to_longlong = (long long *)p; |
| 849 | , | 645 | \\ } |
| 850 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; | 646 | \\ { |
| 851 | , | 647 | \\ char *to_char = p; |
| 852 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; | 648 | \\ short *to_short = p; |
| 853 | }); | 649 | \\ int *to_int = p; |
| 854 | 650 | \\ long long *to_longlong = p; | |
| 855 | cases.addC("simple function", | 651 | \\ } |
| 856 | \\int abs(int a) { | ||
| 857 | \\ return a < 0 ? -a : a; | ||
| 858 | \\} | 652 | \\} |
| 859 | , &[_][]const u8{ | 653 | , &[_][]const u8{ |
| 860 | \\export fn abs(a: c_int) c_int { | 654 | \\pub export fn test_ptr_cast() void { |
| 861 | \\ return if (a < 0) -a else a; | 655 | \\ var p: ?*c_void = undefined; |
| 656 | \\ { | ||
| 657 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | ||
| 658 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | ||
| 659 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | ||
| 660 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | ||
| 661 | \\ } | ||
| 662 | \\ { | ||
| 663 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | ||
| 664 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | ||
| 665 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | ||
| 666 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | ||
| 667 | \\ } | ||
| 862 | \\} | 668 | \\} |
| 863 | }); | 669 | }); |
| 864 | 670 | ||
| 865 | cases.add("restrict -> noalias", | 671 | cases.addC_both("while on non-bool", |
| 866 | \\void foo(void *restrict bar, void *restrict); | 672 | \\int while_none_bool() { |
| 867 | , &[_][]const u8{ | 673 | \\ int a; |
| 868 | \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; | 674 | \\ float b; |
| 869 | }); | 675 | \\ void *c; |
| 870 | 676 | \\ while (a) return 0; | |
| 871 | cases.add("qualified struct and enum", | 677 | \\ while (b) return 1; |
| 872 | \\struct Foo { | 678 | \\ while (c) return 2; |
| 873 | \\ int x; | 679 | \\ return 3; |
| 874 | \\ int y; | 680 | \\} |
| 875 | \\}; | ||
| 876 | \\enum Bar { | ||
| 877 | \\ BarA, | ||
| 878 | \\ BarB, | ||
| 879 | \\}; | ||
| 880 | \\void func(struct Foo *a, enum Bar **b); | ||
| 881 | , &[_][]const u8{ | ||
| 882 | \\pub const struct_Foo = extern struct { | ||
| 883 | \\ x: c_int, | ||
| 884 | \\ y: c_int, | ||
| 885 | \\}; | ||
| 886 | , | ||
| 887 | \\pub const enum_Bar = extern enum { | ||
| 888 | \\ A, | ||
| 889 | \\ B, | ||
| 890 | \\}; | ||
| 891 | , | ||
| 892 | \\pub const BarA = enum_Bar.A; | ||
| 893 | , | ||
| 894 | \\pub const BarB = enum_Bar.B; | ||
| 895 | , | ||
| 896 | \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void; | ||
| 897 | , | ||
| 898 | \\pub const Foo = struct_Foo; | ||
| 899 | , | ||
| 900 | \\pub const Bar = enum_Bar; | ||
| 901 | }); | ||
| 902 | |||
| 903 | cases.add("constant size array", | ||
| 904 | \\void func(int array[20]); | ||
| 905 | , &[_][]const u8{ | ||
| 906 | \\pub extern fn func(array: [*c]c_int) void; | ||
| 907 | }); | ||
| 908 | |||
| 909 | cases.add("__cdecl doesn't mess up function pointers", | ||
| 910 | \\void foo(void (__cdecl *fn_ptr)(void)); | ||
| 911 | , &[_][]const u8{ | ||
| 912 | \\pub extern fn foo(fn_ptr: ?extern fn () void) void; | ||
| 913 | }); | ||
| 914 | |||
| 915 | cases.add("macro defines string literal with hex", | ||
| 916 | \\#define FOO "aoeu\xab derp" | ||
| 917 | \\#define FOO2 "aoeu\x0007a derp" | ||
| 918 | \\#define FOO_CHAR '\xfF' | ||
| 919 | , &[_][]const u8{ | ||
| 920 | \\pub const FOO = "aoeu\xab derp"; | ||
| 921 | , | ||
| 922 | \\pub const FOO2 = "aoeuz derp"; | ||
| 923 | , | ||
| 924 | \\pub const FOO_CHAR = 255; | ||
| 925 | }); | ||
| 926 | |||
| 927 | cases.add("macro defines string literal with octal", | ||
| 928 | \\#define FOO "aoeu\023 derp" | ||
| 929 | \\#define FOO2 "aoeu\0234 derp" | ||
| 930 | \\#define FOO_CHAR '\077' | ||
| 931 | , &[_][]const u8{ | 681 | , &[_][]const u8{ |
| 932 | \\pub const FOO = "aoeu\x13 derp"; | 682 | \\pub export fn while_none_bool() c_int { |
| 933 | , | 683 | \\ var a: c_int = undefined; |
| 934 | \\pub const FOO2 = "aoeu\x134 derp"; | 684 | \\ var b: f32 = undefined; |
| 935 | , | 685 | \\ var c: ?*c_void = undefined; |
| 936 | \\pub const FOO_CHAR = 63; | 686 | \\ while (a != 0) return 0; |
| 687 | \\ while (b != 0) return 1; | ||
| 688 | \\ while (c != null) return 2; | ||
| 689 | \\ return 3; | ||
| 690 | \\} | ||
| 937 | }); | 691 | }); |
| 938 | 692 | ||
| 939 | cases.addC("post increment", | 693 | cases.addC_both("for on non-bool", |
| 940 | \\unsigned foo1(unsigned a) { | 694 | \\int for_none_bool() { |
| 941 | \\ a++; | 695 | \\ int a; |
| 942 | \\ return a; | 696 | \\ float b; |
| 943 | \\} | 697 | \\ void *c; |
| 944 | \\int foo2(int a) { | 698 | \\ for (;a;) return 0; |
| 945 | \\ a++; | 699 | \\ for (;b;) return 1; |
| 946 | \\ return a; | 700 | \\ for (;c;) return 2; |
| 701 | \\ return 3; | ||
| 947 | \\} | 702 | \\} |
| 948 | , &[_][]const u8{ | 703 | , &[_][]const u8{ |
| 949 | \\pub export fn foo1(_arg_a: c_uint) c_uint { | 704 | \\pub export fn for_none_bool() c_int { |
| 950 | \\ var a = _arg_a; | 705 | \\ var a: c_int = undefined; |
| 951 | \\ a +%= 1; | 706 | \\ var b: f32 = undefined; |
| 952 | \\ return a; | 707 | \\ var c: ?*c_void = undefined; |
| 953 | \\} | 708 | \\ while (a != 0) return 0; |
| 954 | \\pub export fn foo2(_arg_a: c_int) c_int { | 709 | \\ while (b != 0) return 1; |
| 955 | \\ var a = _arg_a; | 710 | \\ while (c != null) return 2; |
| 956 | \\ a += 1; | 711 | \\ return 3; |
| 957 | \\ return a; | ||
| 958 | \\} | 712 | \\} |
| 959 | }); | 713 | }); |
| 960 | 714 | ||
| 961 | cases.addC("shift right assign", | 715 | cases.addC_both("bitshift", |
| 962 | \\int log2(unsigned a) { | 716 | \\int foo(void) { |
| 963 | \\ int i = 0; | 717 | \\ return (1 << 2) >> 1; |
| 964 | \\ while (a > 0) { | ||
| 965 | \\ a >>= 1; | ||
| 966 | \\ } | ||
| 967 | \\ return i; | ||
| 968 | \\} | 718 | \\} |
| 969 | , &[_][]const u8{ | 719 | , &[_][]const u8{ |
| 970 | \\pub export fn log2(_arg_a: c_uint) c_int { | 720 | \\pub export fn foo() c_int { |
| 971 | \\ var a = _arg_a; | 721 | \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1); |
| 972 | \\ var i: c_int = 0; | ||
| 973 | \\ while (a > @as(c_uint, 0)) { | ||
| 974 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1); | ||
| 975 | \\ } | ||
| 976 | \\ return i; | ||
| 977 | \\} | 722 | \\} |
| 978 | }); | 723 | }); |
| 979 | 724 | ||
| 980 | cases.addC("if statement", | 725 | cases.addC_both("sizeof", |
| 981 | \\int max(int a, int b) { | 726 | \\#include <stddef.h> |
| 982 | \\ if (a < b) | 727 | \\size_t size_of(void) { |
| 983 | \\ return b; | 728 | \\ return sizeof(int); |
| 984 | \\ | ||
| 985 | \\ if (a < b) | ||
| 986 | \\ return b; | ||
| 987 | \\ else | ||
| 988 | \\ return a; | ||
| 989 | \\ | ||
| 990 | \\ if (a < b) ; else ; | ||
| 991 | \\} | 729 | \\} |
| 992 | , &[_][]const u8{ | 730 | , &[_][]const u8{ |
| 993 | \\pub export fn max(a: c_int, b: c_int) c_int { | 731 | \\pub export fn size_of() usize { |
| 994 | \\ if (a < b) return b; | 732 | \\ return @sizeOf(c_int); |
| 995 | \\ if (a < b) return b else return a; | ||
| 996 | \\ if (a < b) {} else {} | ||
| 997 | \\} | 733 | \\} |
| 998 | }); | 734 | }); |
| 999 | 735 | ||
| 1000 | cases.addC("==, !=", | 736 | cases.addC_both("normal deref", |
| 1001 | \\int max(int a, int b) { | 737 | \\void foo() { |
| 1002 | \\ if (a == b) | 738 | \\ int *x; |
| 1003 | \\ return a; | 739 | \\ *x = 1; |
| 1004 | \\ if (a != b) | ||
| 1005 | \\ return b; | ||
| 1006 | \\ return a; | ||
| 1007 | \\} | 740 | \\} |
| 1008 | , &[_][]const u8{ | 741 | , &[_][]const u8{ |
| 1009 | \\pub export fn max(a: c_int, b: c_int) c_int { | 742 | \\pub export fn foo() void { |
| 1010 | \\ if (a == b) return a; | 743 | \\ var x: [*c]c_int = undefined; |
| 1011 | \\ if (a != b) return b; | 744 | \\ x.?.* = 1; |
| 1012 | \\ return a; | ||
| 1013 | \\} | 745 | \\} |
| 1014 | }); | 746 | }); |
| 1015 | 747 | ||
| 1016 | cases.addC("bitwise binary operators", | 748 | cases.addC_both("address of operator", |
| 1017 | \\int max(int a, int b) { | 749 | \\int foo(void) { |
| 1018 | \\ return (a & b) ^ (a | b); | 750 | \\ int x = 1234; |
| 751 | \\ int *ptr = &x; | ||
| 752 | \\ return *ptr; | ||
| 1019 | \\} | 753 | \\} |
| 1020 | , &[_][]const u8{ | 754 | , &[_][]const u8{ |
| 1021 | \\pub export fn max(a: c_int, b: c_int) c_int { | 755 | \\pub export fn foo() c_int { |
| 1022 | \\ return (a & b) ^ (a | b); | 756 | \\ var x: c_int = 1234; |
| 757 | \\ var ptr: [*c]c_int = &x; | ||
| 758 | \\ return ptr.?.*; | ||
| 1023 | \\} | 759 | \\} |
| 1024 | }); | 760 | }); |
| 1025 | 761 | ||
| 1026 | cases.addC("logical and, logical or", | 762 | cases.addC_both("bin not", |
| 1027 | \\int max(int a, int b) { | 763 | \\int foo() { |
| 1028 | \\ if (a < b || a == b) | 764 | \\ int x; |
| 1029 | \\ return b; | 765 | \\ return ~x; |
| 1030 | \\ if (a >= b && a == b) | ||
| 1031 | \\ return a; | ||
| 1032 | \\ return a; | ||
| 1033 | \\} | 766 | \\} |
| 1034 | , &[_][]const u8{ | 767 | , &[_][]const u8{ |
| 1035 | \\pub export fn max(a: c_int, b: c_int) c_int { | 768 | \\pub export fn foo() c_int { |
| 1036 | \\ if ((a < b) or (a == b)) return b; | 769 | \\ var x: c_int = undefined; |
| 1037 | \\ if ((a >= b) and (a == b)) return a; | 770 | \\ return ~x; |
| 1038 | \\ return a; | ||
| 1039 | \\} | 771 | \\} |
| 1040 | }); | 772 | }); |
| 1041 | 773 | ||
| 1042 | cases.addC("logical and, logical or on none bool values", | 774 | cases.addC_both("bool not", |
| 1043 | \\int and_or_none_bool(int a, float b, void *c) { | 775 | \\int foo() { |
| 1044 | \\ if (a && b) return 0; | 776 | \\ int a; |
| 1045 | \\ if (b && c) return 1; | 777 | \\ float b; |
| 1046 | \\ if (a && c) return 2; | 778 | \\ void *c; |
| 1047 | \\ if (a || b) return 3; | 779 | \\ return !(a == 0); |
| 1048 | \\ if (b || c) return 4; | 780 | \\ return !a; |
| 1049 | \\ if (a || c) return 5; | 781 | \\ return !b; |
| 1050 | \\ return 6; | 782 | \\ return !c; |
| 1051 | \\} | 783 | \\} |
| 1052 | , &[_][]const u8{ | 784 | , &[_][]const u8{ |
| 1053 | \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | 785 | \\pub export fn foo() c_int { |
| 1054 | \\ if ((a != 0) and (b != 0)) return 0; | 786 | \\ var a: c_int = undefined; |
| 1055 | \\ if ((b != 0) and (c != null)) return 1; | 787 | \\ var b: f32 = undefined; |
| 1056 | \\ if ((a != 0) and (c != null)) return 2; | 788 | \\ var c: ?*c_void = undefined; |
| 1057 | \\ if ((a != 0) or (b != 0)) return 3; | 789 | \\ return !(a == 0); |
| 1058 | \\ if ((b != 0) or (c != null)) return 4; | 790 | \\ return !(a != 0); |
| 1059 | \\ if ((a != 0) or (c != null)) return 5; | 791 | \\ return !(b != 0); |
| 1060 | \\ return 6; | 792 | \\ return !(c != null); |
| 1061 | \\} | 793 | \\} |
| 1062 | }); | 794 | }); |
| 1063 | 795 | ||
| 1064 | cases.addC("assign", | 796 | cases.addC("__extension__ cast", |
| 1065 | \\int max(int a) { | 797 | \\int foo(void) { |
| 1066 | \\ int tmp; | 798 | \\ return __extension__ 1; |
| 1067 | \\ tmp = a; | ||
| 1068 | \\ a = tmp; | ||
| 1069 | \\} | 799 | \\} |
| 1070 | , &[_][]const u8{ | 800 | , &[_][]const u8{ |
| 1071 | \\pub export fn max(_arg_a: c_int) c_int { | 801 | \\pub export fn foo() c_int { |
| 1072 | \\ var a = _arg_a; | 802 | \\ return 1; |
| 1073 | \\ var tmp: c_int = undefined; | ||
| 1074 | \\ tmp = a; | ||
| 1075 | \\ a = tmp; | ||
| 1076 | \\} | 803 | \\} |
| 1077 | }); | 804 | }); |
| 1078 | 805 | ||
| 1079 | cases.addC("chaining assign", | 806 | if (builtin.os != builtin.Os.windows) { |
| 1080 | \\void max(int a) { | 807 | // sysv_abi not currently supported on windows |
| 1081 | \\ int b, c; | 808 | cases.add_both("Macro qualified functions", |
| 1082 | \\ c = b = a; | 809 | \\void __attribute__((sysv_abi)) foo(void); |
| 1083 | \\} | 810 | , &[_][]const u8{ |
| 1084 | , &[_][]const u8{ | 811 | \\pub extern fn foo() void; |
| 1085 | \\pub export fn max(a: c_int) void { | 812 | }); |
| 1086 | \\ var b: c_int = undefined; | 813 | } |
| 1087 | \\ var c: c_int = undefined; | ||
| 1088 | \\ c = (x: { | ||
| 1089 | \\ const _tmp = a; | ||
| 1090 | \\ b = _tmp; | ||
| 1091 | \\ break :x _tmp; | ||
| 1092 | \\ }); | ||
| 1093 | \\} | ||
| 1094 | }); | ||
| 1095 | 814 | ||
| 1096 | cases.addC("shift right assign with a fixed size type", | 815 | /////////////// Cases that pass for only stage2 //////////////// |
| 1097 | \\#include <stdint.h> | 816 | |
| 1098 | \\int log2(uint32_t a) { | 817 | cases.add_2("Parameterless function prototypes", |
| 1099 | \\ int i = 0; | 818 | \\void a() {} |
| 1100 | \\ while (a > 0) { | 819 | \\void b(void) {} |
| 1101 | \\ a >>= 1; | 820 | \\void c(); |
| 1102 | \\ } | 821 | \\void d(void); |
| 1103 | \\ return i; | ||
| 1104 | \\} | ||
| 1105 | , &[_][]const u8{ | 822 | , &[_][]const u8{ |
| 1106 | \\pub export fn log2(_arg_a: u32) c_int { | 823 | \\pub export fn a() void {} |
| 1107 | \\ var a = _arg_a; | 824 | \\pub export fn b() void {} |
| 1108 | \\ var i: c_int = 0; | 825 | \\pub extern fn c(...) void; |
| 1109 | \\ while (a > @as(c_uint, 0)) { | 826 | \\pub extern fn d() void; |
| 1110 | \\ a >>= @as(u5, 1); | ||
| 1111 | \\ } | ||
| 1112 | \\ return i; | ||
| 1113 | \\} | ||
| 1114 | }); | 827 | }); |
| 1115 | 828 | ||
| 1116 | cases.add("anonymous enum", | 829 | cases.add_2("variable declarations", |
| 1117 | \\enum { | 830 | \\extern char arr0[] = "hello"; |
| 1118 | \\ One, | 831 | \\static char arr1[] = "hello"; |
| 1119 | \\ Two, | 832 | \\char arr2[] = "hello"; |
| 1120 | \\}; | ||
| 1121 | , &[_][]const u8{ | 833 | , &[_][]const u8{ |
| 1122 | \\pub const One = 0; | 834 | \\pub extern var arr0: [*c]u8 = "hello"; |
| 1123 | \\pub const Two = 1; | 835 | \\pub var arr1: [*c]u8 = "hello"; |
| 836 | \\pub export var arr2: [*c]u8 = "hello"; | ||
| 1124 | }); | 837 | }); |
| 1125 | 838 | ||
| 1126 | cases.addC("function call", | 839 | cases.add_2("array initializer expr", |
| 1127 | \\static void bar(void) { } | 840 | \\static void foo(void){ |
| 1128 | \\static int baz(void) { return 0; } | 841 | \\ char arr[10] ={1}; |
| 1129 | \\void foo(void) { | 842 | \\ char *arr1[10] ={0}; |
| 1130 | \\ bar(); | ||
| 1131 | \\ baz(); | ||
| 1132 | \\} | 843 | \\} |
| 1133 | , &[_][]const u8{ | 844 | , &[_][]const u8{ |
| 1134 | \\pub fn bar() void {} | 845 | \\pub fn foo() void { |
| 1135 | \\pub fn baz() c_int { | 846 | \\ var arr: [10]u8 = .{ |
| 1136 | \\ return 0; | 847 | \\ @as(u8, 1), |
| 1137 | \\} | 848 | \\ } ++ .{0} ** 9; |
| 1138 | \\pub export fn foo() void { | 849 | \\ var arr1: [10][*c]u8 = .{ |
| 1139 | \\ bar(); | 850 | \\ null, |
| 1140 | \\ _ = baz(); | 851 | \\ } ++ .{null} ** 9; |
| 1141 | \\} | 852 | \\} |
| 1142 | }); | 853 | }); |
| 1143 | 854 | ||
| 1144 | cases.addC("field access expression", | 855 | cases.add_2("enums", |
| 1145 | \\struct Foo { | 856 | \\typedef enum { |
| 1146 | \\ int field; | 857 | \\ a, |
| 858 | \\ b, | ||
| 859 | \\ c, | ||
| 860 | \\} d; | ||
| 861 | \\enum { | ||
| 862 | \\ e, | ||
| 863 | \\ f = 4, | ||
| 864 | \\ g, | ||
| 865 | \\} h = e; | ||
| 866 | \\struct Baz { | ||
| 867 | \\ enum { | ||
| 868 | \\ i, | ||
| 869 | \\ j, | ||
| 870 | \\ k, | ||
| 871 | \\ } l; | ||
| 872 | \\ d m; | ||
| 873 | \\}; | ||
| 874 | \\enum i { | ||
| 875 | \\ n, | ||
| 876 | \\ o, | ||
| 877 | \\ p, | ||
| 1147 | \\}; | 878 | \\}; |
| 1148 | \\int read_field(struct Foo *foo) { | ||
| 1149 | \\ return foo->field; | ||
| 1150 | \\} | ||
| 1151 | , &[_][]const u8{ | 879 | , &[_][]const u8{ |
| 1152 | \\pub const struct_Foo = extern struct { | 880 | \\pub const a = 0; |
| 1153 | \\ field: c_int, | 881 | \\pub const b = 1; |
| 882 | \\pub const c = 2; | ||
| 883 | \\const enum_unnamed_1 = extern enum { | ||
| 884 | \\ a, | ||
| 885 | \\ b, | ||
| 886 | \\ c, | ||
| 1154 | \\}; | 887 | \\}; |
| 1155 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { | 888 | \\pub const d = enum_unnamed_1; |
| 1156 | \\ return foo.*.field; | 889 | \\pub const e = 0; |
| 1157 | \\} | 890 | \\pub const f = 4; |
| 891 | \\pub const g = 5; | ||
| 892 | \\const enum_unnamed_2 = extern enum { | ||
| 893 | \\ e = 0, | ||
| 894 | \\ f = 4, | ||
| 895 | \\ g = 5, | ||
| 896 | \\}; | ||
| 897 | \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e); | ||
| 898 | \\pub const i = 0; | ||
| 899 | \\pub const j = 1; | ||
| 900 | \\pub const k = 2; | ||
| 901 | \\const enum_unnamed_3 = extern enum { | ||
| 902 | \\ i, | ||
| 903 | \\ j, | ||
| 904 | \\ k, | ||
| 905 | \\}; | ||
| 906 | \\pub const struct_Baz = extern struct { | ||
| 907 | \\ l: enum_unnamed_3, | ||
| 908 | \\ m: d, | ||
| 909 | \\}; | ||
| 910 | \\pub const n = 0; | ||
| 911 | \\pub const o = 1; | ||
| 912 | \\pub const p = 2; | ||
| 913 | \\pub const enum_i = extern enum { | ||
| 914 | \\ n, | ||
| 915 | \\ o, | ||
| 916 | \\ p, | ||
| 917 | \\}; | ||
| 918 | , | ||
| 919 | \\pub const Baz = struct_Baz; | ||
| 1158 | }); | 920 | }); |
| 1159 | 921 | ||
| 1160 | cases.addC("null statements", | 922 | cases.add_2("#define a char literal", |
| 1161 | \\void foo(void) { | 923 | \\#define A_CHAR 'a' |
| 1162 | \\ ;;;;; | ||
| 1163 | \\} | ||
| 1164 | , &[_][]const u8{ | 924 | , &[_][]const u8{ |
| 1165 | \\pub export fn foo() void { | 925 | \\pub const A_CHAR = 'a'; |
| 1166 | \\ {} | ||
| 1167 | \\ {} | ||
| 1168 | \\ {} | ||
| 1169 | \\ {} | ||
| 1170 | \\ {} | ||
| 1171 | \\} | ||
| 1172 | }); | 926 | }); |
| 1173 | 927 | ||
| 1174 | cases.add("undefined array global", | 928 | cases.add_2("comment after integer literal", |
| 1175 | \\int array[100]; | 929 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1176 | , &[_][]const u8{ | 930 | , &[_][]const u8{ |
| 1177 | \\pub var array: [100]c_int = undefined; | 931 | \\pub const SDL_INIT_VIDEO = 0x00000020; |
| 1178 | }); | 932 | }); |
| 1179 | 933 | ||
| 1180 | cases.addC("array access", | 934 | cases.add_2("u integer suffix after hex literal", |
| 1181 | \\int array[100]; | 935 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1182 | \\int foo(int index) { | ||
| 1183 | \\ return array[index]; | ||
| 1184 | \\} | ||
| 1185 | , &[_][]const u8{ | 936 | , &[_][]const u8{ |
| 1186 | \\pub var array: [100]c_int = undefined; | 937 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 0x00000020); |
| 1187 | \\pub export fn foo(index: c_int) c_int { | ||
| 1188 | \\ return array[index]; | ||
| 1189 | \\} | ||
| 1190 | }); | 938 | }); |
| 1191 | 939 | ||
| 1192 | cases.addC("c style cast", | 940 | cases.add_2("l integer suffix after hex literal", |
| 1193 | \\int float_to_int(float a) { | 941 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1194 | \\ return (int)a; | ||
| 1195 | \\} | ||
| 1196 | , &[_][]const u8{ | 942 | , &[_][]const u8{ |
| 1197 | \\pub export fn float_to_int(a: f32) c_int { | 943 | \\pub const SDL_INIT_VIDEO = @as(c_long, 0x00000020); |
| 1198 | \\ return @as(c_int, a); | ||
| 1199 | \\} | ||
| 1200 | }); | 944 | }); |
| 1201 | 945 | ||
| 1202 | cases.addC("void cast", | 946 | cases.add_2("ul integer suffix after hex literal", |
| 1203 | \\void foo(int a) { | 947 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1204 | \\ (void) a; | ||
| 1205 | \\} | ||
| 1206 | , &[_][]const u8{ | 948 | , &[_][]const u8{ |
| 1207 | \\pub export fn foo(a: c_int) void { | 949 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); |
| 1208 | \\ _ = a; | ||
| 1209 | \\} | ||
| 1210 | }); | 950 | }); |
| 1211 | 951 | ||
| 1212 | cases.addC("implicit cast to void *", | 952 | cases.add_2("lu integer suffix after hex literal", |
| 1213 | \\void *foo(unsigned short *x) { | 953 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1214 | \\ return x; | ||
| 1215 | \\} | ||
| 1216 | , &[_][]const u8{ | 954 | , &[_][]const u8{ |
| 1217 | \\pub export fn foo(x: [*c]c_ushort) ?*c_void { | 955 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 0x00000020); |
| 1218 | \\ return @ptrCast(?*c_void, x); | ||
| 1219 | \\} | ||
| 1220 | }); | 956 | }); |
| 1221 | 957 | ||
| 1222 | cases.addC("sizeof", | 958 | cases.add_2("ll integer suffix after hex literal", |
| 1223 | \\#include <stddef.h> | 959 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1224 | \\size_t size_of(void) { | ||
| 1225 | \\ return sizeof(int); | ||
| 1226 | \\} | ||
| 1227 | , &[_][]const u8{ | 960 | , &[_][]const u8{ |
| 1228 | \\pub export fn size_of() usize { | 961 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 0x00000020); |
| 1229 | \\ return @sizeOf(c_int); | ||
| 1230 | \\} | ||
| 1231 | }); | 962 | }); |
| 1232 | 963 | ||
| 1233 | cases.addC("null pointer implicit cast", | 964 | cases.add_2("ull integer suffix after hex literal", |
| 1234 | \\int* foo(void) { | 965 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1235 | \\ return 0; | ||
| 1236 | \\} | ||
| 1237 | , &[_][]const u8{ | 966 | , &[_][]const u8{ |
| 1238 | \\pub export fn foo() [*c]c_int { | 967 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); |
| 1239 | \\ return null; | ||
| 1240 | \\} | ||
| 1241 | }); | 968 | }); |
| 1242 | 969 | ||
| 1243 | cases.addC("comma operator", | 970 | cases.add_2("llu integer suffix after hex literal", |
| 1244 | \\int foo(void) { | 971 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ |
| 1245 | \\ return 1, 2; | ||
| 1246 | \\} | ||
| 1247 | , &[_][]const u8{ | 972 | , &[_][]const u8{ |
| 1248 | \\pub export fn foo() c_int { | 973 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 0x00000020); |
| 1249 | \\ return x: { | ||
| 1250 | \\ _ = 1; | ||
| 1251 | \\ break :x 2; | ||
| 1252 | \\ }; | ||
| 1253 | \\} | ||
| 1254 | }); | 974 | }); |
| 1255 | 975 | ||
| 1256 | cases.addC("statement expression", | 976 | cases.add_2("generate inline func for #define global extern fn", |
| 1257 | \\int foo(void) { | 977 | \\extern void (*fn_ptr)(void); |
| 1258 | \\ return ({ | 978 | \\#define foo fn_ptr |
| 1259 | \\ int a = 1; | 979 | \\ |
| 1260 | \\ a; | 980 | \\extern char (*fn_ptr2)(int, float); |
| 1261 | \\ }); | 981 | \\#define bar fn_ptr2 |
| 1262 | \\} | ||
| 1263 | , &[_][]const u8{ | 982 | , &[_][]const u8{ |
| 1264 | \\pub export fn foo() c_int { | 983 | \\pub extern var fn_ptr: ?extern fn () void; |
| 1265 | \\ return x: { | 984 | , |
| 1266 | \\ var a: c_int = 1; | 985 | \\pub inline fn foo() void { |
| 1267 | \\ break :x a; | 986 | \\ return fn_ptr.?(); |
| 1268 | \\ }; | ||
| 1269 | \\} | 987 | \\} |
| 1270 | }); | 988 | , |
| 1271 | 989 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | |
| 1272 | cases.addC("__extension__ cast", | 990 | , |
| 1273 | \\int foo(void) { | 991 | \\pub inline fn bar(arg_1: c_int, arg_2: f32) u8 { |
| 1274 | \\ return __extension__ 1; | 992 | \\ return fn_ptr2.?(arg_1, arg_2); |
| 993 | \\} | ||
| 994 | }); | ||
| 995 | |||
| 996 | cases.add_2("macros with field targets", | ||
| 997 | \\typedef unsigned int GLbitfield; | ||
| 998 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | ||
| 999 | \\typedef void(*OpenGLProc)(void); | ||
| 1000 | \\union OpenGLProcs { | ||
| 1001 | \\ OpenGLProc ptr[1]; | ||
| 1002 | \\ struct { | ||
| 1003 | \\ PFNGLCLEARPROC Clear; | ||
| 1004 | \\ } gl; | ||
| 1005 | \\}; | ||
| 1006 | \\extern union OpenGLProcs glProcs; | ||
| 1007 | \\#define glClearUnion glProcs.gl.Clear | ||
| 1008 | \\#define glClearPFN PFNGLCLEARPROC | ||
| 1009 | , &[_][]const u8{ | ||
| 1010 | \\pub const GLbitfield = c_uint; | ||
| 1011 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | ||
| 1012 | \\pub const OpenGLProc = ?extern fn () void; | ||
| 1013 | \\const struct_unnamed_1 = extern struct { | ||
| 1014 | \\ Clear: PFNGLCLEARPROC, | ||
| 1015 | \\}; | ||
| 1016 | \\pub const union_OpenGLProcs = extern union { | ||
| 1017 | \\ ptr: [1]OpenGLProc, | ||
| 1018 | \\ gl: struct_unnamed_1, | ||
| 1019 | \\}; | ||
| 1020 | \\pub extern var glProcs: union_OpenGLProcs; | ||
| 1021 | , | ||
| 1022 | \\pub const glClearPFN = PFNGLCLEARPROC; | ||
| 1023 | , | ||
| 1024 | \\pub inline fn glClearUnion(arg_2: GLbitfield) void { | ||
| 1025 | \\ return glProcs.gl.Clear.?(arg_2); | ||
| 1026 | \\} | ||
| 1027 | , | ||
| 1028 | \\pub const OpenGLProcs = union_OpenGLProcs; | ||
| 1029 | }); | ||
| 1030 | |||
| 1031 | cases.add_2("macro pointer cast", | ||
| 1032 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | ||
| 1033 | , &[_][]const u8{ | ||
| 1034 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | ||
| 1035 | }); | ||
| 1036 | |||
| 1037 | cases.add_2("basic macro function", | ||
| 1038 | \\extern int c; | ||
| 1039 | \\#define BASIC(c) (c*2) | ||
| 1040 | , &[_][]const u8{ | ||
| 1041 | \\pub extern var c: c_int; | ||
| 1042 | , | ||
| 1043 | \\pub inline fn BASIC(c_1: var) @TypeOf(c_1 * 2) { | ||
| 1044 | \\ return c_1 * 2; | ||
| 1045 | \\} | ||
| 1046 | }); | ||
| 1047 | |||
| 1048 | cases.add_2("macro defines string literal with hex", | ||
| 1049 | \\#define FOO "aoeu\xab derp" | ||
| 1050 | \\#define FOO2 "aoeu\x0007a derp" | ||
| 1051 | \\#define FOO_CHAR '\xfF' | ||
| 1052 | , &[_][]const u8{ | ||
| 1053 | \\pub const FOO = "aoeu\xab derp"; | ||
| 1054 | , | ||
| 1055 | \\pub const FOO2 = "aoeu\x7a derp"; | ||
| 1056 | , | ||
| 1057 | \\pub const FOO_CHAR = '\xff'; | ||
| 1058 | }); | ||
| 1059 | |||
| 1060 | cases.add_2("variable aliasing", | ||
| 1061 | \\static long a = 2; | ||
| 1062 | \\static long b = 2; | ||
| 1063 | \\static int c = 4; | ||
| 1064 | \\void foo(char c) { | ||
| 1065 | \\ int a; | ||
| 1066 | \\ char b = 123; | ||
| 1067 | \\ b = (char) a; | ||
| 1068 | \\ { | ||
| 1069 | \\ int d = 5; | ||
| 1070 | \\ } | ||
| 1071 | \\ unsigned d = 440; | ||
| 1072 | \\} | ||
| 1073 | , &[_][]const u8{ | ||
| 1074 | \\pub var a: c_long = @as(c_long, 2); | ||
| 1075 | \\pub var b: c_long = @as(c_long, 2); | ||
| 1076 | \\pub var c: c_int = 4; | ||
| 1077 | \\pub export fn foo(_arg_c_1: u8) void { | ||
| 1078 | \\ var c_1 = _arg_c_1; | ||
| 1079 | \\ var a_2: c_int = undefined; | ||
| 1080 | \\ var b_3: u8 = @as(u8, 123); | ||
| 1081 | \\ b_3 = @as(u8, a_2); | ||
| 1082 | \\ { | ||
| 1083 | \\ var d: c_int = 5; | ||
| 1084 | \\ } | ||
| 1085 | \\ var d: c_uint = @as(c_uint, 440); | ||
| 1086 | \\} | ||
| 1087 | }); | ||
| 1088 | |||
| 1089 | cases.add_2("comma operator", | ||
| 1090 | \\int foo(char c) { | ||
| 1091 | \\ 2, 4; | ||
| 1092 | \\ return 2, 4, 6; | ||
| 1093 | \\} | ||
| 1094 | , &[_][]const u8{ | ||
| 1095 | \\pub export fn foo(_arg_c: u8) c_int { | ||
| 1096 | \\ var c = _arg_c; | ||
| 1097 | \\ _ = 2; | ||
| 1098 | \\ _ = 4; | ||
| 1099 | \\ _ = 2; | ||
| 1100 | \\ _ = 4; | ||
| 1101 | \\ return 6; | ||
| 1102 | \\} | ||
| 1103 | }); | ||
| 1104 | |||
| 1105 | cases.add_2("wors-case assign", | ||
| 1106 | \\int foo(char c) { | ||
| 1107 | \\ int a; | ||
| 1108 | \\ int b; | ||
| 1109 | \\ a = b = 2; | ||
| 1110 | \\} | ||
| 1111 | , &[_][]const u8{ | ||
| 1112 | \\pub export fn foo(_arg_c: u8) c_int { | ||
| 1113 | \\ var c = _arg_c; | ||
| 1114 | \\ var a: c_int = undefined; | ||
| 1115 | \\ var b: c_int = undefined; | ||
| 1116 | \\ a = blk: { | ||
| 1117 | \\ const _tmp_1 = 2; | ||
| 1118 | \\ b = _tmp_1; | ||
| 1119 | \\ break :blk _tmp_1; | ||
| 1120 | \\ }; | ||
| 1121 | \\} | ||
| 1122 | }); | ||
| 1123 | |||
| 1124 | cases.add_2("if statements", | ||
| 1125 | \\int foo(char c) { | ||
| 1126 | \\ if (2) { | ||
| 1127 | \\ int a = 2; | ||
| 1128 | \\ } | ||
| 1129 | \\ if (2, 5) { | ||
| 1130 | \\ int a = 2; | ||
| 1131 | \\ } | ||
| 1132 | \\} | ||
| 1133 | , &[_][]const u8{ | ||
| 1134 | \\pub export fn foo(_arg_c: u8) c_int { | ||
| 1135 | \\ var c = _arg_c; | ||
| 1136 | \\ if (2 != 0) { | ||
| 1137 | \\ var a: c_int = 2; | ||
| 1138 | \\ } | ||
| 1139 | \\ if ((blk: { | ||
| 1140 | \\ _ = 2; | ||
| 1141 | \\ break :blk 5; | ||
| 1142 | \\ }) != 0) { | ||
| 1143 | \\ var a: c_int = 2; | ||
| 1144 | \\ } | ||
| 1145 | \\} | ||
| 1146 | }); | ||
| 1147 | |||
| 1148 | cases.add_2("while loops", | ||
| 1149 | \\int foo() { | ||
| 1150 | \\ int a = 5; | ||
| 1151 | \\ while (2) | ||
| 1152 | \\ a = 2; | ||
| 1153 | \\ while (4) { | ||
| 1154 | \\ int a = 4; | ||
| 1155 | \\ a = 9; | ||
| 1156 | \\ return 6, a; | ||
| 1157 | \\ } | ||
| 1158 | \\ do { | ||
| 1159 | \\ int a = 2; | ||
| 1160 | \\ a = 12; | ||
| 1161 | \\ } while (4); | ||
| 1162 | \\ do | ||
| 1163 | \\ a = 7; | ||
| 1164 | \\ while (4); | ||
| 1275 | \\} | 1165 | \\} |
| 1276 | , &[_][]const u8{ | 1166 | , &[_][]const u8{ |
| 1277 | \\pub export fn foo() c_int { | 1167 | \\pub export fn foo() c_int { |
| 1278 | \\ return 1; | 1168 | \\ var a: c_int = 5; |
| 1169 | \\ while (2 != 0) a = 2; | ||
| 1170 | \\ while (4 != 0) { | ||
| 1171 | \\ var a: c_int = 4; | ||
| 1172 | \\ a = 9; | ||
| 1173 | \\ _ = 6; | ||
| 1174 | \\ return a; | ||
| 1175 | \\ } | ||
| 1176 | \\ while (true) { | ||
| 1177 | \\ var a: c_int = 2; | ||
| 1178 | \\ a = 12; | ||
| 1179 | \\ if (!(4 != 0)) break; | ||
| 1180 | \\ } | ||
| 1181 | \\ while (true) { | ||
| 1182 | \\ a = 7; | ||
| 1183 | \\ if (!(4 != 0)) break; | ||
| 1184 | \\ } | ||
| 1279 | \\} | 1185 | \\} |
| 1280 | }); | 1186 | }); |
| 1281 | 1187 | ||
| 1282 | cases.addC("bitshift", | 1188 | cases.add_2("for loops", |
| 1283 | \\int foo(void) { | 1189 | \\int foo() { |
| 1284 | \\ return (1 << 2) >> 1; | 1190 | \\ for (int i = 2, b = 4; i + 2; i = 2) { |
| 1191 | \\ int a = 2; | ||
| 1192 | \\ a = 6, 5, 7; | ||
| 1193 | \\ } | ||
| 1194 | \\ char i = 2; | ||
| 1285 | \\} | 1195 | \\} |
| 1286 | , &[_][]const u8{ | 1196 | , &[_][]const u8{ |
| 1287 | \\pub export fn foo() c_int { | 1197 | \\pub export fn foo() c_int { |
| 1288 | \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1); | 1198 | \\ { |
| 1199 | \\ var i: c_int = 2; | ||
| 1200 | \\ var b: c_int = 4; | ||
| 1201 | \\ while ((i + 2) != 0) : (i = 2) { | ||
| 1202 | \\ var a: c_int = 2; | ||
| 1203 | \\ a = 6; | ||
| 1204 | \\ _ = 5; | ||
| 1205 | \\ _ = 7; | ||
| 1206 | \\ } | ||
| 1207 | \\ } | ||
| 1208 | \\ var i: u8 = @as(u8, 2); | ||
| 1289 | \\} | 1209 | \\} |
| 1290 | }); | 1210 | }); |
| 1291 | 1211 | ||
| 1292 | cases.addC("compound assignment operators", | 1212 | cases.add_2("shadowing primitive types", |
| 1293 | \\void foo(void) { | 1213 | \\unsigned anyerror = 2; |
| 1294 | \\ int a = 0; | 1214 | , &[_][]const u8{ |
| 1295 | \\ a += (a += 1); | 1215 | \\pub export var _anyerror: c_uint = @as(c_uint, 2); |
| 1296 | \\ a -= (a -= 1); | 1216 | }); |
| 1297 | \\ a *= (a *= 1); | 1217 | |
| 1298 | \\ a &= (a &= 1); | 1218 | cases.add_2("floats", |
| 1299 | \\ a |= (a |= 1); | 1219 | \\float a = 3.1415; |
| 1300 | \\ a ^= (a ^= 1); | 1220 | \\double b = 3.1415; |
| 1301 | \\ a >>= (a >>= 1); | 1221 | \\int c = 3.1415; |
| 1302 | \\ a <<= (a <<= 1); | 1222 | \\double d = 3; |
| 1223 | , &[_][]const u8{ | ||
| 1224 | \\pub export var a: f32 = @floatCast(f32, 3.1415); | ||
| 1225 | \\pub export var b: f64 = 3.1415; | ||
| 1226 | \\pub export var c: c_int = @floatToInt(c_int, 3.1415); | ||
| 1227 | \\pub export var d: f64 = @intToFloat(f64, 3); | ||
| 1228 | }); | ||
| 1229 | |||
| 1230 | cases.add_2("conditional operator", | ||
| 1231 | \\int bar(void) { | ||
| 1232 | \\ if (2 ? 5 : 5 ? 4 : 6) 2; | ||
| 1233 | \\ return 2 ? 5 : 5 ? 4 : 6; | ||
| 1303 | \\} | 1234 | \\} |
| 1304 | , &[_][]const u8{ | 1235 | , &[_][]const u8{ |
| 1305 | \\pub export fn foo() void { | 1236 | \\pub export fn bar() c_int { |
| 1306 | \\ var a: c_int = 0; | 1237 | \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2; |
| 1307 | \\ a += (x: { | 1238 | \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6; |
| 1308 | \\ const _ref = &a; | 1239 | \\} |
| 1309 | \\ _ref.* = (_ref.* + 1); | 1240 | }); |
| 1310 | \\ break :x _ref.*; | 1241 | |
| 1311 | \\ }); | 1242 | cases.add_2("switch on int", |
| 1312 | \\ a -= (x: { | 1243 | \\int switch_fn(int i) { |
| 1313 | \\ const _ref = &a; | 1244 | \\ int res = 0; |
| 1314 | \\ _ref.* = (_ref.* - 1); | 1245 | \\ switch (i) { |
| 1315 | \\ break :x _ref.*; | 1246 | \\ case 0: |
| 1316 | \\ }); | 1247 | \\ res = 1; |
| 1317 | \\ a *= (x: { | 1248 | \\ case 1 ... 3: |
| 1318 | \\ const _ref = &a; | 1249 | \\ res = 2; |
| 1319 | \\ _ref.* = (_ref.* * 1); | 1250 | \\ default: |
| 1320 | \\ break :x _ref.*; | 1251 | \\ res = 3 * i; |
| 1321 | \\ }); | 1252 | \\ break; |
| 1322 | \\ a &= (x: { | 1253 | \\ case 4: |
| 1323 | \\ const _ref = &a; | 1254 | \\ res = 5; |
| 1324 | \\ _ref.* = (_ref.* & 1); | 1255 | \\ } |
| 1325 | \\ break :x _ref.*; | 1256 | \\} |
| 1326 | \\ }); | 1257 | , &[_][]const u8{ |
| 1327 | \\ a |= (x: { | 1258 | \\pub export fn switch_fn(_arg_i: c_int) c_int { |
| 1328 | \\ const _ref = &a; | 1259 | \\ var i = _arg_i; |
| 1329 | \\ _ref.* = (_ref.* | 1); | 1260 | \\ var res: c_int = 0; |
| 1330 | \\ break :x _ref.*; | 1261 | \\ __switch: { |
| 1331 | \\ }); | 1262 | \\ __case_2: { |
| 1332 | \\ a ^= (x: { | 1263 | \\ __default: { |
| 1333 | \\ const _ref = &a; | 1264 | \\ __case_1: { |
| 1334 | \\ _ref.* = (_ref.* ^ 1); | 1265 | \\ __case_0: { |
| 1335 | \\ break :x _ref.*; | 1266 | \\ switch (i) { |
| 1336 | \\ }); | 1267 | \\ 0 => break :__case_0, |
| 1337 | \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: { | 1268 | \\ 1...3 => break :__case_1, |
| 1338 | \\ const _ref = &a; | 1269 | \\ else => break :__default, |
| 1339 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1)); | 1270 | \\ 4 => break :__case_2, |
| 1340 | \\ break :x _ref.*; | 1271 | \\ } |
| 1341 | \\ })); | 1272 | \\ } |
| 1342 | \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: { | 1273 | \\ res = 1; |
| 1343 | \\ const _ref = &a; | 1274 | \\ } |
| 1344 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1)); | 1275 | \\ res = 2; |
| 1345 | \\ break :x _ref.*; | 1276 | \\ } |
| 1346 | \\ })); | 1277 | \\ res = (3 * i); |
| 1278 | \\ break :__switch; | ||
| 1279 | \\ } | ||
| 1280 | \\ res = 5; | ||
| 1281 | \\ } | ||
| 1282 | \\} | ||
| 1283 | }); | ||
| 1284 | |||
| 1285 | cases.add_2("type referenced struct", | ||
| 1286 | \\struct Foo { | ||
| 1287 | \\ struct Bar{ | ||
| 1288 | \\ int b; | ||
| 1289 | \\ }; | ||
| 1290 | \\ struct Bar c; | ||
| 1291 | \\}; | ||
| 1292 | , &[_][]const u8{ | ||
| 1293 | \\pub const struct_Bar = extern struct { | ||
| 1294 | \\ b: c_int, | ||
| 1295 | \\}; | ||
| 1296 | \\pub const struct_Foo = extern struct { | ||
| 1297 | \\ c: struct_Bar, | ||
| 1298 | \\}; | ||
| 1299 | }); | ||
| 1300 | |||
| 1301 | cases.add_2("undefined array global", | ||
| 1302 | \\int array[100] = {}; | ||
| 1303 | , &[_][]const u8{ | ||
| 1304 | \\pub export var array: [100]c_int = .{0} ** 100; | ||
| 1305 | }); | ||
| 1306 | |||
| 1307 | cases.add_2("restrict -> noalias", | ||
| 1308 | \\void foo(void *restrict bar, void *restrict); | ||
| 1309 | , &[_][]const u8{ | ||
| 1310 | \\pub extern fn foo(noalias bar: ?*c_void, noalias ?*c_void) void; | ||
| 1311 | }); | ||
| 1312 | |||
| 1313 | cases.add_2("assign", | ||
| 1314 | \\int max(int a) { | ||
| 1315 | \\ int tmp; | ||
| 1316 | \\ tmp = a; | ||
| 1317 | \\ a = tmp; | ||
| 1347 | \\} | 1318 | \\} |
| 1319 | , &[_][]const u8{ | ||
| 1320 | \\pub export fn max(_arg_a: c_int) c_int { | ||
| 1321 | \\ var a = _arg_a; | ||
| 1322 | \\ var tmp: c_int = undefined; | ||
| 1323 | \\ tmp = a; | ||
| 1324 | \\ a = tmp; | ||
| 1325 | \\} | ||
| 1326 | }); | ||
| 1327 | |||
| 1328 | cases.add_2("chaining assign", | ||
| 1329 | \\void max(int a) { | ||
| 1330 | \\ int b, c; | ||
| 1331 | \\ c = b = a; | ||
| 1332 | \\} | ||
| 1333 | , &[_][]const u8{ | ||
| 1334 | \\pub export fn max(_arg_a: c_int) void { | ||
| 1335 | \\ var a = _arg_a; | ||
| 1336 | \\ var b: c_int = undefined; | ||
| 1337 | \\ var c: c_int = undefined; | ||
| 1338 | \\ c = blk: { | ||
| 1339 | \\ const _tmp_1 = a; | ||
| 1340 | \\ b = _tmp_1; | ||
| 1341 | \\ break :blk _tmp_1; | ||
| 1342 | \\ }; | ||
| 1343 | \\} | ||
| 1344 | }); | ||
| 1345 | |||
| 1346 | cases.add_2("anonymous enum", | ||
| 1347 | \\enum { | ||
| 1348 | \\ One, | ||
| 1349 | \\ Two, | ||
| 1350 | \\}; | ||
| 1351 | , &[_][]const u8{ | ||
| 1352 | \\pub const One = 0; | ||
| 1353 | \\pub const Two = 1; | ||
| 1354 | \\const enum_unnamed_1 = extern enum { | ||
| 1355 | \\ One, | ||
| 1356 | \\ Two, | ||
| 1357 | \\}; | ||
| 1358 | }); | ||
| 1359 | |||
| 1360 | cases.add_2("c style cast", | ||
| 1361 | \\int float_to_int(float a) { | ||
| 1362 | \\ return (int)a; | ||
| 1363 | \\} | ||
| 1364 | , &[_][]const u8{ | ||
| 1365 | \\pub export fn float_to_int(_arg_a: f32) c_int { | ||
| 1366 | \\ var a = _arg_a; | ||
| 1367 | \\ return @floatToInt(c_int, a); | ||
| 1368 | \\} | ||
| 1369 | }); | ||
| 1370 | |||
| 1371 | cases.add_2("escape sequences", | ||
| 1372 | \\const char *escapes() { | ||
| 1373 | \\char a = '\'', | ||
| 1374 | \\ b = '\\', | ||
| 1375 | \\ c = '\a', | ||
| 1376 | \\ d = '\b', | ||
| 1377 | \\ e = '\f', | ||
| 1378 | \\ f = '\n', | ||
| 1379 | \\ g = '\r', | ||
| 1380 | \\ h = '\t', | ||
| 1381 | \\ i = '\v', | ||
| 1382 | \\ j = '\0', | ||
| 1383 | \\ k = '\"'; | ||
| 1384 | \\ return "\'\\\a\b\f\n\r\t\v\0\""; | ||
| 1385 | \\} | ||
| 1386 | \\ | ||
| 1387 | , &[_][]const u8{ | ||
| 1388 | \\pub export fn escapes() [*c]const u8 { | ||
| 1389 | \\ var a: u8 = @as(u8, '\''); | ||
| 1390 | \\ var b: u8 = @as(u8, '\\'); | ||
| 1391 | \\ var c: u8 = @as(u8, '\x07'); | ||
| 1392 | \\ var d: u8 = @as(u8, '\x08'); | ||
| 1393 | \\ var e: u8 = @as(u8, '\x0c'); | ||
| 1394 | \\ var f: u8 = @as(u8, '\n'); | ||
| 1395 | \\ var g: u8 = @as(u8, '\r'); | ||
| 1396 | \\ var h: u8 = @as(u8, '\t'); | ||
| 1397 | \\ var i: u8 = @as(u8, '\x0b'); | ||
| 1398 | \\ var j: u8 = @as(u8, '\x00'); | ||
| 1399 | \\ var k: u8 = @as(u8, '\"'); | ||
| 1400 | \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; | ||
| 1401 | \\} | ||
| 1402 | }); | ||
| 1403 | |||
| 1404 | cases.add_2("do loop", | ||
| 1405 | \\void foo(void) { | ||
| 1406 | \\ int a = 2; | ||
| 1407 | \\ do { | ||
| 1408 | \\ a = a - 1; | ||
| 1409 | \\ } while (a); | ||
| 1410 | \\ | ||
| 1411 | \\ int b = 2; | ||
| 1412 | \\ do | ||
| 1413 | \\ b = b -1; | ||
| 1414 | \\ while (b); | ||
| 1415 | \\} | ||
| 1416 | , &[_][]const u8{ | ||
| 1417 | \\pub export fn foo() void { | ||
| 1418 | \\ var a: c_int = 2; | ||
| 1419 | \\ while (true) { | ||
| 1420 | \\ a = (a - 1); | ||
| 1421 | \\ if (!(a != 0)) break; | ||
| 1422 | \\ } | ||
| 1423 | \\ var b: c_int = 2; | ||
| 1424 | \\ while (true) { | ||
| 1425 | \\ b = (b - 1); | ||
| 1426 | \\ if (!(b != 0)) break; | ||
| 1427 | \\ } | ||
| 1428 | \\} | ||
| 1429 | }); | ||
| 1430 | |||
| 1431 | cases.add_2("logical and, logical or, on non-bool values, extra parens", | ||
| 1432 | \\enum Foo { | ||
| 1433 | \\ FooA, | ||
| 1434 | \\ FooB, | ||
| 1435 | \\ FooC, | ||
| 1436 | \\}; | ||
| 1437 | \\typedef int SomeTypedef; | ||
| 1438 | \\int and_or_non_bool(int a, float b, void *c) { | ||
| 1439 | \\ enum Foo d = FooA; | ||
| 1440 | \\ int e = (a && b); | ||
| 1441 | \\ int f = (b && c); | ||
| 1442 | \\ int g = (a && c); | ||
| 1443 | \\ int h = (a || b); | ||
| 1444 | \\ int i = (b || c); | ||
| 1445 | \\ int j = (a || c); | ||
| 1446 | \\ int k = (a || d); | ||
| 1447 | \\ int l = (d && b); | ||
| 1448 | \\ int m = (c || d); | ||
| 1449 | \\ SomeTypedef td = 44; | ||
| 1450 | \\ int o = (td || b); | ||
| 1451 | \\ int p = (c && td); | ||
| 1452 | \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p); | ||
| 1453 | \\} | ||
| 1454 | , &[_][]const u8{ | ||
| 1455 | \\pub const enum_Foo = extern enum { | ||
| 1456 | \\ A, | ||
| 1457 | \\ B, | ||
| 1458 | \\ C, | ||
| 1459 | \\}; | ||
| 1460 | \\pub const SomeTypedef = c_int; | ||
| 1461 | \\pub export fn and_or_non_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void) c_int { | ||
| 1462 | \\ var a = _arg_a; | ||
| 1463 | \\ var b = _arg_b; | ||
| 1464 | \\ var c = _arg_c; | ||
| 1465 | \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA); | ||
| 1466 | \\ var e: c_int = @boolToInt(((a != 0) and (b != 0))); | ||
| 1467 | \\ var f: c_int = @boolToInt(((b != 0) and (c != null))); | ||
| 1468 | \\ var g: c_int = @boolToInt(((a != 0) and (c != null))); | ||
| 1469 | \\ var h: c_int = @boolToInt(((a != 0) or (b != 0))); | ||
| 1470 | \\ var i: c_int = @boolToInt(((b != 0) or (c != null))); | ||
| 1471 | \\ var j: c_int = @boolToInt(((a != 0) or (c != null))); | ||
| 1472 | \\ var k: c_int = @boolToInt(((a != 0) or (@enumToInt(d) != 0))); | ||
| 1473 | \\ var l: c_int = @boolToInt(((@enumToInt(d) != 0) and (b != 0))); | ||
| 1474 | \\ var m: c_int = @boolToInt(((c != null) or (@enumToInt(d) != 0))); | ||
| 1475 | \\ var td: SomeTypedef = 44; | ||
| 1476 | \\ var o: c_int = @boolToInt(((td != 0) or (b != 0))); | ||
| 1477 | \\ var p: c_int = @boolToInt(((c != null) and (td != 0))); | ||
| 1478 | \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p); | ||
| 1479 | \\} | ||
| 1480 | , | ||
| 1481 | \\pub const Foo = enum_Foo; | ||
| 1482 | }); | ||
| 1483 | |||
| 1484 | cases.add_2("qualified struct and enum", | ||
| 1485 | \\struct Foo { | ||
| 1486 | \\ int x; | ||
| 1487 | \\ int y; | ||
| 1488 | \\}; | ||
| 1489 | \\enum Bar { | ||
| 1490 | \\ BarA, | ||
| 1491 | \\ BarB, | ||
| 1492 | \\}; | ||
| 1493 | \\void func(struct Foo *a, enum Bar **b); | ||
| 1494 | , &[_][]const u8{ | ||
| 1495 | \\pub const struct_Foo = extern struct { | ||
| 1496 | \\ x: c_int, | ||
| 1497 | \\ y: c_int, | ||
| 1498 | \\}; | ||
| 1499 | , | ||
| 1500 | \\pub const enum_Bar = extern enum { | ||
| 1501 | \\ A, | ||
| 1502 | \\ B, | ||
| 1503 | \\}; | ||
| 1504 | \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void; | ||
| 1505 | , | ||
| 1506 | \\pub const Foo = struct_Foo; | ||
| 1507 | \\pub const Bar = enum_Bar; | ||
| 1508 | }); | ||
| 1509 | |||
| 1510 | cases.add_2("bitwise binary operators, simpler parens", | ||
| 1511 | \\int max(int a, int b) { | ||
| 1512 | \\ return (a & b) ^ (a | b); | ||
| 1513 | \\} | ||
| 1514 | , &[_][]const u8{ | ||
| 1515 | \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { | ||
| 1516 | \\ var a = _arg_a; | ||
| 1517 | \\ var b = _arg_b; | ||
| 1518 | \\ return ((a & b) ^ (a | b)); | ||
| 1519 | \\} | ||
| 1520 | }); | ||
| 1521 | |||
| 1522 | cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. | ||
| 1523 | \\int test_comparisons(int a, int b) { | ||
| 1524 | \\ int c = (a < b); | ||
| 1525 | \\ int d = (a > b); | ||
| 1526 | \\ int e = (a <= b); | ||
| 1527 | \\ int f = (a >= b); | ||
| 1528 | \\ int g = (c < d); | ||
| 1529 | \\ int h = (e < f); | ||
| 1530 | \\ int i = (g < h); | ||
| 1531 | \\ return i; | ||
| 1532 | \\} | ||
| 1533 | , &[_][]const u8{ | ||
| 1534 | \\pub export fn test_comparisons(_arg_a: c_int, _arg_b: c_int) c_int { | ||
| 1535 | \\ var a = _arg_a; | ||
| 1536 | \\ var b = _arg_b; | ||
| 1537 | \\ var c: c_int = @boolToInt((a < b)); | ||
| 1538 | \\ var d: c_int = @boolToInt((a > b)); | ||
| 1539 | \\ var e: c_int = @boolToInt((a <= b)); | ||
| 1540 | \\ var f: c_int = @boolToInt((a >= b)); | ||
| 1541 | \\ var g: c_int = @boolToInt((c < d)); | ||
| 1542 | \\ var h: c_int = @boolToInt((e < f)); | ||
| 1543 | \\ var i: c_int = @boolToInt((g < h)); | ||
| 1544 | \\ return i; | ||
| 1545 | \\} | ||
| 1546 | }); | ||
| 1547 | |||
| 1548 | cases.add_2("==, !=", | ||
| 1549 | \\int max(int a, int b) { | ||
| 1550 | \\ if (a == b) | ||
| 1551 | \\ return a; | ||
| 1552 | \\ if (a != b) | ||
| 1553 | \\ return b; | ||
| 1554 | \\ return a; | ||
| 1555 | \\} | ||
| 1556 | , &[_][]const u8{ | ||
| 1557 | \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { | ||
| 1558 | \\ var a = _arg_a; | ||
| 1559 | \\ var b = _arg_b; | ||
| 1560 | \\ if (a == b) return a; | ||
| 1561 | \\ if (a != b) return b; | ||
| 1562 | \\ return a; | ||
| 1563 | \\} | ||
| 1564 | }); | ||
| 1565 | |||
| 1566 | cases.add_2("typedeffed bool expression", | ||
| 1567 | \\typedef char* yes; | ||
| 1568 | \\void foo(void) { | ||
| 1569 | \\ yes a; | ||
| 1570 | \\ if (a) 2; | ||
| 1571 | \\} | ||
| 1572 | , &[_][]const u8{ | ||
| 1573 | \\pub const yes = [*c]u8; | ||
| 1574 | \\pub export fn foo() void { | ||
| 1575 | \\ var a: yes = undefined; | ||
| 1576 | \\ if (a != null) _ = 2; | ||
| 1577 | \\} | ||
| 1578 | }); | ||
| 1579 | |||
| 1580 | cases.add_2("statement expression", | ||
| 1581 | \\int foo(void) { | ||
| 1582 | \\ return ({ | ||
| 1583 | \\ int a = 1; | ||
| 1584 | \\ a; | ||
| 1585 | \\ a; | ||
| 1586 | \\ }); | ||
| 1587 | \\} | ||
| 1588 | , &[_][]const u8{ | ||
| 1589 | \\pub export fn foo() c_int { | ||
| 1590 | \\ return (blk: { | ||
| 1591 | \\ var a: c_int = 1; | ||
| 1592 | \\ _ = a; | ||
| 1593 | \\ break :blk a; | ||
| 1594 | \\ }); | ||
| 1595 | \\} | ||
| 1596 | }); | ||
| 1597 | |||
| 1598 | cases.add_2("field access expression", | ||
| 1599 | \\#define ARROW a->b | ||
| 1600 | \\#define DOT a.b | ||
| 1601 | \\extern struct Foo { | ||
| 1602 | \\ int b; | ||
| 1603 | \\}a; | ||
| 1604 | \\float b = 2.0f; | ||
| 1605 | \\int foo(void) { | ||
| 1606 | \\ struct Foo *c; | ||
| 1607 | \\ a.b; | ||
| 1608 | \\ c->b; | ||
| 1609 | \\} | ||
| 1610 | , &[_][]const u8{ | ||
| 1611 | \\pub const struct_Foo = extern struct { | ||
| 1612 | \\ b: c_int, | ||
| 1613 | \\}; | ||
| 1614 | \\pub extern var a: struct_Foo; | ||
| 1615 | \\pub export var b: f32 = 2; | ||
| 1616 | \\pub export fn foo() c_int { | ||
| 1617 | \\ var c: [*c]struct_Foo = undefined; | ||
| 1618 | \\ _ = a.b; | ||
| 1619 | \\ _ = c.*.b; | ||
| 1620 | \\} | ||
| 1621 | , | ||
| 1622 | \\pub const DOT = a.b; | ||
| 1623 | , | ||
| 1624 | \\pub const ARROW = a.*.b; | ||
| 1625 | }); | ||
| 1626 | |||
| 1627 | cases.add_2("array access", | ||
| 1628 | \\#define ACCESS array[2] | ||
| 1629 | \\int array[100] = {}; | ||
| 1630 | \\int foo(int index) { | ||
| 1631 | \\ return array[index]; | ||
| 1632 | \\} | ||
| 1633 | , &[_][]const u8{ | ||
| 1634 | \\pub export var array: [100]c_int = .{0} ** 100; | ||
| 1635 | \\pub export fn foo(_arg_index: c_int) c_int { | ||
| 1636 | \\ var index = _arg_index; | ||
| 1637 | \\ return array[index]; | ||
| 1638 | \\} | ||
| 1639 | , | ||
| 1640 | \\pub const ACCESS = array[2]; | ||
| 1641 | }); | ||
| 1642 | |||
| 1643 | cases.add_2("macro call", | ||
| 1644 | \\#define CALL(arg) bar(arg) | ||
| 1645 | , &[_][]const u8{ | ||
| 1646 | \\pub inline fn CALL(arg: var) @TypeOf(bar(arg)) { | ||
| 1647 | \\ return bar(arg); | ||
| 1648 | \\} | ||
| 1649 | }); | ||
| 1650 | |||
| 1651 | cases.add_2("logical and, logical or", | ||
| 1652 | \\int max(int a, int b) { | ||
| 1653 | \\ if (a < b || a == b) | ||
| 1654 | \\ return b; | ||
| 1655 | \\ if (a >= b && a == b) | ||
| 1656 | \\ return a; | ||
| 1657 | \\ return a; | ||
| 1658 | \\} | ||
| 1659 | , &[_][]const u8{ | ||
| 1660 | \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { | ||
| 1661 | \\ var a = _arg_a; | ||
| 1662 | \\ var b = _arg_b; | ||
| 1663 | \\ if ((a < b) or (a == b)) return b; | ||
| 1664 | \\ if ((a >= b) and (a == b)) return a; | ||
| 1665 | \\ return a; | ||
| 1666 | \\} | ||
| 1667 | }); | ||
| 1668 | |||
| 1669 | cases.add_2("if statement", | ||
| 1670 | \\int max(int a, int b) { | ||
| 1671 | \\ if (a < b) | ||
| 1672 | \\ return b; | ||
| 1673 | \\ | ||
| 1674 | \\ if (a < b) | ||
| 1675 | \\ return b; | ||
| 1676 | \\ else | ||
| 1677 | \\ return a; | ||
| 1678 | \\ | ||
| 1679 | \\ if (a < b) ; else ; | ||
| 1680 | \\} | ||
| 1681 | , &[_][]const u8{ | ||
| 1682 | \\pub export fn max(_arg_a: c_int, _arg_b: c_int) c_int { | ||
| 1683 | \\ var a = _arg_a; | ||
| 1684 | \\ var b = _arg_b; | ||
| 1685 | \\ if (a < b) return b; | ||
| 1686 | \\ if (a < b) return b else return a; | ||
| 1687 | \\ if (a < b) {} else {} | ||
| 1688 | \\} | ||
| 1689 | }); | ||
| 1690 | |||
| 1691 | cases.add_2("if on non-bool", | ||
| 1692 | \\enum SomeEnum { A, B, C }; | ||
| 1693 | \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { | ||
| 1694 | \\ if (a) return 0; | ||
| 1695 | \\ if (b) return 1; | ||
| 1696 | \\ if (c) return 2; | ||
| 1697 | \\ if (d) return 3; | ||
| 1698 | \\ return 4; | ||
| 1699 | \\} | ||
| 1700 | , &[_][]const u8{ | ||
| 1701 | \\pub const enum_SomeEnum = extern enum { | ||
| 1702 | \\ A, | ||
| 1703 | \\ B, | ||
| 1704 | \\ C, | ||
| 1705 | \\}; | ||
| 1706 | \\pub export fn if_none_bool(_arg_a: c_int, _arg_b: f32, _arg_c: ?*c_void, _arg_d: enum_SomeEnum) c_int { | ||
| 1707 | \\ var a = _arg_a; | ||
| 1708 | \\ var b = _arg_b; | ||
| 1709 | \\ var c = _arg_c; | ||
| 1710 | \\ var d = _arg_d; | ||
| 1711 | \\ if (a != 0) return 0; | ||
| 1712 | \\ if (b != 0) return 1; | ||
| 1713 | \\ if (c != null) return 2; | ||
| 1714 | \\ if (d != 0) return 3; | ||
| 1715 | \\ return 4; | ||
| 1716 | \\} | ||
| 1717 | }); | ||
| 1718 | |||
| 1719 | cases.add_2("simple data types", | ||
| 1720 | \\#include <stdint.h> | ||
| 1721 | \\int foo(char a, unsigned char b, signed char c); | ||
| 1722 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | ||
| 1723 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | ||
| 1724 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | ||
| 1725 | , &[_][]const u8{ | ||
| 1726 | \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; | ||
| 1727 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; | ||
| 1728 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; | ||
| 1729 | }); | ||
| 1730 | |||
| 1731 | cases.add_2("simple function", | ||
| 1732 | \\int abs(int a) { | ||
| 1733 | \\ return a < 0 ? -a : a; | ||
| 1734 | \\} | ||
| 1735 | , &[_][]const u8{ | ||
| 1736 | \\pub export fn abs(_arg_a: c_int) c_int { | ||
| 1737 | \\ var a = _arg_a; | ||
| 1738 | \\ return if (a < 0) -a else a; | ||
| 1739 | \\} | ||
| 1740 | }); | ||
| 1741 | |||
| 1742 | cases.add_2("post increment", | ||
| 1743 | \\unsigned foo1(unsigned a) { | ||
| 1744 | \\ a++; | ||
| 1745 | \\ return a; | ||
| 1746 | \\} | ||
| 1747 | \\int foo2(int a) { | ||
| 1748 | \\ a++; | ||
| 1749 | \\ return a; | ||
| 1750 | \\} | ||
| 1751 | , &[_][]const u8{ | ||
| 1752 | \\pub export fn foo1(_arg_a: c_uint) c_uint { | ||
| 1753 | \\ var a = _arg_a; | ||
| 1754 | \\ a +%= 1; | ||
| 1755 | \\ return a; | ||
| 1756 | \\} | ||
| 1757 | \\pub export fn foo2(_arg_a: c_int) c_int { | ||
| 1758 | \\ var a = _arg_a; | ||
| 1759 | \\ a += 1; | ||
| 1760 | \\ return a; | ||
| 1761 | \\} | ||
| 1762 | }); | ||
| 1763 | |||
| 1764 | cases.add_2("deref function pointer", | ||
| 1765 | \\void foo(void) {} | ||
| 1766 | \\int baz(void) { return 0; } | ||
| 1767 | \\void bar(void) { | ||
| 1768 | \\ void(*f)(void) = foo; | ||
| 1769 | \\ int(*b)(void) = baz; | ||
| 1770 | \\ f(); | ||
| 1771 | \\ (*(f))(); | ||
| 1772 | \\ foo(); | ||
| 1773 | \\ b(); | ||
| 1774 | \\ (*(b))(); | ||
| 1775 | \\ baz(); | ||
| 1776 | \\} | ||
| 1777 | , &[_][]const u8{ | ||
| 1778 | \\pub export fn foo() void {} | ||
| 1779 | \\pub export fn baz() c_int { | ||
| 1780 | \\ return 0; | ||
| 1781 | \\} | ||
| 1782 | \\pub export fn bar() void { | ||
| 1783 | \\ var f: ?extern fn () void = foo; | ||
| 1784 | \\ var b: ?extern fn () c_int = baz; | ||
| 1785 | \\ f.?(); | ||
| 1786 | \\ (f).?(); | ||
| 1787 | \\ foo(); | ||
| 1788 | \\ _ = b.?(); | ||
| 1789 | \\ _ = (b).?(); | ||
| 1790 | \\ _ = baz(); | ||
| 1791 | \\} | ||
| 1792 | }); | ||
| 1793 | |||
| 1794 | cases.add_2("pre increment/decrement", | ||
| 1795 | \\void foo(void) { | ||
| 1796 | \\ int i = 0; | ||
| 1797 | \\ unsigned u = 0; | ||
| 1798 | \\ ++i; | ||
| 1799 | \\ --i; | ||
| 1800 | \\ ++u; | ||
| 1801 | \\ --u; | ||
| 1802 | \\ i = ++i; | ||
| 1803 | \\ i = --i; | ||
| 1804 | \\ u = ++u; | ||
| 1805 | \\ u = --u; | ||
| 1806 | \\} | ||
| 1807 | , &[_][]const u8{ | ||
| 1808 | \\pub export fn foo() void { | ||
| 1809 | \\ var i: c_int = 0; | ||
| 1810 | \\ var u: c_uint = @as(c_uint, 0); | ||
| 1811 | \\ i += 1; | ||
| 1812 | \\ i -= 1; | ||
| 1813 | \\ u +%= 1; | ||
| 1814 | \\ u -%= 1; | ||
| 1815 | \\ i = (blk: { | ||
| 1816 | \\ const _ref_1 = &i; | ||
| 1817 | \\ _ref_1.* += 1; | ||
| 1818 | \\ break :blk _ref_1.*; | ||
| 1819 | \\ }); | ||
| 1820 | \\ i = (blk: { | ||
| 1821 | \\ const _ref_2 = &i; | ||
| 1822 | \\ _ref_2.* -= 1; | ||
| 1823 | \\ break :blk _ref_2.*; | ||
| 1824 | \\ }); | ||
| 1825 | \\ u = (blk: { | ||
| 1826 | \\ const _ref_3 = &u; | ||
| 1827 | \\ _ref_3.* +%= 1; | ||
| 1828 | \\ break :blk _ref_3.*; | ||
| 1829 | \\ }); | ||
| 1830 | \\ u = (blk: { | ||
| 1831 | \\ const _ref_4 = &u; | ||
| 1832 | \\ _ref_4.* -%= 1; | ||
| 1833 | \\ break :blk _ref_4.*; | ||
| 1834 | \\ }); | ||
| 1835 | \\} | ||
| 1836 | }); | ||
| 1837 | |||
| 1838 | cases.add_2("shift right assign", | ||
| 1839 | \\int log2(unsigned a) { | ||
| 1840 | \\ int i = 0; | ||
| 1841 | \\ while (a > 0) { | ||
| 1842 | \\ a >>= 1; | ||
| 1843 | \\ } | ||
| 1844 | \\ return i; | ||
| 1845 | \\} | ||
| 1846 | , &[_][]const u8{ | ||
| 1847 | \\pub export fn log2(_arg_a: c_uint) c_int { | ||
| 1848 | \\ var a = _arg_a; | ||
| 1849 | \\ var i: c_int = 0; | ||
| 1850 | \\ while (a > @as(c_uint, 0)) { | ||
| 1851 | \\ a >>= @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1852 | \\ } | ||
| 1853 | \\ return i; | ||
| 1854 | \\} | ||
| 1855 | }); | ||
| 1856 | |||
| 1857 | cases.add_2("shift right assign with a fixed size type", | ||
| 1858 | \\#include <stdint.h> | ||
| 1859 | \\int log2(uint32_t a) { | ||
| 1860 | \\ int i = 0; | ||
| 1861 | \\ while (a > 0) { | ||
| 1862 | \\ a >>= 1; | ||
| 1863 | \\ } | ||
| 1864 | \\ return i; | ||
| 1865 | \\} | ||
| 1866 | , &[_][]const u8{ | ||
| 1867 | \\pub export fn log2(_arg_a: u32) c_int { | ||
| 1868 | \\ var a = _arg_a; | ||
| 1869 | \\ var i: c_int = 0; | ||
| 1870 | \\ while (a > @as(c_uint, 0)) { | ||
| 1871 | \\ a >>= @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1872 | \\ } | ||
| 1873 | \\ return i; | ||
| 1874 | \\} | ||
| 1875 | }); | ||
| 1876 | |||
| 1877 | cases.add_2("compound assignment operators", | ||
| 1878 | \\void foo(void) { | ||
| 1879 | \\ int a = 0; | ||
| 1880 | \\ a += (a += 1); | ||
| 1881 | \\ a -= (a -= 1); | ||
| 1882 | \\ a *= (a *= 1); | ||
| 1883 | \\ a &= (a &= 1); | ||
| 1884 | \\ a |= (a |= 1); | ||
| 1885 | \\ a ^= (a ^= 1); | ||
| 1886 | \\ a >>= (a >>= 1); | ||
| 1887 | \\ a <<= (a <<= 1); | ||
| 1888 | \\} | ||
| 1889 | , &[_][]const u8{ | ||
| 1890 | \\pub export fn foo() void { | ||
| 1891 | \\ var a: c_int = 0; | ||
| 1892 | \\ a += (blk: { | ||
| 1893 | \\ const _ref_1 = &a; | ||
| 1894 | \\ _ref_1.* = _ref_1.* + 1; | ||
| 1895 | \\ break :blk _ref_1.*; | ||
| 1896 | \\ }); | ||
| 1897 | \\ a -= (blk: { | ||
| 1898 | \\ const _ref_2 = &a; | ||
| 1899 | \\ _ref_2.* = _ref_2.* - 1; | ||
| 1900 | \\ break :blk _ref_2.*; | ||
| 1901 | \\ }); | ||
| 1902 | \\ a *= (blk: { | ||
| 1903 | \\ const _ref_3 = &a; | ||
| 1904 | \\ _ref_3.* = _ref_3.* * 1; | ||
| 1905 | \\ break :blk _ref_3.*; | ||
| 1906 | \\ }); | ||
| 1907 | \\ a &= (blk: { | ||
| 1908 | \\ const _ref_4 = &a; | ||
| 1909 | \\ _ref_4.* = _ref_4.* & 1; | ||
| 1910 | \\ break :blk _ref_4.*; | ||
| 1911 | \\ }); | ||
| 1912 | \\ a |= (blk: { | ||
| 1913 | \\ const _ref_5 = &a; | ||
| 1914 | \\ _ref_5.* = _ref_5.* | 1; | ||
| 1915 | \\ break :blk _ref_5.*; | ||
| 1916 | \\ }); | ||
| 1917 | \\ a ^= (blk: { | ||
| 1918 | \\ const _ref_6 = &a; | ||
| 1919 | \\ _ref_6.* = _ref_6.* ^ 1; | ||
| 1920 | \\ break :blk _ref_6.*; | ||
| 1921 | \\ }); | ||
| 1922 | \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: { | ||
| 1923 | \\ const _ref_7 = &a; | ||
| 1924 | \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1925 | \\ break :blk _ref_7.*; | ||
| 1926 | \\ })); | ||
| 1927 | \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: { | ||
| 1928 | \\ const _ref_8 = &a; | ||
| 1929 | \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1930 | \\ break :blk _ref_8.*; | ||
| 1931 | \\ })); | ||
| 1932 | \\} | ||
| 1933 | }); | ||
| 1934 | |||
| 1935 | cases.add_2("compound assignment operators unsigned", | ||
| 1936 | \\void foo(void) { | ||
| 1937 | \\ unsigned a = 0; | ||
| 1938 | \\ a += (a += 1); | ||
| 1939 | \\ a -= (a -= 1); | ||
| 1940 | \\ a *= (a *= 1); | ||
| 1941 | \\ a &= (a &= 1); | ||
| 1942 | \\ a |= (a |= 1); | ||
| 1943 | \\ a ^= (a ^= 1); | ||
| 1944 | \\ a >>= (a >>= 1); | ||
| 1945 | \\ a <<= (a <<= 1); | ||
| 1946 | \\} | ||
| 1947 | , &[_][]const u8{ | ||
| 1948 | \\pub export fn foo() void { | ||
| 1949 | \\ var a: c_uint = @as(c_uint, 0); | ||
| 1950 | \\ a +%= (blk: { | ||
| 1951 | \\ const _ref_1 = &a; | ||
| 1952 | \\ _ref_1.* = _ref_1.* +% @as(c_uint, 1); | ||
| 1953 | \\ break :blk _ref_1.*; | ||
| 1954 | \\ }); | ||
| 1955 | \\ a -%= (blk: { | ||
| 1956 | \\ const _ref_2 = &a; | ||
| 1957 | \\ _ref_2.* = _ref_2.* -% @as(c_uint, 1); | ||
| 1958 | \\ break :blk _ref_2.*; | ||
| 1959 | \\ }); | ||
| 1960 | \\ a *%= (blk: { | ||
| 1961 | \\ const _ref_3 = &a; | ||
| 1962 | \\ _ref_3.* = _ref_3.* *% @as(c_uint, 1); | ||
| 1963 | \\ break :blk _ref_3.*; | ||
| 1964 | \\ }); | ||
| 1965 | \\ a &= (blk: { | ||
| 1966 | \\ const _ref_4 = &a; | ||
| 1967 | \\ _ref_4.* = _ref_4.* & @as(c_uint, 1); | ||
| 1968 | \\ break :blk _ref_4.*; | ||
| 1969 | \\ }); | ||
| 1970 | \\ a |= (blk: { | ||
| 1971 | \\ const _ref_5 = &a; | ||
| 1972 | \\ _ref_5.* = _ref_5.* | @as(c_uint, 1); | ||
| 1973 | \\ break :blk _ref_5.*; | ||
| 1974 | \\ }); | ||
| 1975 | \\ a ^= (blk: { | ||
| 1976 | \\ const _ref_6 = &a; | ||
| 1977 | \\ _ref_6.* = _ref_6.* ^ @as(c_uint, 1); | ||
| 1978 | \\ break :blk _ref_6.*; | ||
| 1979 | \\ }); | ||
| 1980 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: { | ||
| 1981 | \\ const _ref_7 = &a; | ||
| 1982 | \\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1983 | \\ break :blk _ref_7.*; | ||
| 1984 | \\ })); | ||
| 1985 | \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: { | ||
| 1986 | \\ const _ref_8 = &a; | ||
| 1987 | \\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1); | ||
| 1988 | \\ break :blk _ref_8.*; | ||
| 1989 | \\ })); | ||
| 1990 | \\} | ||
| 1991 | }); | ||
| 1992 | |||
| 1993 | cases.add_2("post increment/decrement", | ||
| 1994 | \\void foo(void) { | ||
| 1995 | \\ int i = 0; | ||
| 1996 | \\ unsigned u = 0; | ||
| 1997 | \\ i++; | ||
| 1998 | \\ i--; | ||
| 1999 | \\ u++; | ||
| 2000 | \\ u--; | ||
| 2001 | \\ i = i++; | ||
| 2002 | \\ i = i--; | ||
| 2003 | \\ u = u++; | ||
| 2004 | \\ u = u--; | ||
| 2005 | \\} | ||
| 2006 | , &[_][]const u8{ | ||
| 2007 | \\pub export fn foo() void { | ||
| 2008 | \\ var i: c_int = 0; | ||
| 2009 | \\ var u: c_uint = @as(c_uint, 0); | ||
| 2010 | \\ i += 1; | ||
| 2011 | \\ i -= 1; | ||
| 2012 | \\ u +%= 1; | ||
| 2013 | \\ u -%= 1; | ||
| 2014 | \\ i = (blk: { | ||
| 2015 | \\ const _ref_1 = &i; | ||
| 2016 | \\ const _tmp_2 = _ref_1.*; | ||
| 2017 | \\ _ref_1.* += 1; | ||
| 2018 | \\ break :blk _tmp_2; | ||
| 2019 | \\ }); | ||
| 2020 | \\ i = (blk: { | ||
| 2021 | \\ const _ref_3 = &i; | ||
| 2022 | \\ const _tmp_4 = _ref_3.*; | ||
| 2023 | \\ _ref_3.* -= 1; | ||
| 2024 | \\ break :blk _tmp_4; | ||
| 2025 | \\ }); | ||
| 2026 | \\ u = (blk: { | ||
| 2027 | \\ const _ref_5 = &u; | ||
| 2028 | \\ const _tmp_6 = _ref_5.*; | ||
| 2029 | \\ _ref_5.* +%= 1; | ||
| 2030 | \\ break :blk _tmp_6; | ||
| 2031 | \\ }); | ||
| 2032 | \\ u = (blk: { | ||
| 2033 | \\ const _ref_7 = &u; | ||
| 2034 | \\ const _tmp_8 = _ref_7.*; | ||
| 2035 | \\ _ref_7.* -%= 1; | ||
| 2036 | \\ break :blk _tmp_8; | ||
| 2037 | \\ }); | ||
| 2038 | \\} | ||
| 2039 | }); | ||
| 2040 | |||
| 2041 | cases.add_2("implicit casts", | ||
| 2042 | \\#include <stdbool.h> | ||
| 2043 | \\ | ||
| 2044 | \\void fn_int(int x); | ||
| 2045 | \\void fn_f32(float x); | ||
| 2046 | \\void fn_f64(double x); | ||
| 2047 | \\void fn_char(char x); | ||
| 2048 | \\void fn_bool(bool x); | ||
| 2049 | \\void fn_ptr(void *x); | ||
| 2050 | \\ | ||
| 2051 | \\void call(int q) { | ||
| 2052 | \\ fn_int(3.0f); | ||
| 2053 | \\ fn_int(3.0); | ||
| 2054 | \\ fn_int(3.0L); | ||
| 2055 | \\ fn_int('ABCD'); | ||
| 2056 | \\ fn_f32(3); | ||
| 2057 | \\ fn_f64(3); | ||
| 2058 | \\ fn_char('3'); | ||
| 2059 | \\ fn_char('\x1'); | ||
| 2060 | \\ fn_char(0); | ||
| 2061 | \\ fn_f32(3.0f); | ||
| 2062 | \\ fn_f64(3.0); | ||
| 2063 | \\ fn_bool(123); | ||
| 2064 | \\ fn_bool(0); | ||
| 2065 | \\ fn_bool(&fn_int); | ||
| 2066 | \\ fn_int(&fn_int); | ||
| 2067 | \\ fn_ptr(42); | ||
| 2068 | \\} | ||
| 2069 | , &[_][]const u8{ | ||
| 2070 | \\pub extern fn fn_int(x: c_int) void; | ||
| 2071 | \\pub extern fn fn_f32(x: f32) void; | ||
| 2072 | \\pub extern fn fn_f64(x: f64) void; | ||
| 2073 | \\pub extern fn fn_char(x: u8) void; | ||
| 2074 | \\pub extern fn fn_bool(x: bool) void; | ||
| 2075 | \\pub extern fn fn_ptr(x: ?*c_void) void; | ||
| 2076 | \\pub export fn call(_arg_q: c_int) void { | ||
| 2077 | \\ var q = _arg_q; | ||
| 2078 | \\ fn_int(@floatToInt(c_int, 3)); | ||
| 2079 | \\ fn_int(@floatToInt(c_int, 3)); | ||
| 2080 | \\ fn_int(@floatToInt(c_int, 3)); | ||
| 2081 | \\ fn_int(1094861636); | ||
| 2082 | \\ fn_f32(@intToFloat(f32, 3)); | ||
| 2083 | \\ fn_f64(@intToFloat(f64, 3)); | ||
| 2084 | \\ fn_char(@as(u8, '3')); | ||
| 2085 | \\ fn_char(@as(u8, '\x01')); | ||
| 2086 | \\ fn_char(@as(u8, 0)); | ||
| 2087 | \\ fn_f32(3); | ||
| 2088 | \\ fn_f64(3); | ||
| 2089 | \\ fn_bool(123 != 0); | ||
| 2090 | \\ fn_bool(0 != 0); | ||
| 2091 | \\ fn_bool(@ptrToInt(&fn_int) != 0); | ||
| 2092 | \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); | ||
| 2093 | \\ fn_ptr(@intToPtr(?*c_void, 42)); | ||
| 2094 | \\} | ||
| 2095 | }); | ||
| 2096 | |||
| 2097 | cases.add_2("function call", | ||
| 2098 | \\static void bar(void) { } | ||
| 2099 | \\void foo(int *(baz)(void)) { | ||
| 2100 | \\ bar(); | ||
| 2101 | \\ baz(); | ||
| 2102 | \\} | ||
| 2103 | , &[_][]const u8{ | ||
| 2104 | \\pub fn bar() void {} | ||
| 2105 | \\pub export fn foo(_arg_baz: ?extern fn () [*c]c_int) void { | ||
| 2106 | \\ var baz = _arg_baz; | ||
| 2107 | \\ bar(); | ||
| 2108 | \\ _ = baz.?(); | ||
| 2109 | \\} | ||
| 2110 | }); | ||
| 2111 | |||
| 2112 | cases.add_2("macro defines string literal with octal", | ||
| 2113 | \\#define FOO "aoeu\023 derp" | ||
| 2114 | \\#define FOO2 "aoeu\0234 derp" | ||
| 2115 | \\#define FOO_CHAR '\077' | ||
| 2116 | , &[_][]const u8{ | ||
| 2117 | \\pub const FOO = "aoeu\x13 derp"; | ||
| 2118 | , | ||
| 2119 | \\pub const FOO2 = "aoeu\x134 derp"; | ||
| 2120 | , | ||
| 2121 | \\pub const FOO_CHAR = '\x3f'; | ||
| 2122 | }); | ||
| 2123 | |||
| 2124 | cases.add_2("enums", | ||
| 2125 | \\enum Foo { | ||
| 2126 | \\ FooA, | ||
| 2127 | \\ FooB, | ||
| 2128 | \\ Foo1, | ||
| 2129 | \\}; | ||
| 2130 | , &[_][]const u8{ | ||
| 2131 | \\pub const enum_Foo = extern enum { | ||
| 2132 | \\ A, | ||
| 2133 | \\ B, | ||
| 2134 | \\ @"1", | ||
| 2135 | \\}; | ||
| 2136 | , | ||
| 2137 | \\pub const FooA = 0; | ||
| 2138 | , | ||
| 2139 | \\pub const FooB = 1; | ||
| 2140 | , | ||
| 2141 | \\pub const Foo1 = 2; | ||
| 2142 | , | ||
| 2143 | \\pub const Foo = enum_Foo; | ||
| 2144 | }); | ||
| 2145 | |||
| 2146 | cases.add_2("enums", | ||
| 2147 | \\enum Foo { | ||
| 2148 | \\ FooA = 2, | ||
| 2149 | \\ FooB = 5, | ||
| 2150 | \\ Foo1, | ||
| 2151 | \\}; | ||
| 2152 | , &[_][]const u8{ | ||
| 2153 | \\pub const enum_Foo = extern enum { | ||
| 2154 | \\ A = 2, | ||
| 2155 | \\ B = 5, | ||
| 2156 | \\ @"1" = 6, | ||
| 2157 | \\}; | ||
| 2158 | , | ||
| 2159 | \\pub const FooA = 2; | ||
| 2160 | , | ||
| 2161 | \\pub const FooB = 5; | ||
| 2162 | , | ||
| 2163 | \\pub const Foo1 = 6; | ||
| 2164 | , | ||
| 2165 | \\pub const Foo = enum_Foo; | ||
| 2166 | }); | ||
| 2167 | |||
| 2168 | cases.add_2("macro cast", | ||
| 2169 | \\#define FOO(bar) baz((void *)(baz)) | ||
| 2170 | , &[_][]const u8{ | ||
| 2171 | \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz))) { | ||
| 2172 | \\ return baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast([*c]void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr([*c]void, baz) else @as([*c]void, baz)); | ||
| 2173 | \\} | ||
| 2174 | }); | ||
| 2175 | |||
| 2176 | /////////////// Cases for only stage1 because stage2 behavior is better //////////////// | ||
| 2177 | cases.addC("Parameterless function prototypes", | ||
| 2178 | \\void foo() {} | ||
| 2179 | \\void bar(void) {} | ||
| 2180 | , &[_][]const u8{ | ||
| 2181 | \\pub export fn foo() void {} | ||
| 2182 | \\pub export fn bar() void {} | ||
| 2183 | }); | ||
| 2184 | |||
| 2185 | cases.add("#define a char literal", | ||
| 2186 | \\#define A_CHAR 'a' | ||
| 2187 | , &[_][]const u8{ | ||
| 2188 | \\pub const A_CHAR = 97; | ||
| 2189 | }); | ||
| 2190 | |||
| 2191 | cases.add("generate inline func for #define global extern fn", | ||
| 2192 | \\extern void (*fn_ptr)(void); | ||
| 2193 | \\#define foo fn_ptr | ||
| 2194 | \\ | ||
| 2195 | \\extern char (*fn_ptr2)(int, float); | ||
| 2196 | \\#define bar fn_ptr2 | ||
| 2197 | , &[_][]const u8{ | ||
| 2198 | \\pub extern var fn_ptr: ?extern fn () void; | ||
| 2199 | , | ||
| 2200 | \\pub inline fn foo() void { | ||
| 2201 | \\ return fn_ptr.?(); | ||
| 2202 | \\} | ||
| 2203 | , | ||
| 2204 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | ||
| 2205 | , | ||
| 2206 | \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { | ||
| 2207 | \\ return fn_ptr2.?(arg0, arg1); | ||
| 2208 | \\} | ||
| 2209 | }); | ||
| 2210 | cases.add("comment after integer literal", | ||
| 2211 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2212 | , &[_][]const u8{ | ||
| 2213 | \\pub const SDL_INIT_VIDEO = 32; | ||
| 2214 | }); | ||
| 2215 | |||
| 2216 | cases.add("u integer suffix after hex literal", | ||
| 2217 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2218 | , &[_][]const u8{ | ||
| 2219 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); | ||
| 2220 | }); | ||
| 2221 | |||
| 2222 | cases.add("l integer suffix after hex literal", | ||
| 2223 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2224 | , &[_][]const u8{ | ||
| 2225 | \\pub const SDL_INIT_VIDEO = @as(c_long, 32); | ||
| 2226 | }); | ||
| 2227 | |||
| 2228 | cases.add("ul integer suffix after hex literal", | ||
| 2229 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2230 | , &[_][]const u8{ | ||
| 2231 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | ||
| 2232 | }); | ||
| 2233 | |||
| 2234 | cases.add("lu integer suffix after hex literal", | ||
| 2235 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2236 | , &[_][]const u8{ | ||
| 2237 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | ||
| 2238 | }); | ||
| 2239 | |||
| 2240 | cases.add("ll integer suffix after hex literal", | ||
| 2241 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2242 | , &[_][]const u8{ | ||
| 2243 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); | ||
| 2244 | }); | ||
| 2245 | |||
| 2246 | cases.add("ull integer suffix after hex literal", | ||
| 2247 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2248 | , &[_][]const u8{ | ||
| 2249 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | ||
| 2250 | }); | ||
| 2251 | |||
| 2252 | cases.add("llu integer suffix after hex literal", | ||
| 2253 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2254 | , &[_][]const u8{ | ||
| 2255 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | ||
| 2256 | }); | ||
| 2257 | |||
| 2258 | cases.add("macros with field targets", | ||
| 2259 | \\typedef unsigned int GLbitfield; | ||
| 2260 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | ||
| 2261 | \\typedef void(*OpenGLProc)(void); | ||
| 2262 | \\union OpenGLProcs { | ||
| 2263 | \\ OpenGLProc ptr[1]; | ||
| 2264 | \\ struct { | ||
| 2265 | \\ PFNGLCLEARPROC Clear; | ||
| 2266 | \\ } gl; | ||
| 2267 | \\}; | ||
| 2268 | \\extern union OpenGLProcs glProcs; | ||
| 2269 | \\#define glClearUnion glProcs.gl.Clear | ||
| 2270 | \\#define glClearPFN PFNGLCLEARPROC | ||
| 2271 | , &[_][]const u8{ | ||
| 2272 | \\pub const GLbitfield = c_uint; | ||
| 2273 | , | ||
| 2274 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | ||
| 2275 | , | ||
| 2276 | \\pub const OpenGLProc = ?extern fn () void; | ||
| 2277 | , | ||
| 2278 | \\pub const union_OpenGLProcs = extern union { | ||
| 2279 | \\ ptr: [1]OpenGLProc, | ||
| 2280 | \\ gl: extern struct { | ||
| 2281 | \\ Clear: PFNGLCLEARPROC, | ||
| 2282 | \\ }, | ||
| 2283 | \\}; | ||
| 2284 | , | ||
| 2285 | \\pub extern var glProcs: union_OpenGLProcs; | ||
| 2286 | , | ||
| 2287 | \\pub const glClearPFN = PFNGLCLEARPROC; | ||
| 2288 | , | ||
| 2289 | \\pub inline fn glClearUnion(arg0: GLbitfield) void { | ||
| 2290 | \\ return glProcs.gl.Clear.?(arg0); | ||
| 2291 | \\} | ||
| 2292 | , | ||
| 2293 | \\pub const OpenGLProcs = union_OpenGLProcs; | ||
| 2294 | }); | ||
| 2295 | |||
| 2296 | cases.add("macro pointer cast", | ||
| 2297 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | ||
| 2298 | , &[_][]const u8{ | ||
| 2299 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | ||
| 2300 | }); | ||
| 2301 | |||
| 2302 | cases.add("switch on int", | ||
| 2303 | \\int switch_fn(int i) { | ||
| 2304 | \\ int res = 0; | ||
| 2305 | \\ switch (i) { | ||
| 2306 | \\ case 0: | ||
| 2307 | \\ res = 1; | ||
| 2308 | \\ case 1: | ||
| 2309 | \\ res = 2; | ||
| 2310 | \\ default: | ||
| 2311 | \\ res = 3 * i; | ||
| 2312 | \\ break; | ||
| 2313 | \\ case 2: | ||
| 2314 | \\ res = 5; | ||
| 2315 | \\ } | ||
| 2316 | \\} | ||
| 2317 | , &[_][]const u8{ | ||
| 2318 | \\pub fn switch_fn(i: c_int) c_int { | ||
| 2319 | \\ var res: c_int = 0; | ||
| 2320 | \\ __switch: { | ||
| 2321 | \\ __case_2: { | ||
| 2322 | \\ __default: { | ||
| 2323 | \\ __case_1: { | ||
| 2324 | \\ __case_0: { | ||
| 2325 | \\ switch (i) { | ||
| 2326 | \\ 0 => break :__case_0, | ||
| 2327 | \\ 1 => break :__case_1, | ||
| 2328 | \\ else => break :__default, | ||
| 2329 | \\ 2 => break :__case_2, | ||
| 2330 | \\ } | ||
| 2331 | \\ } | ||
| 2332 | \\ res = 1; | ||
| 2333 | \\ } | ||
| 2334 | \\ res = 2; | ||
| 2335 | \\ } | ||
| 2336 | \\ res = (3 * i); | ||
| 2337 | \\ break :__switch; | ||
| 2338 | \\ } | ||
| 2339 | \\ res = 5; | ||
| 2340 | \\ } | ||
| 2341 | \\} | ||
| 2342 | }); | ||
| 2343 | |||
| 2344 | cases.add("for loop with var init but empty body", | ||
| 2345 | \\void foo(void) { | ||
| 2346 | \\ for (int x = 0; x < 10; x++); | ||
| 2347 | \\} | ||
| 2348 | , &[_][]const u8{ | ||
| 2349 | \\pub fn foo() void { | ||
| 2350 | \\ { | ||
| 2351 | \\ var x: c_int = 0; | ||
| 2352 | \\ while (x < 10) : (x += 1) {} | ||
| 2353 | \\ } | ||
| 2354 | \\} | ||
| 2355 | }); | ||
| 2356 | |||
| 2357 | cases.add("do while with empty body", | ||
| 2358 | \\void foo(void) { | ||
| 2359 | \\ do ; while (1); | ||
| 2360 | \\} | ||
| 2361 | , &[_][]const u8{ // TODO this should be if (1 != 0) break | ||
| 2362 | \\pub fn foo() void { | ||
| 2363 | \\ while (true) { | ||
| 2364 | \\ {} | ||
| 2365 | \\ if (!1) break; | ||
| 2366 | \\ } | ||
| 2367 | \\} | ||
| 2368 | }); | ||
| 2369 | |||
| 2370 | cases.add("for with empty body", | ||
| 2371 | \\void foo(void) { | ||
| 2372 | \\ for (;;); | ||
| 2373 | \\} | ||
| 2374 | , &[_][]const u8{ | ||
| 2375 | \\pub fn foo() void { | ||
| 2376 | \\ while (true) {} | ||
| 2377 | \\} | ||
| 2378 | }); | ||
| 2379 | |||
| 2380 | cases.add("while with empty body", | ||
| 2381 | \\void foo(void) { | ||
| 2382 | \\ while (1); | ||
| 2383 | \\} | ||
| 2384 | , &[_][]const u8{ | ||
| 2385 | \\pub fn foo() void { | ||
| 2386 | \\ while (1 != 0) {} | ||
| 2387 | \\} | ||
| 2388 | }); | ||
| 2389 | |||
| 2390 | cases.add("undefined array global", | ||
| 2391 | \\int array[100]; | ||
| 2392 | , &[_][]const u8{ | ||
| 2393 | \\pub var array: [100]c_int = undefined; | ||
| 2394 | }); | ||
| 2395 | |||
| 2396 | cases.add("qualified struct and enum", | ||
| 2397 | \\struct Foo { | ||
| 2398 | \\ int x; | ||
| 2399 | \\ int y; | ||
| 2400 | \\}; | ||
| 2401 | \\enum Bar { | ||
| 2402 | \\ BarA, | ||
| 2403 | \\ BarB, | ||
| 2404 | \\}; | ||
| 2405 | \\void func(struct Foo *a, enum Bar **b); | ||
| 2406 | , &[_][]const u8{ | ||
| 2407 | \\pub const struct_Foo = extern struct { | ||
| 2408 | \\ x: c_int, | ||
| 2409 | \\ y: c_int, | ||
| 2410 | \\}; | ||
| 2411 | , | ||
| 2412 | \\pub const enum_Bar = extern enum { | ||
| 2413 | \\ A, | ||
| 2414 | \\ B, | ||
| 2415 | \\}; | ||
| 2416 | , | ||
| 2417 | \\pub const BarA = enum_Bar.A; | ||
| 2418 | , | ||
| 2419 | \\pub const BarB = enum_Bar.B; | ||
| 2420 | , | ||
| 2421 | \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void; | ||
| 2422 | , | ||
| 2423 | \\pub const Foo = struct_Foo; | ||
| 2424 | , | ||
| 2425 | \\pub const Bar = enum_Bar; | ||
| 2426 | }); | ||
| 2427 | |||
| 2428 | cases.add("restrict -> noalias", | ||
| 2429 | \\void foo(void *restrict bar, void *restrict); | ||
| 2430 | , &[_][]const u8{ | ||
| 2431 | \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; | ||
| 1348 | }); | 2432 | }); |
| 1349 | 2433 | ||
| 1350 | cases.addC("compound assignment operators unsigned", | 2434 | cases.addC("assign", |
| 1351 | \\void foo(void) { | 2435 | \\int max(int a) { |
| 1352 | \\ unsigned a = 0; | 2436 | \\ int tmp; |
| 1353 | \\ a += (a += 1); | 2437 | \\ tmp = a; |
| 1354 | \\ a -= (a -= 1); | 2438 | \\ a = tmp; |
| 1355 | \\ a *= (a *= 1); | ||
| 1356 | \\ a &= (a &= 1); | ||
| 1357 | \\ a |= (a |= 1); | ||
| 1358 | \\ a ^= (a ^= 1); | ||
| 1359 | \\ a >>= (a >>= 1); | ||
| 1360 | \\ a <<= (a <<= 1); | ||
| 1361 | \\} | 2439 | \\} |
| 1362 | , &[_][]const u8{ | 2440 | , &[_][]const u8{ |
| 1363 | \\pub export fn foo() void { | 2441 | \\pub export fn max(_arg_a: c_int) c_int { |
| 1364 | \\ var a: c_uint = @as(c_uint, 0); | 2442 | \\ var a = _arg_a; |
| 1365 | \\ a +%= (x: { | 2443 | \\ var tmp: c_int = undefined; |
| 1366 | \\ const _ref = &a; | 2444 | \\ tmp = a; |
| 1367 | \\ _ref.* = (_ref.* +% @as(c_uint, 1)); | 2445 | \\ a = tmp; |
| 1368 | \\ break :x _ref.*; | ||
| 1369 | \\ }); | ||
| 1370 | \\ a -%= (x: { | ||
| 1371 | \\ const _ref = &a; | ||
| 1372 | \\ _ref.* = (_ref.* -% @as(c_uint, 1)); | ||
| 1373 | \\ break :x _ref.*; | ||
| 1374 | \\ }); | ||
| 1375 | \\ a *%= (x: { | ||
| 1376 | \\ const _ref = &a; | ||
| 1377 | \\ _ref.* = (_ref.* *% @as(c_uint, 1)); | ||
| 1378 | \\ break :x _ref.*; | ||
| 1379 | \\ }); | ||
| 1380 | \\ a &= (x: { | ||
| 1381 | \\ const _ref = &a; | ||
| 1382 | \\ _ref.* = (_ref.* & @as(c_uint, 1)); | ||
| 1383 | \\ break :x _ref.*; | ||
| 1384 | \\ }); | ||
| 1385 | \\ a |= (x: { | ||
| 1386 | \\ const _ref = &a; | ||
| 1387 | \\ _ref.* = (_ref.* | @as(c_uint, 1)); | ||
| 1388 | \\ break :x _ref.*; | ||
| 1389 | \\ }); | ||
| 1390 | \\ a ^= (x: { | ||
| 1391 | \\ const _ref = &a; | ||
| 1392 | \\ _ref.* = (_ref.* ^ @as(c_uint, 1)); | ||
| 1393 | \\ break :x _ref.*; | ||
| 1394 | \\ }); | ||
| 1395 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: { | ||
| 1396 | \\ const _ref = &a; | ||
| 1397 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1)); | ||
| 1398 | \\ break :x _ref.*; | ||
| 1399 | \\ })); | ||
| 1400 | \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: { | ||
| 1401 | \\ const _ref = &a; | ||
| 1402 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1)); | ||
| 1403 | \\ break :x _ref.*; | ||
| 1404 | \\ })); | ||
| 1405 | \\} | 2446 | \\} |
| 1406 | }); | 2447 | }); |
| 1407 | 2448 | ||
| 1408 | cases.addC("post increment/decrement", | 2449 | cases.addC("chaining assign", |
| 1409 | \\void foo(void) { | 2450 | \\void max(int a) { |
| 1410 | \\ int i = 0; | 2451 | \\ int b, c; |
| 1411 | \\ unsigned u = 0; | 2452 | \\ c = b = a; |
| 1412 | \\ i++; | ||
| 1413 | \\ i--; | ||
| 1414 | \\ u++; | ||
| 1415 | \\ u--; | ||
| 1416 | \\ i = i++; | ||
| 1417 | \\ i = i--; | ||
| 1418 | \\ u = u++; | ||
| 1419 | \\ u = u--; | ||
| 1420 | \\} | 2453 | \\} |
| 1421 | , &[_][]const u8{ | 2454 | , &[_][]const u8{ |
| 1422 | \\pub export fn foo() void { | 2455 | \\pub export fn max(a: c_int) void { |
| 1423 | \\ var i: c_int = 0; | 2456 | \\ var b: c_int = undefined; |
| 1424 | \\ var u: c_uint = @as(c_uint, 0); | 2457 | \\ var c: c_int = undefined; |
| 1425 | \\ i += 1; | 2458 | \\ c = (x: { |
| 1426 | \\ i -= 1; | 2459 | \\ const _tmp = a; |
| 1427 | \\ u +%= 1; | 2460 | \\ b = _tmp; |
| 1428 | \\ u -%= 1; | ||
| 1429 | \\ i = (x: { | ||
| 1430 | \\ const _ref = &i; | ||
| 1431 | \\ const _tmp = _ref.*; | ||
| 1432 | \\ _ref.* += 1; | ||
| 1433 | \\ break :x _tmp; | ||
| 1434 | \\ }); | ||
| 1435 | \\ i = (x: { | ||
| 1436 | \\ const _ref = &i; | ||
| 1437 | \\ const _tmp = _ref.*; | ||
| 1438 | \\ _ref.* -= 1; | ||
| 1439 | \\ break :x _tmp; | ||
| 1440 | \\ }); | ||
| 1441 | \\ u = (x: { | ||
| 1442 | \\ const _ref = &u; | ||
| 1443 | \\ const _tmp = _ref.*; | ||
| 1444 | \\ _ref.* +%= 1; | ||
| 1445 | \\ break :x _tmp; | ||
| 1446 | \\ }); | ||
| 1447 | \\ u = (x: { | ||
| 1448 | \\ const _ref = &u; | ||
| 1449 | \\ const _tmp = _ref.*; | ||
| 1450 | \\ _ref.* -%= 1; | ||
| 1451 | \\ break :x _tmp; | 2461 | \\ break :x _tmp; |
| 1452 | \\ }); | 2462 | \\ }); |
| 1453 | \\} | 2463 | \\} |
| 1454 | }); | 2464 | }); |
| 1455 | 2465 | ||
| 1456 | cases.addC("pre increment/decrement", | 2466 | cases.add("anonymous enum", |
| 1457 | \\void foo(void) { | 2467 | \\enum { |
| 1458 | \\ int i = 0; | 2468 | \\ One, |
| 1459 | \\ unsigned u = 0; | 2469 | \\ Two, |
| 1460 | \\ ++i; | 2470 | \\}; |
| 1461 | \\ --i; | ||
| 1462 | \\ ++u; | ||
| 1463 | \\ --u; | ||
| 1464 | \\ i = ++i; | ||
| 1465 | \\ i = --i; | ||
| 1466 | \\ u = ++u; | ||
| 1467 | \\ u = --u; | ||
| 1468 | \\} | ||
| 1469 | , &[_][]const u8{ | 2471 | , &[_][]const u8{ |
| 1470 | \\pub export fn foo() void { | 2472 | \\pub const One = 0; |
| 1471 | \\ var i: c_int = 0; | 2473 | \\pub const Two = 1; |
| 1472 | \\ var u: c_uint = @as(c_uint, 0); | ||
| 1473 | \\ i += 1; | ||
| 1474 | \\ i -= 1; | ||
| 1475 | \\ u +%= 1; | ||
| 1476 | \\ u -%= 1; | ||
| 1477 | \\ i = (x: { | ||
| 1478 | \\ const _ref = &i; | ||
| 1479 | \\ _ref.* += 1; | ||
| 1480 | \\ break :x _ref.*; | ||
| 1481 | \\ }); | ||
| 1482 | \\ i = (x: { | ||
| 1483 | \\ const _ref = &i; | ||
| 1484 | \\ _ref.* -= 1; | ||
| 1485 | \\ break :x _ref.*; | ||
| 1486 | \\ }); | ||
| 1487 | \\ u = (x: { | ||
| 1488 | \\ const _ref = &u; | ||
| 1489 | \\ _ref.* +%= 1; | ||
| 1490 | \\ break :x _ref.*; | ||
| 1491 | \\ }); | ||
| 1492 | \\ u = (x: { | ||
| 1493 | \\ const _ref = &u; | ||
| 1494 | \\ _ref.* -%= 1; | ||
| 1495 | \\ break :x _ref.*; | ||
| 1496 | \\ }); | ||
| 1497 | \\} | ||
| 1498 | }); | 2474 | }); |
| 1499 | 2475 | ||
| 1500 | cases.addC("do loop", | 2476 | cases.addC("c style cast", |
| 1501 | \\void foo(void) { | 2477 | \\int float_to_int(float a) { |
| 1502 | \\ int a = 2; | 2478 | \\ return (int)a; |
| 1503 | \\ do { | ||
| 1504 | \\ a--; | ||
| 1505 | \\ } while (a != 0); | ||
| 1506 | \\ | ||
| 1507 | \\ int b = 2; | ||
| 1508 | \\ do | ||
| 1509 | \\ b--; | ||
| 1510 | \\ while (b != 0); | ||
| 1511 | \\} | 2479 | \\} |
| 1512 | , &[_][]const u8{ | 2480 | , &[_][]const u8{ |
| 1513 | \\pub export fn foo() void { | 2481 | \\pub export fn float_to_int(a: f32) c_int { |
| 1514 | \\ var a: c_int = 2; | 2482 | \\ return @as(c_int, a); |
| 1515 | \\ while (true) { | ||
| 1516 | \\ a -= 1; | ||
| 1517 | \\ if (!(a != 0)) break; | ||
| 1518 | \\ } | ||
| 1519 | \\ var b: c_int = 2; | ||
| 1520 | \\ while (true) { | ||
| 1521 | \\ b -= 1; | ||
| 1522 | \\ if (!(b != 0)) break; | ||
| 1523 | \\ } | ||
| 1524 | \\} | 2483 | \\} |
| 1525 | }); | 2484 | }); |
| 1526 | 2485 | ||
| 1527 | cases.addC("deref function pointer", | 2486 | cases.addC("comma operator", |
| 1528 | \\void foo(void) {} | 2487 | \\int foo(void) { |
| 1529 | \\int baz(void) { return 0; } | 2488 | \\ return 1, 2; |
| 1530 | \\void bar(void) { | ||
| 1531 | \\ void(*f)(void) = foo; | ||
| 1532 | \\ int(*b)(void) = baz; | ||
| 1533 | \\ f(); | ||
| 1534 | \\ (*(f))(); | ||
| 1535 | \\ foo(); | ||
| 1536 | \\ b(); | ||
| 1537 | \\ (*(b))(); | ||
| 1538 | \\ baz(); | ||
| 1539 | \\} | 2489 | \\} |
| 1540 | , &[_][]const u8{ | 2490 | , &[_][]const u8{ |
| 1541 | \\pub export fn foo() void {} | 2491 | \\pub export fn foo() c_int { |
| 1542 | \\pub export fn baz() c_int { | 2492 | \\ return x: { |
| 1543 | \\ return 0; | 2493 | \\ _ = 1; |
| 1544 | \\} | 2494 | \\ break :x 2; |
| 1545 | \\pub export fn bar() void { | 2495 | \\ }; |
| 1546 | \\ var f: ?extern fn () void = foo; | ||
| 1547 | \\ var b: ?extern fn () c_int = baz; | ||
| 1548 | \\ f.?(); | ||
| 1549 | \\ f.?(); | ||
| 1550 | \\ foo(); | ||
| 1551 | \\ _ = b.?(); | ||
| 1552 | \\ _ = b.?(); | ||
| 1553 | \\ _ = baz(); | ||
| 1554 | \\} | 2496 | \\} |
| 1555 | }); | 2497 | }); |
| 1556 | 2498 | ||
| 1557 | cases.addC("normal deref", | 2499 | cases.addC("escape sequences", |
| 1558 | \\void foo(int *x) { | 2500 | \\const char *escapes() { |
| 1559 | \\ *x = 1; | 2501 | \\char a = '\'', |
| 2502 | \\ b = '\\', | ||
| 2503 | \\ c = '\a', | ||
| 2504 | \\ d = '\b', | ||
| 2505 | \\ e = '\f', | ||
| 2506 | \\ f = '\n', | ||
| 2507 | \\ g = '\r', | ||
| 2508 | \\ h = '\t', | ||
| 2509 | \\ i = '\v', | ||
| 2510 | \\ j = '\0', | ||
| 2511 | \\ k = '\"'; | ||
| 2512 | \\ return "\'\\\a\b\f\n\r\t\v\0\""; | ||
| 1560 | \\} | 2513 | \\} |
| 2514 | \\ | ||
| 1561 | , &[_][]const u8{ | 2515 | , &[_][]const u8{ |
| 1562 | \\pub export fn foo(x: [*c]c_int) void { | 2516 | \\pub export fn escapes() [*c]const u8 { |
| 1563 | \\ x.?.* = 1; | 2517 | \\ var a: u8 = @as(u8, '\''); |
| 2518 | \\ var b: u8 = @as(u8, '\\'); | ||
| 2519 | \\ var c: u8 = @as(u8, '\x07'); | ||
| 2520 | \\ var d: u8 = @as(u8, '\x08'); | ||
| 2521 | \\ var e: u8 = @as(u8, '\x0c'); | ||
| 2522 | \\ var f: u8 = @as(u8, '\n'); | ||
| 2523 | \\ var g: u8 = @as(u8, '\r'); | ||
| 2524 | \\ var h: u8 = @as(u8, '\t'); | ||
| 2525 | \\ var i: u8 = @as(u8, '\x0b'); | ||
| 2526 | \\ var j: u8 = @as(u8, '\x00'); | ||
| 2527 | \\ var k: u8 = @as(u8, '\"'); | ||
| 2528 | \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; | ||
| 1564 | \\} | 2529 | \\} |
| 2530 | \\ | ||
| 1565 | }); | 2531 | }); |
| 1566 | 2532 | ||
| 1567 | cases.add("simple union", | 2533 | cases.addC("do loop", |
| 1568 | \\union Foo { | 2534 | \\void foo(void) { |
| 1569 | \\ int x; | 2535 | \\ int a = 2; |
| 1570 | \\ double y; | 2536 | \\ do { |
| 1571 | \\}; | 2537 | \\ a--; |
| 2538 | \\ } while (a != 0); | ||
| 2539 | \\ | ||
| 2540 | \\ int b = 2; | ||
| 2541 | \\ do | ||
| 2542 | \\ b--; | ||
| 2543 | \\ while (b != 0); | ||
| 2544 | \\} | ||
| 1572 | , &[_][]const u8{ | 2545 | , &[_][]const u8{ |
| 1573 | \\pub const union_Foo = extern union { | 2546 | \\pub export fn foo() void { |
| 1574 | \\ x: c_int, | 2547 | \\ var a: c_int = 2; |
| 1575 | \\ y: f64, | 2548 | \\ while (true) { |
| 1576 | \\}; | 2549 | \\ a -= 1; |
| 1577 | , | 2550 | \\ if (!(a != 0)) break; |
| 1578 | \\pub const Foo = union_Foo; | 2551 | \\ } |
| 2552 | \\ var b: c_int = 2; | ||
| 2553 | \\ while (true) { | ||
| 2554 | \\ b -= 1; | ||
| 2555 | \\ if (!(b != 0)) break; | ||
| 2556 | \\ } | ||
| 2557 | \\} | ||
| 1579 | }); | 2558 | }); |
| 1580 | 2559 | ||
| 1581 | cases.add("address of operator", | 2560 | cases.addC("==, !=", |
| 1582 | \\int foo(void) { | 2561 | \\int max(int a, int b) { |
| 1583 | \\ int x = 1234; | 2562 | \\ if (a == b) |
| 1584 | \\ int *ptr = &x; | 2563 | \\ return a; |
| 1585 | \\ return *ptr; | 2564 | \\ if (a != b) |
| 2565 | \\ return b; | ||
| 2566 | \\ return a; | ||
| 1586 | \\} | 2567 | \\} |
| 1587 | , &[_][]const u8{ | 2568 | , &[_][]const u8{ |
| 1588 | \\pub fn foo() c_int { | 2569 | \\pub export fn max(a: c_int, b: c_int) c_int { |
| 1589 | \\ var x: c_int = 1234; | 2570 | \\ if (a == b) return a; |
| 1590 | \\ var ptr: [*c]c_int = &x; | 2571 | \\ if (a != b) return b; |
| 1591 | \\ return ptr.?.*; | 2572 | \\ return a; |
| 1592 | \\} | 2573 | \\} |
| 1593 | }); | 2574 | }); |
| 1594 | 2575 | ||
| 1595 | cases.add("string literal", | 2576 | cases.addC("bitwise binary operators", |
| 1596 | \\const char *foo(void) { | 2577 | \\int max(int a, int b) { |
| 1597 | \\ return "bar"; | 2578 | \\ return (a & b) ^ (a | b); |
| 1598 | \\} | 2579 | \\} |
| 1599 | , &[_][]const u8{ | 2580 | , &[_][]const u8{ |
| 1600 | \\pub fn foo() [*c]const u8 { | 2581 | \\pub export fn max(a: c_int, b: c_int) c_int { |
| 1601 | \\ return "bar"; | 2582 | \\ return (a & b) ^ (a | b); |
| 1602 | \\} | 2583 | \\} |
| 1603 | }); | 2584 | }); |
| 1604 | 2585 | ||
| 1605 | cases.add("return void", | 2586 | cases.addC("statement expression", |
| 1606 | \\void foo(void) { | 2587 | \\int foo(void) { |
| 1607 | \\ return; | 2588 | \\ return ({ |
| 2589 | \\ int a = 1; | ||
| 2590 | \\ a; | ||
| 2591 | \\ }); | ||
| 1608 | \\} | 2592 | \\} |
| 1609 | , &[_][]const u8{ | 2593 | , &[_][]const u8{ |
| 1610 | \\pub fn foo() void { | 2594 | \\pub export fn foo() c_int { |
| 1611 | \\ return; | 2595 | \\ return x: { |
| 2596 | \\ var a: c_int = 1; | ||
| 2597 | \\ break :x a; | ||
| 2598 | \\ }; | ||
| 1612 | \\} | 2599 | \\} |
| 1613 | }); | 2600 | }); |
| 1614 | 2601 | ||
| 1615 | cases.add("for loop", | 2602 | cases.addC("field access expression", |
| 1616 | \\void foo(void) { | 2603 | \\struct Foo { |
| 1617 | \\ for (int i = 0; i < 10; i += 1) { } | 2604 | \\ int field; |
| 2605 | \\}; | ||
| 2606 | \\int read_field(struct Foo *foo) { | ||
| 2607 | \\ return foo->field; | ||
| 1618 | \\} | 2608 | \\} |
| 1619 | , &[_][]const u8{ | 2609 | , &[_][]const u8{ |
| 1620 | \\pub fn foo() void { | 2610 | \\pub const struct_Foo = extern struct { |
| 1621 | \\ { | 2611 | \\ field: c_int, |
| 1622 | \\ var i: c_int = 0; | 2612 | \\}; |
| 1623 | \\ while (i < 10) : (i += 1) {} | 2613 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { |
| 1624 | \\ } | 2614 | \\ return foo.*.field; |
| 1625 | \\} | 2615 | \\} |
| 1626 | }); | 2616 | }); |
| 1627 | 2617 | ||
| 1628 | cases.add("empty for loop", | 2618 | cases.addC("array access", |
| 1629 | \\void foo(void) { | 2619 | \\int array[100]; |
| 1630 | \\ for (;;) { } | 2620 | \\int foo(int index) { |
| 2621 | \\ return array[index]; | ||
| 1631 | \\} | 2622 | \\} |
| 1632 | , &[_][]const u8{ | 2623 | , &[_][]const u8{ |
| 1633 | \\pub fn foo() void { | 2624 | \\pub var array: [100]c_int = undefined; |
| 1634 | \\ while (true) {} | 2625 | \\pub export fn foo(index: c_int) c_int { |
| 2626 | \\ return array[index]; | ||
| 1635 | \\} | 2627 | \\} |
| 1636 | }); | 2628 | }); |
| 1637 | 2629 | ||
| 1638 | cases.add("break statement", | 2630 | cases.addC("logical and, logical or", |
| 1639 | \\void foo(void) { | 2631 | \\int max(int a, int b) { |
| 1640 | \\ for (;;) { | 2632 | \\ if (a < b || a == b) |
| 1641 | \\ break; | 2633 | \\ return b; |
| 1642 | \\ } | 2634 | \\ if (a >= b && a == b) |
| 2635 | \\ return a; | ||
| 2636 | \\ return a; | ||
| 1643 | \\} | 2637 | \\} |
| 1644 | , &[_][]const u8{ | 2638 | , &[_][]const u8{ |
| 1645 | \\pub fn foo() void { | 2639 | \\pub export fn max(a: c_int, b: c_int) c_int { |
| 1646 | \\ while (true) { | 2640 | \\ if ((a < b) or (a == b)) return b; |
| 1647 | \\ break; | 2641 | \\ if ((a >= b) and (a == b)) return a; |
| 1648 | \\ } | 2642 | \\ return a; |
| 1649 | \\} | 2643 | \\} |
| 1650 | }); | 2644 | }); |
| 1651 | 2645 | ||
| 1652 | cases.add("continue statement", | 2646 | cases.addC("if statement", |
| 1653 | \\void foo(void) { | 2647 | \\int max(int a, int b) { |
| 1654 | \\ for (;;) { | 2648 | \\ if (a < b) |
| 1655 | \\ continue; | 2649 | \\ return b; |
| 1656 | \\ } | 2650 | \\ |
| 2651 | \\ if (a < b) | ||
| 2652 | \\ return b; | ||
| 2653 | \\ else | ||
| 2654 | \\ return a; | ||
| 2655 | \\ | ||
| 2656 | \\ if (a < b) ; else ; | ||
| 1657 | \\} | 2657 | \\} |
| 1658 | , &[_][]const u8{ | 2658 | , &[_][]const u8{ |
| 1659 | \\pub fn foo() void { | 2659 | \\pub export fn max(a: c_int, b: c_int) c_int { |
| 1660 | \\ while (true) { | 2660 | \\ if (a < b) return b; |
| 1661 | \\ continue; | 2661 | \\ if (a < b) return b else return a; |
| 1662 | \\ } | 2662 | \\ if (a < b) {} else {} |
| 1663 | \\} | 2663 | \\} |
| 1664 | }); | 2664 | }); |
| 1665 | 2665 | ||
| ... | @@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1683,150 +2683,353 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1683 | \\} | 2683 | \\} |
| 1684 | }); | 2684 | }); |
| 1685 | 2685 | ||
| 1686 | cases.add("pointer casting", | 2686 | cases.add("if on non-bool", |
| 1687 | \\float *ptrcast(int *a) { | 2687 | \\enum SomeEnum { A, B, C }; |
| 1688 | \\ return (float *)a; | 2688 | \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { |
| 2689 | \\ if (a) return 0; | ||
| 2690 | \\ if (b) return 1; | ||
| 2691 | \\ if (c) return 2; | ||
| 2692 | \\ if (d) return 3; | ||
| 2693 | \\ return 4; | ||
| 1689 | \\} | 2694 | \\} |
| 1690 | , &[_][]const u8{ | 2695 | , &[_][]const u8{ |
| 1691 | \\fn ptrcast(a: [*c]c_int) [*c]f32 { | 2696 | \\pub const A = enum_SomeEnum.A; |
| 1692 | \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); | 2697 | \\pub const B = enum_SomeEnum.B; |
| 2698 | \\pub const C = enum_SomeEnum.C; | ||
| 2699 | \\pub const enum_SomeEnum = extern enum { | ||
| 2700 | \\ A, | ||
| 2701 | \\ B, | ||
| 2702 | \\ C, | ||
| 2703 | \\}; | ||
| 2704 | \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { | ||
| 2705 | \\ if (a != 0) return 0; | ||
| 2706 | \\ if (b != 0) return 1; | ||
| 2707 | \\ if (c != null) return 2; | ||
| 2708 | \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3; | ||
| 2709 | \\ return 4; | ||
| 1693 | \\} | 2710 | \\} |
| 1694 | }); | 2711 | }); |
| 1695 | 2712 | ||
| 1696 | cases.add("bin not", | 2713 | cases.addAllowWarnings("simple data types", |
| 1697 | \\int foo(int x) { | 2714 | \\#include <stdint.h> |
| 1698 | \\ return ~x; | 2715 | \\int foo(char a, unsigned char b, signed char c); |
| 2716 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | ||
| 2717 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | ||
| 2718 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | ||
| 2719 | , &[_][]const u8{ | ||
| 2720 | \\pub extern fn foo(a: u8, b: u8, c: i8) c_int; | ||
| 2721 | , | ||
| 2722 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void; | ||
| 2723 | , | ||
| 2724 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; | ||
| 2725 | }); | ||
| 2726 | |||
| 2727 | cases.addC("simple function", | ||
| 2728 | \\int abs(int a) { | ||
| 2729 | \\ return a < 0 ? -a : a; | ||
| 1699 | \\} | 2730 | \\} |
| 1700 | , &[_][]const u8{ | 2731 | , &[_][]const u8{ |
| 1701 | \\pub fn foo(x: c_int) c_int { | 2732 | \\pub export fn abs(a: c_int) c_int { |
| 1702 | \\ return ~x; | 2733 | \\ return if (a < 0) -a else a; |
| 1703 | \\} | 2734 | \\} |
| 1704 | }); | 2735 | }); |
| 1705 | 2736 | ||
| 1706 | cases.add("bool not", | 2737 | cases.addC("post increment", |
| 1707 | \\int foo(int a, float b, void *c) { | 2738 | \\unsigned foo1(unsigned a) { |
| 1708 | \\ return !(a == 0); | 2739 | \\ a++; |
| 1709 | \\ return !a; | 2740 | \\ return a; |
| 1710 | \\ return !b; | 2741 | \\} |
| 1711 | \\ return !c; | 2742 | \\int foo2(int a) { |
| 2743 | \\ a++; | ||
| 2744 | \\ return a; | ||
| 2745 | \\} | ||
| 2746 | , &[_][]const u8{ | ||
| 2747 | \\pub export fn foo1(_arg_a: c_uint) c_uint { | ||
| 2748 | \\ var a = _arg_a; | ||
| 2749 | \\ a +%= 1; | ||
| 2750 | \\ return a; | ||
| 2751 | \\} | ||
| 2752 | \\pub export fn foo2(_arg_a: c_int) c_int { | ||
| 2753 | \\ var a = _arg_a; | ||
| 2754 | \\ a += 1; | ||
| 2755 | \\ return a; | ||
| 2756 | \\} | ||
| 2757 | }); | ||
| 2758 | |||
| 2759 | cases.addC("deref function pointer", | ||
| 2760 | \\void foo(void) {} | ||
| 2761 | \\int baz(void) { return 0; } | ||
| 2762 | \\void bar(void) { | ||
| 2763 | \\ void(*f)(void) = foo; | ||
| 2764 | \\ int(*b)(void) = baz; | ||
| 2765 | \\ f(); | ||
| 2766 | \\ (*(f))(); | ||
| 2767 | \\ foo(); | ||
| 2768 | \\ b(); | ||
| 2769 | \\ (*(b))(); | ||
| 2770 | \\ baz(); | ||
| 2771 | \\} | ||
| 2772 | , &[_][]const u8{ | ||
| 2773 | \\pub export fn foo() void {} | ||
| 2774 | \\pub export fn baz() c_int { | ||
| 2775 | \\ return 0; | ||
| 2776 | \\} | ||
| 2777 | \\pub export fn bar() void { | ||
| 2778 | \\ var f: ?extern fn () void = foo; | ||
| 2779 | \\ var b: ?extern fn () c_int = baz; | ||
| 2780 | \\ f.?(); | ||
| 2781 | \\ f.?(); | ||
| 2782 | \\ foo(); | ||
| 2783 | \\ _ = b.?(); | ||
| 2784 | \\ _ = b.?(); | ||
| 2785 | \\ _ = baz(); | ||
| 2786 | \\} | ||
| 2787 | }); | ||
| 2788 | |||
| 2789 | cases.addC("pre increment/decrement", | ||
| 2790 | \\void foo(void) { | ||
| 2791 | \\ int i = 0; | ||
| 2792 | \\ unsigned u = 0; | ||
| 2793 | \\ ++i; | ||
| 2794 | \\ --i; | ||
| 2795 | \\ ++u; | ||
| 2796 | \\ --u; | ||
| 2797 | \\ i = ++i; | ||
| 2798 | \\ i = --i; | ||
| 2799 | \\ u = ++u; | ||
| 2800 | \\ u = --u; | ||
| 1712 | \\} | 2801 | \\} |
| 1713 | , &[_][]const u8{ | 2802 | , &[_][]const u8{ |
| 1714 | \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int { | 2803 | \\pub export fn foo() void { |
| 1715 | \\ return !(a == 0); | 2804 | \\ var i: c_int = 0; |
| 1716 | \\ return !(a != 0); | 2805 | \\ var u: c_uint = @as(c_uint, 0); |
| 1717 | \\ return !(b != 0); | 2806 | \\ i += 1; |
| 1718 | \\ return !(c != null); | 2807 | \\ i -= 1; |
| 2808 | \\ u +%= 1; | ||
| 2809 | \\ u -%= 1; | ||
| 2810 | \\ i = (x: { | ||
| 2811 | \\ const _ref = &i; | ||
| 2812 | \\ _ref.* += 1; | ||
| 2813 | \\ break :x _ref.*; | ||
| 2814 | \\ }); | ||
| 2815 | \\ i = (x: { | ||
| 2816 | \\ const _ref = &i; | ||
| 2817 | \\ _ref.* -= 1; | ||
| 2818 | \\ break :x _ref.*; | ||
| 2819 | \\ }); | ||
| 2820 | \\ u = (x: { | ||
| 2821 | \\ const _ref = &u; | ||
| 2822 | \\ _ref.* +%= 1; | ||
| 2823 | \\ break :x _ref.*; | ||
| 2824 | \\ }); | ||
| 2825 | \\ u = (x: { | ||
| 2826 | \\ const _ref = &u; | ||
| 2827 | \\ _ref.* -%= 1; | ||
| 2828 | \\ break :x _ref.*; | ||
| 2829 | \\ }); | ||
| 1719 | \\} | 2830 | \\} |
| 1720 | }); | 2831 | }); |
| 1721 | 2832 | ||
| 1722 | cases.add("primitive types included in defined symbols", | 2833 | cases.addC("shift right assign", |
| 1723 | \\int foo(int u32) { | 2834 | \\int log2(unsigned a) { |
| 1724 | \\ return u32; | 2835 | \\ int i = 0; |
| 2836 | \\ while (a > 0) { | ||
| 2837 | \\ a >>= 1; | ||
| 2838 | \\ } | ||
| 2839 | \\ return i; | ||
| 1725 | \\} | 2840 | \\} |
| 1726 | , &[_][]const u8{ | 2841 | , &[_][]const u8{ |
| 1727 | \\pub fn foo(u32_0: c_int) c_int { | 2842 | \\pub export fn log2(_arg_a: c_uint) c_int { |
| 1728 | \\ return u32_0; | 2843 | \\ var a = _arg_a; |
| 2844 | \\ var i: c_int = 0; | ||
| 2845 | \\ while (a > @as(c_uint, 0)) { | ||
| 2846 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), 1); | ||
| 2847 | \\ } | ||
| 2848 | \\ return i; | ||
| 1729 | \\} | 2849 | \\} |
| 1730 | }); | 2850 | }); |
| 1731 | 2851 | ||
| 1732 | cases.add("if on non-bool", | 2852 | cases.addC("shift right assign with a fixed size type", |
| 1733 | \\enum SomeEnum { A, B, C }; | 2853 | \\#include <stdint.h> |
| 1734 | \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) { | 2854 | \\int log2(uint32_t a) { |
| 1735 | \\ if (a) return 0; | 2855 | \\ int i = 0; |
| 1736 | \\ if (b) return 1; | 2856 | \\ while (a > 0) { |
| 1737 | \\ if (c) return 2; | 2857 | \\ a >>= 1; |
| 1738 | \\ if (d) return 3; | 2858 | \\ } |
| 1739 | \\ return 4; | 2859 | \\ return i; |
| 1740 | \\} | 2860 | \\} |
| 1741 | , &[_][]const u8{ | 2861 | , &[_][]const u8{ |
| 1742 | \\pub const A = enum_SomeEnum.A; | 2862 | \\pub export fn log2(_arg_a: u32) c_int { |
| 1743 | \\pub const B = enum_SomeEnum.B; | 2863 | \\ var a = _arg_a; |
| 1744 | \\pub const C = enum_SomeEnum.C; | 2864 | \\ var i: c_int = 0; |
| 1745 | \\pub const enum_SomeEnum = extern enum { | 2865 | \\ while (a > @as(c_uint, 0)) { |
| 1746 | \\ A, | 2866 | \\ a >>= @as(u5, 1); |
| 1747 | \\ B, | 2867 | \\ } |
| 1748 | \\ C, | 2868 | \\ return i; |
| 1749 | \\}; | ||
| 1750 | \\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int { | ||
| 1751 | \\ if (a != 0) return 0; | ||
| 1752 | \\ if (b != 0) return 1; | ||
| 1753 | \\ if (c != null) return 2; | ||
| 1754 | \\ if (d != @bitCast(enum_SomeEnum, @as(@TagType(enum_SomeEnum), 0))) return 3; | ||
| 1755 | \\ return 4; | ||
| 1756 | \\} | 2869 | \\} |
| 1757 | }); | 2870 | }); |
| 1758 | 2871 | ||
| 1759 | cases.add("while on non-bool", | 2872 | cases.addC("compound assignment operators", |
| 1760 | \\int while_none_bool(int a, float b, void *c) { | 2873 | \\void foo(void) { |
| 1761 | \\ while (a) return 0; | 2874 | \\ int a = 0; |
| 1762 | \\ while (b) return 1; | 2875 | \\ a += (a += 1); |
| 1763 | \\ while (c) return 2; | 2876 | \\ a -= (a -= 1); |
| 1764 | \\ return 3; | 2877 | \\ a *= (a *= 1); |
| 2878 | \\ a &= (a &= 1); | ||
| 2879 | \\ a |= (a |= 1); | ||
| 2880 | \\ a ^= (a ^= 1); | ||
| 2881 | \\ a >>= (a >>= 1); | ||
| 2882 | \\ a <<= (a <<= 1); | ||
| 1765 | \\} | 2883 | \\} |
| 1766 | , &[_][]const u8{ | 2884 | , &[_][]const u8{ |
| 1767 | \\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | 2885 | \\pub export fn foo() void { |
| 1768 | \\ while (a != 0) return 0; | 2886 | \\ var a: c_int = 0; |
| 1769 | \\ while (b != 0) return 1; | 2887 | \\ a += (x: { |
| 1770 | \\ while (c != null) return 2; | 2888 | \\ const _ref = &a; |
| 1771 | \\ return 3; | 2889 | \\ _ref.* = (_ref.* + 1); |
| 2890 | \\ break :x _ref.*; | ||
| 2891 | \\ }); | ||
| 2892 | \\ a -= (x: { | ||
| 2893 | \\ const _ref = &a; | ||
| 2894 | \\ _ref.* = (_ref.* - 1); | ||
| 2895 | \\ break :x _ref.*; | ||
| 2896 | \\ }); | ||
| 2897 | \\ a *= (x: { | ||
| 2898 | \\ const _ref = &a; | ||
| 2899 | \\ _ref.* = (_ref.* * 1); | ||
| 2900 | \\ break :x _ref.*; | ||
| 2901 | \\ }); | ||
| 2902 | \\ a &= (x: { | ||
| 2903 | \\ const _ref = &a; | ||
| 2904 | \\ _ref.* = (_ref.* & 1); | ||
| 2905 | \\ break :x _ref.*; | ||
| 2906 | \\ }); | ||
| 2907 | \\ a |= (x: { | ||
| 2908 | \\ const _ref = &a; | ||
| 2909 | \\ _ref.* = (_ref.* | 1); | ||
| 2910 | \\ break :x _ref.*; | ||
| 2911 | \\ }); | ||
| 2912 | \\ a ^= (x: { | ||
| 2913 | \\ const _ref = &a; | ||
| 2914 | \\ _ref.* = (_ref.* ^ 1); | ||
| 2915 | \\ break :x _ref.*; | ||
| 2916 | \\ }); | ||
| 2917 | \\ a >>= @as(@import("std").math.Log2Int(c_int), (x: { | ||
| 2918 | \\ const _ref = &a; | ||
| 2919 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1)); | ||
| 2920 | \\ break :x _ref.*; | ||
| 2921 | \\ })); | ||
| 2922 | \\ a <<= @as(@import("std").math.Log2Int(c_int), (x: { | ||
| 2923 | \\ const _ref = &a; | ||
| 2924 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1)); | ||
| 2925 | \\ break :x _ref.*; | ||
| 2926 | \\ })); | ||
| 1772 | \\} | 2927 | \\} |
| 1773 | }); | 2928 | }); |
| 1774 | 2929 | ||
| 1775 | cases.add("for on non-bool", | 2930 | cases.addC("compound assignment operators unsigned", |
| 1776 | \\int for_none_bool(int a, float b, void *c) { | 2931 | \\void foo(void) { |
| 1777 | \\ for (;a;) return 0; | 2932 | \\ unsigned a = 0; |
| 1778 | \\ for (;b;) return 1; | 2933 | \\ a += (a += 1); |
| 1779 | \\ for (;c;) return 2; | 2934 | \\ a -= (a -= 1); |
| 1780 | \\ return 3; | 2935 | \\ a *= (a *= 1); |
| 2936 | \\ a &= (a &= 1); | ||
| 2937 | \\ a |= (a |= 1); | ||
| 2938 | \\ a ^= (a ^= 1); | ||
| 2939 | \\ a >>= (a >>= 1); | ||
| 2940 | \\ a <<= (a <<= 1); | ||
| 1781 | \\} | 2941 | \\} |
| 1782 | , &[_][]const u8{ | 2942 | , &[_][]const u8{ |
| 1783 | \\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int { | 2943 | \\pub export fn foo() void { |
| 1784 | \\ while (a != 0) return 0; | 2944 | \\ var a: c_uint = @as(c_uint, 0); |
| 1785 | \\ while (b != 0) return 1; | 2945 | \\ a +%= (x: { |
| 1786 | \\ while (c != null) return 2; | 2946 | \\ const _ref = &a; |
| 1787 | \\ return 3; | 2947 | \\ _ref.* = (_ref.* +% @as(c_uint, 1)); |
| 2948 | \\ break :x _ref.*; | ||
| 2949 | \\ }); | ||
| 2950 | \\ a -%= (x: { | ||
| 2951 | \\ const _ref = &a; | ||
| 2952 | \\ _ref.* = (_ref.* -% @as(c_uint, 1)); | ||
| 2953 | \\ break :x _ref.*; | ||
| 2954 | \\ }); | ||
| 2955 | \\ a *%= (x: { | ||
| 2956 | \\ const _ref = &a; | ||
| 2957 | \\ _ref.* = (_ref.* *% @as(c_uint, 1)); | ||
| 2958 | \\ break :x _ref.*; | ||
| 2959 | \\ }); | ||
| 2960 | \\ a &= (x: { | ||
| 2961 | \\ const _ref = &a; | ||
| 2962 | \\ _ref.* = (_ref.* & @as(c_uint, 1)); | ||
| 2963 | \\ break :x _ref.*; | ||
| 2964 | \\ }); | ||
| 2965 | \\ a |= (x: { | ||
| 2966 | \\ const _ref = &a; | ||
| 2967 | \\ _ref.* = (_ref.* | @as(c_uint, 1)); | ||
| 2968 | \\ break :x _ref.*; | ||
| 2969 | \\ }); | ||
| 2970 | \\ a ^= (x: { | ||
| 2971 | \\ const _ref = &a; | ||
| 2972 | \\ _ref.* = (_ref.* ^ @as(c_uint, 1)); | ||
| 2973 | \\ break :x _ref.*; | ||
| 2974 | \\ }); | ||
| 2975 | \\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: { | ||
| 2976 | \\ const _ref = &a; | ||
| 2977 | \\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1)); | ||
| 2978 | \\ break :x _ref.*; | ||
| 2979 | \\ })); | ||
| 2980 | \\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: { | ||
| 2981 | \\ const _ref = &a; | ||
| 2982 | \\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1)); | ||
| 2983 | \\ break :x _ref.*; | ||
| 2984 | \\ })); | ||
| 1788 | \\} | 2985 | \\} |
| 1789 | }); | 2986 | }); |
| 1790 | 2987 | ||
| 1791 | cases.add("switch on int", | 2988 | cases.addC("post increment/decrement", |
| 1792 | \\int switch_fn(int i) { | 2989 | \\void foo(void) { |
| 1793 | \\ int res = 0; | 2990 | \\ int i = 0; |
| 1794 | \\ switch (i) { | 2991 | \\ unsigned u = 0; |
| 1795 | \\ case 0: | 2992 | \\ i++; |
| 1796 | \\ res = 1; | 2993 | \\ i--; |
| 1797 | \\ case 1: | 2994 | \\ u++; |
| 1798 | \\ res = 2; | 2995 | \\ u--; |
| 1799 | \\ default: | 2996 | \\ i = i++; |
| 1800 | \\ res = 3 * i; | 2997 | \\ i = i--; |
| 1801 | \\ break; | 2998 | \\ u = u++; |
| 1802 | \\ case 2: | 2999 | \\ u = u--; |
| 1803 | \\ res = 5; | ||
| 1804 | \\ } | ||
| 1805 | \\} | 3000 | \\} |
| 1806 | , &[_][]const u8{ | 3001 | , &[_][]const u8{ |
| 1807 | \\pub fn switch_fn(i: c_int) c_int { | 3002 | \\pub export fn foo() void { |
| 1808 | \\ var res: c_int = 0; | 3003 | \\ var i: c_int = 0; |
| 1809 | \\ __switch: { | 3004 | \\ var u: c_uint = @as(c_uint, 0); |
| 1810 | \\ __case_2: { | 3005 | \\ i += 1; |
| 1811 | \\ __default: { | 3006 | \\ i -= 1; |
| 1812 | \\ __case_1: { | 3007 | \\ u +%= 1; |
| 1813 | \\ __case_0: { | 3008 | \\ u -%= 1; |
| 1814 | \\ switch (i) { | 3009 | \\ i = (x: { |
| 1815 | \\ 0 => break :__case_0, | 3010 | \\ const _ref = &i; |
| 1816 | \\ 1 => break :__case_1, | 3011 | \\ const _tmp = _ref.*; |
| 1817 | \\ else => break :__default, | 3012 | \\ _ref.* += 1; |
| 1818 | \\ 2 => break :__case_2, | 3013 | \\ break :x _tmp; |
| 1819 | \\ } | 3014 | \\ }); |
| 1820 | \\ } | 3015 | \\ i = (x: { |
| 1821 | \\ res = 1; | 3016 | \\ const _ref = &i; |
| 1822 | \\ } | 3017 | \\ const _tmp = _ref.*; |
| 1823 | \\ res = 2; | 3018 | \\ _ref.* -= 1; |
| 1824 | \\ } | 3019 | \\ break :x _tmp; |
| 1825 | \\ res = (3 * i); | 3020 | \\ }); |
| 1826 | \\ break :__switch; | 3021 | \\ u = (x: { |
| 1827 | \\ } | 3022 | \\ const _ref = &u; |
| 1828 | \\ res = 5; | 3023 | \\ const _tmp = _ref.*; |
| 1829 | \\ } | 3024 | \\ _ref.* +%= 1; |
| 3025 | \\ break :x _tmp; | ||
| 3026 | \\ }); | ||
| 3027 | \\ u = (x: { | ||
| 3028 | \\ const _ref = &u; | ||
| 3029 | \\ const _tmp = _ref.*; | ||
| 3030 | \\ _ref.* -%= 1; | ||
| 3031 | \\ break :x _tmp; | ||
| 3032 | \\ }); | ||
| 1830 | \\} | 3033 | \\} |
| 1831 | }); | 3034 | }); |
| 1832 | 3035 | ||
| ... | @@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1885,206 +3088,85 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1885 | \\} | 3088 | \\} |
| 1886 | }); | 3089 | }); |
| 1887 | 3090 | ||
| 1888 | cases.addC("pointer conversion with different alignment", | 3091 | cases.addC("function call", |
| 1889 | \\void test_ptr_cast() { | 3092 | \\static void bar(void) { } |
| 1890 | \\ void *p; | 3093 | \\void foo(int *(baz)(void)) { |
| 1891 | \\ { | 3094 | \\ bar(); |
| 1892 | \\ char *to_char = (char *)p; | 3095 | \\ baz(); |
| 1893 | \\ short *to_short = (short *)p; | ||
| 1894 | \\ int *to_int = (int *)p; | ||
| 1895 | \\ long long *to_longlong = (long long *)p; | ||
| 1896 | \\ } | ||
| 1897 | \\ { | ||
| 1898 | \\ char *to_char = p; | ||
| 1899 | \\ short *to_short = p; | ||
| 1900 | \\ int *to_int = p; | ||
| 1901 | \\ long long *to_longlong = p; | ||
| 1902 | \\ } | ||
| 1903 | \\} | ||
| 1904 | , &[_][]const u8{ | ||
| 1905 | \\pub export fn test_ptr_cast() void { | ||
| 1906 | \\ var p: ?*c_void = undefined; | ||
| 1907 | \\ { | ||
| 1908 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | ||
| 1909 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | ||
| 1910 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | ||
| 1911 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | ||
| 1912 | \\ } | ||
| 1913 | \\ { | ||
| 1914 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | ||
| 1915 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | ||
| 1916 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | ||
| 1917 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | ||
| 1918 | \\ } | ||
| 1919 | \\} | ||
| 1920 | }); | ||
| 1921 | |||
| 1922 | cases.addC("escape sequences", | ||
| 1923 | \\const char *escapes() { | ||
| 1924 | \\char a = '\'', | ||
| 1925 | \\ b = '\\', | ||
| 1926 | \\ c = '\a', | ||
| 1927 | \\ d = '\b', | ||
| 1928 | \\ e = '\f', | ||
| 1929 | \\ f = '\n', | ||
| 1930 | \\ g = '\r', | ||
| 1931 | \\ h = '\t', | ||
| 1932 | \\ i = '\v', | ||
| 1933 | \\ j = '\0', | ||
| 1934 | \\ k = '\"'; | ||
| 1935 | \\ return "\'\\\a\b\f\n\r\t\v\0\""; | ||
| 1936 | \\} | 3096 | \\} |
| 1937 | \\ | ||
| 1938 | , &[_][]const u8{ | 3097 | , &[_][]const u8{ |
| 1939 | \\pub export fn escapes() [*c]const u8 { | 3098 | \\pub fn bar() void {} |
| 1940 | \\ var a: u8 = @as(u8, '\''); | 3099 | \\pub export fn foo(baz: ?extern fn () [*c]c_int) void { |
| 1941 | \\ var b: u8 = @as(u8, '\\'); | 3100 | \\ bar(); |
| 1942 | \\ var c: u8 = @as(u8, '\x07'); | 3101 | \\ _ = baz.?(); |
| 1943 | \\ var d: u8 = @as(u8, '\x08'); | ||
| 1944 | \\ var e: u8 = @as(u8, '\x0c'); | ||
| 1945 | \\ var f: u8 = @as(u8, '\n'); | ||
| 1946 | \\ var g: u8 = @as(u8, '\r'); | ||
| 1947 | \\ var h: u8 = @as(u8, '\t'); | ||
| 1948 | \\ var i: u8 = @as(u8, '\x0b'); | ||
| 1949 | \\ var j: u8 = @as(u8, '\x00'); | ||
| 1950 | \\ var k: u8 = @as(u8, '\"'); | ||
| 1951 | \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; | ||
| 1952 | \\} | 3102 | \\} |
| 1953 | \\ | ||
| 1954 | }); | 3103 | }); |
| 1955 | 3104 | ||
| 1956 | if (builtin.os != builtin.Os.windows) { | 3105 | cases.add("macro defines string literal with hex", |
| 1957 | // sysv_abi not currently supported on windows | 3106 | \\#define FOO "aoeu\xab derp" |
| 1958 | cases.add("Macro qualified functions", | 3107 | \\#define FOO2 "aoeu\x0007a derp" |
| 1959 | \\void __attribute__((sysv_abi)) foo(void); | 3108 | \\#define FOO_CHAR '\xfF' |
| 1960 | , &[_][]const u8{ | ||
| 1961 | \\pub extern fn foo() void; | ||
| 1962 | }); | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | /////////////// Cases for only stage1 because stage2 behavior is better //////////////// | ||
| 1966 | cases.addC("Parameterless function prototypes", | ||
| 1967 | \\void foo() {} | ||
| 1968 | \\void bar(void) {} | ||
| 1969 | , &[_][]const u8{ | 3109 | , &[_][]const u8{ |
| 1970 | \\pub export fn foo() void {} | 3110 | \\pub const FOO = "aoeu\xab derp"; |
| 1971 | \\pub export fn bar() void {} | 3111 | , |
| 3112 | \\pub const FOO2 = "aoeuz derp"; | ||
| 3113 | , | ||
| 3114 | \\pub const FOO_CHAR = 255; | ||
| 1972 | }); | 3115 | }); |
| 1973 | 3116 | ||
| 1974 | cases.add("#define a char literal", | 3117 | cases.add("macro defines string literal with octal", |
| 1975 | \\#define A_CHAR 'a' | 3118 | \\#define FOO "aoeu\023 derp" |
| 3119 | \\#define FOO2 "aoeu\0234 derp" | ||
| 3120 | \\#define FOO_CHAR '\077' | ||
| 1976 | , &[_][]const u8{ | 3121 | , &[_][]const u8{ |
| 1977 | \\pub const A_CHAR = 97; | 3122 | \\pub const FOO = "aoeu\x13 derp"; |
| 3123 | , | ||
| 3124 | \\pub const FOO2 = "aoeu\x134 derp"; | ||
| 3125 | , | ||
| 3126 | \\pub const FOO_CHAR = 63; | ||
| 1978 | }); | 3127 | }); |
| 1979 | 3128 | ||
| 1980 | cases.add("generate inline func for #define global extern fn", | 3129 | cases.add("enums", |
| 1981 | \\extern void (*fn_ptr)(void); | 3130 | \\enum Foo { |
| 1982 | \\#define foo fn_ptr | 3131 | \\ FooA, |
| 1983 | \\ | 3132 | \\ FooB, |
| 1984 | \\extern char (*fn_ptr2)(int, float); | 3133 | \\ Foo1, |
| 1985 | \\#define bar fn_ptr2 | 3134 | \\}; |
| 1986 | , &[_][]const u8{ | 3135 | , &[_][]const u8{ |
| 1987 | \\pub extern var fn_ptr: ?extern fn () void; | 3136 | \\pub const enum_Foo = extern enum { |
| 3137 | \\ A, | ||
| 3138 | \\ B, | ||
| 3139 | \\ @"1", | ||
| 3140 | \\}; | ||
| 1988 | , | 3141 | , |
| 1989 | \\pub inline fn foo() void { | 3142 | \\pub const FooA = enum_Foo.A; |
| 1990 | \\ return fn_ptr.?(); | ||
| 1991 | \\} | ||
| 1992 | , | 3143 | , |
| 1993 | \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; | 3144 | \\pub const FooB = enum_Foo.B; |
| 1994 | , | 3145 | , |
| 1995 | \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { | 3146 | \\pub const Foo1 = enum_Foo.@"1"; |
| 1996 | \\ return fn_ptr2.?(arg0, arg1); | 3147 | , |
| 1997 | \\} | 3148 | \\pub const Foo = enum_Foo; |
| 1998 | }); | ||
| 1999 | cases.add("comment after integer literal", | ||
| 2000 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2001 | , &[_][]const u8{ | ||
| 2002 | \\pub const SDL_INIT_VIDEO = 32; | ||
| 2003 | }); | ||
| 2004 | |||
| 2005 | cases.add("u integer suffix after hex literal", | ||
| 2006 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2007 | , &[_][]const u8{ | ||
| 2008 | \\pub const SDL_INIT_VIDEO = @as(c_uint, 32); | ||
| 2009 | }); | ||
| 2010 | |||
| 2011 | cases.add("l integer suffix after hex literal", | ||
| 2012 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2013 | , &[_][]const u8{ | ||
| 2014 | \\pub const SDL_INIT_VIDEO = @as(c_long, 32); | ||
| 2015 | }); | ||
| 2016 | |||
| 2017 | cases.add("ul integer suffix after hex literal", | ||
| 2018 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2019 | , &[_][]const u8{ | ||
| 2020 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | ||
| 2021 | }); | ||
| 2022 | |||
| 2023 | cases.add("lu integer suffix after hex literal", | ||
| 2024 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2025 | , &[_][]const u8{ | ||
| 2026 | \\pub const SDL_INIT_VIDEO = @as(c_ulong, 32); | ||
| 2027 | }); | ||
| 2028 | |||
| 2029 | cases.add("ll integer suffix after hex literal", | ||
| 2030 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2031 | , &[_][]const u8{ | ||
| 2032 | \\pub const SDL_INIT_VIDEO = @as(c_longlong, 32); | ||
| 2033 | }); | ||
| 2034 | |||
| 2035 | cases.add("ull integer suffix after hex literal", | ||
| 2036 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2037 | , &[_][]const u8{ | ||
| 2038 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | ||
| 2039 | }); | ||
| 2040 | |||
| 2041 | cases.add("llu integer suffix after hex literal", | ||
| 2042 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | ||
| 2043 | , &[_][]const u8{ | ||
| 2044 | \\pub const SDL_INIT_VIDEO = @as(c_ulonglong, 32); | ||
| 2045 | }); | 3149 | }); |
| 2046 | 3150 | ||
| 2047 | cases.add("macros with field targets", | 3151 | cases.add("enums", |
| 2048 | \\typedef unsigned int GLbitfield; | 3152 | \\enum Foo { |
| 2049 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | 3153 | \\ FooA = 2, |
| 2050 | \\typedef void(*OpenGLProc)(void); | 3154 | \\ FooB = 5, |
| 2051 | \\union OpenGLProcs { | 3155 | \\ Foo1, |
| 2052 | \\ OpenGLProc ptr[1]; | ||
| 2053 | \\ struct { | ||
| 2054 | \\ PFNGLCLEARPROC Clear; | ||
| 2055 | \\ } gl; | ||
| 2056 | \\}; | 3156 | \\}; |
| 2057 | \\extern union OpenGLProcs glProcs; | ||
| 2058 | \\#define glClearUnion glProcs.gl.Clear | ||
| 2059 | \\#define glClearPFN PFNGLCLEARPROC | ||
| 2060 | , &[_][]const u8{ | 3157 | , &[_][]const u8{ |
| 2061 | \\pub const GLbitfield = c_uint; | 3158 | \\pub const enum_Foo = extern enum { |
| 2062 | , | 3159 | \\ A = 2, |
| 2063 | \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; | 3160 | \\ B = 5, |
| 2064 | , | 3161 | \\ @"1" = 6, |
| 2065 | \\pub const OpenGLProc = ?extern fn () void; | ||
| 2066 | , | ||
| 2067 | \\pub const union_OpenGLProcs = extern union { | ||
| 2068 | \\ ptr: [1]OpenGLProc, | ||
| 2069 | \\ gl: extern struct { | ||
| 2070 | \\ Clear: PFNGLCLEARPROC, | ||
| 2071 | \\ }, | ||
| 2072 | \\}; | 3162 | \\}; |
| 2073 | , | 3163 | , |
| 2074 | \\pub extern var glProcs: union_OpenGLProcs; | 3164 | \\pub const FooA = enum_Foo.A; |
| 2075 | , | 3165 | , |
| 2076 | \\pub const glClearPFN = PFNGLCLEARPROC; | 3166 | \\pub const FooB = enum_Foo.B; |
| 2077 | , | 3167 | , |
| 2078 | \\pub inline fn glClearUnion(arg0: GLbitfield) void { | 3168 | \\pub const Foo1 = enum_Foo.@"1"; |
| 2079 | \\ return glProcs.gl.Clear.?(arg0); | ||
| 2080 | \\} | ||
| 2081 | , | 3169 | , |
| 2082 | \\pub const OpenGLProcs = union_OpenGLProcs; | 3170 | \\pub const Foo = enum_Foo; |
| 2083 | }); | ||
| 2084 | |||
| 2085 | cases.add("macro pointer cast", | ||
| 2086 | \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) | ||
| 2087 | , &[_][]const u8{ | ||
| 2088 | \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); | ||
| 2089 | }); | 3171 | }); |
| 2090 | } | 3172 | } |