| author | |
| committer | |
| log | 74010fecc7bbeaf9de77c28dda5906c3c1f4a6df |
| tree | 52c184214f084bea4a1cd354ab91151cdc43de2b |
| parent | d2a8660d0467c024790c7dcdeb9366d993723fd7 |
9 files changed, 320 insertions(+), 1868 deletions(-)
CMakeLists.txt-1| ... | ... | @@ -218,7 +218,6 @@ set(ZIG_STAGE2_SOURCES |
| 218 | 218 | "${CMAKE_SOURCE_DIR}/lib/std/builtin.zig" |
| 219 | 219 | "${CMAKE_SOURCE_DIR}/lib/std/c.zig" |
| 220 | 220 | "${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig" |
| 221 | "${CMAKE_SOURCE_DIR}/lib/std/c/tokenizer.zig" | |
| 222 | 221 | "${CMAKE_SOURCE_DIR}/lib/std/child_process.zig" |
| 223 | 222 | "${CMAKE_SOURCE_DIR}/lib/std/coff.zig" |
| 224 | 223 | "${CMAKE_SOURCE_DIR}/lib/std/comptime_string_map.zig" |
lib/std/c.zig-8| ... | ... | @@ -5,14 +5,6 @@ const page_size = std.mem.page_size; |
| 5 | 5 | const iovec = std.os.iovec; |
| 6 | 6 | const iovec_const = std.os.iovec_const; |
| 7 | 7 | |
| 8 | test { | |
| 9 | _ = tokenizer; | |
| 10 | } | |
| 11 | ||
| 12 | pub const tokenizer = @import("c/tokenizer.zig"); | |
| 13 | pub const Token = tokenizer.Token; | |
| 14 | pub const Tokenizer = tokenizer.Tokenizer; | |
| 15 | ||
| 16 | 8 | /// The return type is `type` to force comptime function call execution. |
| 17 | 9 | /// TODO: https://github.com/ziglang/zig/issues/425 |
| 18 | 10 | /// If not linking libc, returns struct{pub const ok = false;} |
lib/std/c/tokenizer.zig deleted-1585| ... | ... | @@ -1,1585 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub const Token = struct { | |
| 4 | id: Id, | |
| 5 | start: usize, | |
| 6 | end: usize, | |
| 7 | ||
| 8 | pub const Id = union(enum) { | |
| 9 | Invalid, | |
| 10 | Eof, | |
| 11 | Nl, | |
| 12 | Identifier, | |
| 13 | ||
| 14 | /// special case for #include <...> | |
| 15 | MacroString, | |
| 16 | StringLiteral: StrKind, | |
| 17 | CharLiteral: StrKind, | |
| 18 | IntegerLiteral: NumSuffix, | |
| 19 | FloatLiteral: NumSuffix, | |
| 20 | Bang, | |
| 21 | BangEqual, | |
| 22 | Pipe, | |
| 23 | PipePipe, | |
| 24 | PipeEqual, | |
| 25 | Equal, | |
| 26 | EqualEqual, | |
| 27 | LParen, | |
| 28 | RParen, | |
| 29 | LBrace, | |
| 30 | RBrace, | |
| 31 | LBracket, | |
| 32 | RBracket, | |
| 33 | Period, | |
| 34 | Ellipsis, | |
| 35 | Caret, | |
| 36 | CaretEqual, | |
| 37 | Plus, | |
| 38 | PlusPlus, | |
| 39 | PlusEqual, | |
| 40 | Minus, | |
| 41 | MinusMinus, | |
| 42 | MinusEqual, | |
| 43 | Asterisk, | |
| 44 | AsteriskEqual, | |
| 45 | Percent, | |
| 46 | PercentEqual, | |
| 47 | Arrow, | |
| 48 | Colon, | |
| 49 | Semicolon, | |
| 50 | Slash, | |
| 51 | SlashEqual, | |
| 52 | Comma, | |
| 53 | Ampersand, | |
| 54 | AmpersandAmpersand, | |
| 55 | AmpersandEqual, | |
| 56 | QuestionMark, | |
| 57 | AngleBracketLeft, | |
| 58 | AngleBracketLeftEqual, | |
| 59 | AngleBracketAngleBracketLeft, | |
| 60 | AngleBracketAngleBracketLeftEqual, | |
| 61 | AngleBracketRight, | |
| 62 | AngleBracketRightEqual, | |
| 63 | AngleBracketAngleBracketRight, | |
| 64 | AngleBracketAngleBracketRightEqual, | |
| 65 | Tilde, | |
| 66 | LineComment, | |
| 67 | MultiLineComment, | |
| 68 | Hash, | |
| 69 | HashHash, | |
| 70 | ||
| 71 | Keyword_auto, | |
| 72 | Keyword_break, | |
| 73 | Keyword_case, | |
| 74 | Keyword_char, | |
| 75 | Keyword_const, | |
| 76 | Keyword_continue, | |
| 77 | Keyword_default, | |
| 78 | Keyword_do, | |
| 79 | Keyword_double, | |
| 80 | Keyword_else, | |
| 81 | Keyword_enum, | |
| 82 | Keyword_extern, | |
| 83 | Keyword_float, | |
| 84 | Keyword_for, | |
| 85 | Keyword_goto, | |
| 86 | Keyword_if, | |
| 87 | Keyword_int, | |
| 88 | Keyword_long, | |
| 89 | Keyword_register, | |
| 90 | Keyword_return, | |
| 91 | Keyword_short, | |
| 92 | Keyword_signed, | |
| 93 | Keyword_sizeof, | |
| 94 | Keyword_static, | |
| 95 | Keyword_struct, | |
| 96 | Keyword_switch, | |
| 97 | Keyword_typedef, | |
| 98 | Keyword_union, | |
| 99 | Keyword_unsigned, | |
| 100 | Keyword_void, | |
| 101 | Keyword_volatile, | |
| 102 | Keyword_while, | |
| 103 | ||
| 104 | // ISO C99 | |
| 105 | Keyword_bool, | |
| 106 | Keyword_complex, | |
| 107 | Keyword_imaginary, | |
| 108 | Keyword_inline, | |
| 109 | Keyword_restrict, | |
| 110 | ||
| 111 | // ISO C11 | |
| 112 | Keyword_alignas, | |
| 113 | Keyword_alignof, | |
| 114 | Keyword_atomic, | |
| 115 | Keyword_generic, | |
| 116 | Keyword_noreturn, | |
| 117 | Keyword_static_assert, | |
| 118 | Keyword_thread_local, | |
| 119 | ||
| 120 | // Preprocessor directives | |
| 121 | Keyword_include, | |
| 122 | Keyword_define, | |
| 123 | Keyword_ifdef, | |
| 124 | Keyword_ifndef, | |
| 125 | Keyword_error, | |
| 126 | Keyword_pragma, | |
| 127 | ||
| 128 | pub fn symbol(id: Id) []const u8 { | |
| 129 | return symbolName(id); | |
| 130 | } | |
| 131 | ||
| 132 | pub fn symbolName(id: std.meta.Tag(Id)) []const u8 { | |
| 133 | return switch (id) { | |
| 134 | .Invalid => "Invalid", | |
| 135 | .Eof => "Eof", | |
| 136 | .Nl => "NewLine", | |
| 137 | .Identifier => "Identifier", | |
| 138 | .MacroString => "MacroString", | |
| 139 | .StringLiteral => "StringLiteral", | |
| 140 | .CharLiteral => "CharLiteral", | |
| 141 | .IntegerLiteral => "IntegerLiteral", | |
| 142 | .FloatLiteral => "FloatLiteral", | |
| 143 | .LineComment => "LineComment", | |
| 144 | .MultiLineComment => "MultiLineComment", | |
| 145 | ||
| 146 | .Bang => "!", | |
| 147 | .BangEqual => "!=", | |
| 148 | .Pipe => "|", | |
| 149 | .PipePipe => "||", | |
| 150 | .PipeEqual => "|=", | |
| 151 | .Equal => "=", | |
| 152 | .EqualEqual => "==", | |
| 153 | .LParen => "(", | |
| 154 | .RParen => ")", | |
| 155 | .LBrace => "{", | |
| 156 | .RBrace => "}", | |
| 157 | .LBracket => "[", | |
| 158 | .RBracket => "]", | |
| 159 | .Period => ".", | |
| 160 | .Ellipsis => "...", | |
| 161 | .Caret => "^", | |
| 162 | .CaretEqual => "^=", | |
| 163 | .Plus => "+", | |
| 164 | .PlusPlus => "++", | |
| 165 | .PlusEqual => "+=", | |
| 166 | .Minus => "-", | |
| 167 | .MinusMinus => "--", | |
| 168 | .MinusEqual => "-=", | |
| 169 | .Asterisk => "*", | |
| 170 | .AsteriskEqual => "*=", | |
| 171 | .Percent => "%", | |
| 172 | .PercentEqual => "%=", | |
| 173 | .Arrow => "->", | |
| 174 | .Colon => ":", | |
| 175 | .Semicolon => ";", | |
| 176 | .Slash => "/", | |
| 177 | .SlashEqual => "/=", | |
| 178 | .Comma => ",", | |
| 179 | .Ampersand => "&", | |
| 180 | .AmpersandAmpersand => "&&", | |
| 181 | .AmpersandEqual => "&=", | |
| 182 | .QuestionMark => "?", | |
| 183 | .AngleBracketLeft => "<", | |
| 184 | .AngleBracketLeftEqual => "<=", | |
| 185 | .AngleBracketAngleBracketLeft => "<<", | |
| 186 | .AngleBracketAngleBracketLeftEqual => "<<=", | |
| 187 | .AngleBracketRight => ">", | |
| 188 | .AngleBracketRightEqual => ">=", | |
| 189 | .AngleBracketAngleBracketRight => ">>", | |
| 190 | .AngleBracketAngleBracketRightEqual => ">>=", | |
| 191 | .Tilde => "~", | |
| 192 | .Hash => "#", | |
| 193 | .HashHash => "##", | |
| 194 | .Keyword_auto => "auto", | |
| 195 | .Keyword_break => "break", | |
| 196 | .Keyword_case => "case", | |
| 197 | .Keyword_char => "char", | |
| 198 | .Keyword_const => "const", | |
| 199 | .Keyword_continue => "continue", | |
| 200 | .Keyword_default => "default", | |
| 201 | .Keyword_do => "do", | |
| 202 | .Keyword_double => "double", | |
| 203 | .Keyword_else => "else", | |
| 204 | .Keyword_enum => "enum", | |
| 205 | .Keyword_extern => "extern", | |
| 206 | .Keyword_float => "float", | |
| 207 | .Keyword_for => "for", | |
| 208 | .Keyword_goto => "goto", | |
| 209 | .Keyword_if => "if", | |
| 210 | .Keyword_int => "int", | |
| 211 | .Keyword_long => "long", | |
| 212 | .Keyword_register => "register", | |
| 213 | .Keyword_return => "return", | |
| 214 | .Keyword_short => "short", | |
| 215 | .Keyword_signed => "signed", | |
| 216 | .Keyword_sizeof => "sizeof", | |
| 217 | .Keyword_static => "static", | |
| 218 | .Keyword_struct => "struct", | |
| 219 | .Keyword_switch => "switch", | |
| 220 | .Keyword_typedef => "typedef", | |
| 221 | .Keyword_union => "union", | |
| 222 | .Keyword_unsigned => "unsigned", | |
| 223 | .Keyword_void => "void", | |
| 224 | .Keyword_volatile => "volatile", | |
| 225 | .Keyword_while => "while", | |
| 226 | .Keyword_bool => "_Bool", | |
| 227 | .Keyword_complex => "_Complex", | |
| 228 | .Keyword_imaginary => "_Imaginary", | |
| 229 | .Keyword_inline => "inline", | |
| 230 | .Keyword_restrict => "restrict", | |
| 231 | .Keyword_alignas => "_Alignas", | |
| 232 | .Keyword_alignof => "_Alignof", | |
| 233 | .Keyword_atomic => "_Atomic", | |
| 234 | .Keyword_generic => "_Generic", | |
| 235 | .Keyword_noreturn => "_Noreturn", | |
| 236 | .Keyword_static_assert => "_Static_assert", | |
| 237 | .Keyword_thread_local => "_Thread_local", | |
| 238 | .Keyword_include => "include", | |
| 239 | .Keyword_define => "define", | |
| 240 | .Keyword_ifdef => "ifdef", | |
| 241 | .Keyword_ifndef => "ifndef", | |
| 242 | .Keyword_error => "error", | |
| 243 | .Keyword_pragma => "pragma", | |
| 244 | }; | |
| 245 | } | |
| 246 | }; | |
| 247 | ||
| 248 | // TODO extensions | |
| 249 | pub const keywords = std.ComptimeStringMap(Id, .{ | |
| 250 | .{ "auto", .Keyword_auto }, | |
| 251 | .{ "break", .Keyword_break }, | |
| 252 | .{ "case", .Keyword_case }, | |
| 253 | .{ "char", .Keyword_char }, | |
| 254 | .{ "const", .Keyword_const }, | |
| 255 | .{ "continue", .Keyword_continue }, | |
| 256 | .{ "default", .Keyword_default }, | |
| 257 | .{ "do", .Keyword_do }, | |
| 258 | .{ "double", .Keyword_double }, | |
| 259 | .{ "else", .Keyword_else }, | |
| 260 | .{ "enum", .Keyword_enum }, | |
| 261 | .{ "extern", .Keyword_extern }, | |
| 262 | .{ "float", .Keyword_float }, | |
| 263 | .{ "for", .Keyword_for }, | |
| 264 | .{ "goto", .Keyword_goto }, | |
| 265 | .{ "if", .Keyword_if }, | |
| 266 | .{ "int", .Keyword_int }, | |
| 267 | .{ "long", .Keyword_long }, | |
| 268 | .{ "register", .Keyword_register }, | |
| 269 | .{ "return", .Keyword_return }, | |
| 270 | .{ "short", .Keyword_short }, | |
| 271 | .{ "signed", .Keyword_signed }, | |
| 272 | .{ "sizeof", .Keyword_sizeof }, | |
| 273 | .{ "static", .Keyword_static }, | |
| 274 | .{ "struct", .Keyword_struct }, | |
| 275 | .{ "switch", .Keyword_switch }, | |
| 276 | .{ "typedef", .Keyword_typedef }, | |
| 277 | .{ "union", .Keyword_union }, | |
| 278 | .{ "unsigned", .Keyword_unsigned }, | |
| 279 | .{ "void", .Keyword_void }, | |
| 280 | .{ "volatile", .Keyword_volatile }, | |
| 281 | .{ "while", .Keyword_while }, | |
| 282 | ||
| 283 | // ISO C99 | |
| 284 | .{ "_Bool", .Keyword_bool }, | |
| 285 | .{ "_Complex", .Keyword_complex }, | |
| 286 | .{ "_Imaginary", .Keyword_imaginary }, | |
| 287 | .{ "inline", .Keyword_inline }, | |
| 288 | .{ "restrict", .Keyword_restrict }, | |
| 289 | ||
| 290 | // ISO C11 | |
| 291 | .{ "_Alignas", .Keyword_alignas }, | |
| 292 | .{ "_Alignof", .Keyword_alignof }, | |
| 293 | .{ "_Atomic", .Keyword_atomic }, | |
| 294 | .{ "_Generic", .Keyword_generic }, | |
| 295 | .{ "_Noreturn", .Keyword_noreturn }, | |
| 296 | .{ "_Static_assert", .Keyword_static_assert }, | |
| 297 | .{ "_Thread_local", .Keyword_thread_local }, | |
| 298 | ||
| 299 | // Preprocessor directives | |
| 300 | .{ "include", .Keyword_include }, | |
| 301 | .{ "define", .Keyword_define }, | |
| 302 | .{ "ifdef", .Keyword_ifdef }, | |
| 303 | .{ "ifndef", .Keyword_ifndef }, | |
| 304 | .{ "error", .Keyword_error }, | |
| 305 | .{ "pragma", .Keyword_pragma }, | |
| 306 | }); | |
| 307 | ||
| 308 | // TODO do this in the preprocessor | |
| 309 | pub fn getKeyword(bytes: []const u8, pp_directive: bool) ?Id { | |
| 310 | if (keywords.get(bytes)) |id| { | |
| 311 | switch (id) { | |
| 312 | .Keyword_include, | |
| 313 | .Keyword_define, | |
| 314 | .Keyword_ifdef, | |
| 315 | .Keyword_ifndef, | |
| 316 | .Keyword_error, | |
| 317 | .Keyword_pragma, | |
| 318 | => if (!pp_directive) return null, | |
| 319 | else => {}, | |
| 320 | } | |
| 321 | return id; | |
| 322 | } | |
| 323 | return null; | |
| 324 | } | |
| 325 | ||
| 326 | pub const NumSuffix = enum { | |
| 327 | none, | |
| 328 | f, | |
| 329 | l, | |
| 330 | u, | |
| 331 | lu, | |
| 332 | ll, | |
| 333 | llu, | |
| 334 | }; | |
| 335 | ||
| 336 | pub const StrKind = enum { | |
| 337 | none, | |
| 338 | wide, | |
| 339 | utf_8, | |
| 340 | utf_16, | |
| 341 | utf_32, | |
| 342 | }; | |
| 343 | }; | |
| 344 | ||
| 345 | pub const Tokenizer = struct { | |
| 346 | buffer: []const u8, | |
| 347 | index: usize = 0, | |
| 348 | prev_tok_id: std.meta.Tag(Token.Id) = .Invalid, | |
| 349 | pp_directive: bool = false, | |
| 350 | ||
| 351 | pub fn next(self: *Tokenizer) Token { | |
| 352 | var result = Token{ | |
| 353 | .id = .Eof, | |
| 354 | .start = self.index, | |
| 355 | .end = undefined, | |
| 356 | }; | |
| 357 | var state: enum { | |
| 358 | Start, | |
| 359 | Cr, | |
| 360 | BackSlash, | |
| 361 | BackSlashCr, | |
| 362 | u, | |
| 363 | u8, | |
| 364 | U, | |
| 365 | L, | |
| 366 | StringLiteral, | |
| 367 | CharLiteralStart, | |
| 368 | CharLiteral, | |
| 369 | EscapeSequence, | |
| 370 | CrEscape, | |
| 371 | OctalEscape, | |
| 372 | HexEscape, | |
| 373 | UnicodeEscape, | |
| 374 | Identifier, | |
| 375 | Equal, | |
| 376 | Bang, | |
| 377 | Pipe, | |
| 378 | Percent, | |
| 379 | Asterisk, | |
| 380 | Plus, | |
| 381 | ||
| 382 | /// special case for #include <...> | |
| 383 | MacroString, | |
| 384 | AngleBracketLeft, | |
| 385 | AngleBracketAngleBracketLeft, | |
| 386 | AngleBracketRight, | |
| 387 | AngleBracketAngleBracketRight, | |
| 388 | Caret, | |
| 389 | Period, | |
| 390 | Period2, | |
| 391 | Minus, | |
| 392 | Slash, | |
| 393 | Ampersand, | |
| 394 | Hash, | |
| 395 | LineComment, | |
| 396 | MultiLineComment, | |
| 397 | MultiLineCommentAsterisk, | |
| 398 | Zero, | |
| 399 | IntegerLiteralOct, | |
| 400 | IntegerLiteralBinary, | |
| 401 | IntegerLiteralBinaryFirst, | |
| 402 | IntegerLiteralHex, | |
| 403 | IntegerLiteralHexFirst, | |
| 404 | IntegerLiteral, | |
| 405 | IntegerSuffix, | |
| 406 | IntegerSuffixU, | |
| 407 | IntegerSuffixL, | |
| 408 | IntegerSuffixLL, | |
| 409 | IntegerSuffixUL, | |
| 410 | FloatFraction, | |
| 411 | FloatFractionHex, | |
| 412 | FloatExponent, | |
| 413 | FloatExponentDigits, | |
| 414 | FloatSuffix, | |
| 415 | } = .Start; | |
| 416 | var string = false; | |
| 417 | var counter: u32 = 0; | |
| 418 | while (self.index < self.buffer.len) : (self.index += 1) { | |
| 419 | const c = self.buffer[self.index]; | |
| 420 | switch (state) { | |
| 421 | .Start => switch (c) { | |
| 422 | '\n' => { | |
| 423 | self.pp_directive = false; | |
| 424 | result.id = .Nl; | |
| 425 | self.index += 1; | |
| 426 | break; | |
| 427 | }, | |
| 428 | '\r' => { | |
| 429 | state = .Cr; | |
| 430 | }, | |
| 431 | '"' => { | |
| 432 | result.id = .{ .StringLiteral = .none }; | |
| 433 | state = .StringLiteral; | |
| 434 | }, | |
| 435 | '\'' => { | |
| 436 | result.id = .{ .CharLiteral = .none }; | |
| 437 | state = .CharLiteralStart; | |
| 438 | }, | |
| 439 | 'u' => { | |
| 440 | state = .u; | |
| 441 | }, | |
| 442 | 'U' => { | |
| 443 | state = .U; | |
| 444 | }, | |
| 445 | 'L' => { | |
| 446 | state = .L; | |
| 447 | }, | |
| 448 | 'a'...'t', 'v'...'z', 'A'...'K', 'M'...'T', 'V'...'Z', '_', '$' => { | |
| 449 | state = .Identifier; | |
| 450 | }, | |
| 451 | '=' => { | |
| 452 | state = .Equal; | |
| 453 | }, | |
| 454 | '!' => { | |
| 455 | state = .Bang; | |
| 456 | }, | |
| 457 | '|' => { | |
| 458 | state = .Pipe; | |
| 459 | }, | |
| 460 | '(' => { | |
| 461 | result.id = .LParen; | |
| 462 | self.index += 1; | |
| 463 | break; | |
| 464 | }, | |
| 465 | ')' => { | |
| 466 | result.id = .RParen; | |
| 467 | self.index += 1; | |
| 468 | break; | |
| 469 | }, | |
| 470 | '[' => { | |
| 471 | result.id = .LBracket; | |
| 472 | self.index += 1; | |
| 473 | break; | |
| 474 | }, | |
| 475 | ']' => { | |
| 476 | result.id = .RBracket; | |
| 477 | self.index += 1; | |
| 478 | break; | |
| 479 | }, | |
| 480 | ';' => { | |
| 481 | result.id = .Semicolon; | |
| 482 | self.index += 1; | |
| 483 | break; | |
| 484 | }, | |
| 485 | ',' => { | |
| 486 | result.id = .Comma; | |
| 487 | self.index += 1; | |
| 488 | break; | |
| 489 | }, | |
| 490 | '?' => { | |
| 491 | result.id = .QuestionMark; | |
| 492 | self.index += 1; | |
| 493 | break; | |
| 494 | }, | |
| 495 | ':' => { | |
| 496 | result.id = .Colon; | |
| 497 | self.index += 1; | |
| 498 | break; | |
| 499 | }, | |
| 500 | '%' => { | |
| 501 | state = .Percent; | |
| 502 | }, | |
| 503 | '*' => { | |
| 504 | state = .Asterisk; | |
| 505 | }, | |
| 506 | '+' => { | |
| 507 | state = .Plus; | |
| 508 | }, | |
| 509 | '<' => { | |
| 510 | if (self.prev_tok_id == .Keyword_include) | |
| 511 | state = .MacroString | |
| 512 | else | |
| 513 | state = .AngleBracketLeft; | |
| 514 | }, | |
| 515 | '>' => { | |
| 516 | state = .AngleBracketRight; | |
| 517 | }, | |
| 518 | '^' => { | |
| 519 | state = .Caret; | |
| 520 | }, | |
| 521 | '{' => { | |
| 522 | result.id = .LBrace; | |
| 523 | self.index += 1; | |
| 524 | break; | |
| 525 | }, | |
| 526 | '}' => { | |
| 527 | result.id = .RBrace; | |
| 528 | self.index += 1; | |
| 529 | break; | |
| 530 | }, | |
| 531 | '~' => { | |
| 532 | result.id = .Tilde; | |
| 533 | self.index += 1; | |
| 534 | break; | |
| 535 | }, | |
| 536 | '.' => { | |
| 537 | state = .Period; | |
| 538 | }, | |
| 539 | '-' => { | |
| 540 | state = .Minus; | |
| 541 | }, | |
| 542 | '/' => { | |
| 543 | state = .Slash; | |
| 544 | }, | |
| 545 | '&' => { | |
| 546 | state = .Ampersand; | |
| 547 | }, | |
| 548 | '#' => { | |
| 549 | state = .Hash; | |
| 550 | }, | |
| 551 | '0' => { | |
| 552 | state = .Zero; | |
| 553 | }, | |
| 554 | '1'...'9' => { | |
| 555 | state = .IntegerLiteral; | |
| 556 | }, | |
| 557 | '\\' => { | |
| 558 | state = .BackSlash; | |
| 559 | }, | |
| 560 | '\t', '\x0B', '\x0C', ' ' => { | |
| 561 | result.start = self.index + 1; | |
| 562 | }, | |
| 563 | else => { | |
| 564 | // TODO handle invalid bytes better | |
| 565 | result.id = .Invalid; | |
| 566 | self.index += 1; | |
| 567 | break; | |
| 568 | }, | |
| 569 | }, | |
| 570 | .Cr => switch (c) { | |
| 571 | '\n' => { | |
| 572 | self.pp_directive = false; | |
| 573 | result.id = .Nl; | |
| 574 | self.index += 1; | |
| 575 | break; | |
| 576 | }, | |
| 577 | else => { | |
| 578 | result.id = .Invalid; | |
| 579 | break; | |
| 580 | }, | |
| 581 | }, | |
| 582 | .BackSlash => switch (c) { | |
| 583 | '\n' => { | |
| 584 | result.start = self.index + 1; | |
| 585 | state = .Start; | |
| 586 | }, | |
| 587 | '\r' => { | |
| 588 | state = .BackSlashCr; | |
| 589 | }, | |
| 590 | '\t', '\x0B', '\x0C', ' ' => { | |
| 591 | // TODO warn | |
| 592 | }, | |
| 593 | else => { | |
| 594 | result.id = .Invalid; | |
| 595 | break; | |
| 596 | }, | |
| 597 | }, | |
| 598 | .BackSlashCr => switch (c) { | |
| 599 | '\n' => { | |
| 600 | result.start = self.index + 1; | |
| 601 | state = .Start; | |
| 602 | }, | |
| 603 | else => { | |
| 604 | result.id = .Invalid; | |
| 605 | break; | |
| 606 | }, | |
| 607 | }, | |
| 608 | .u => switch (c) { | |
| 609 | '8' => { | |
| 610 | state = .u8; | |
| 611 | }, | |
| 612 | '\'' => { | |
| 613 | result.id = .{ .CharLiteral = .utf_16 }; | |
| 614 | state = .CharLiteralStart; | |
| 615 | }, | |
| 616 | '\"' => { | |
| 617 | result.id = .{ .StringLiteral = .utf_16 }; | |
| 618 | state = .StringLiteral; | |
| 619 | }, | |
| 620 | else => { | |
| 621 | self.index -= 1; | |
| 622 | state = .Identifier; | |
| 623 | }, | |
| 624 | }, | |
| 625 | .u8 => switch (c) { | |
| 626 | '\"' => { | |
| 627 | result.id = .{ .StringLiteral = .utf_8 }; | |
| 628 | state = .StringLiteral; | |
| 629 | }, | |
| 630 | else => { | |
| 631 | self.index -= 1; | |
| 632 | state = .Identifier; | |
| 633 | }, | |
| 634 | }, | |
| 635 | .U => switch (c) { | |
| 636 | '\'' => { | |
| 637 | result.id = .{ .CharLiteral = .utf_32 }; | |
| 638 | state = .CharLiteralStart; | |
| 639 | }, | |
| 640 | '\"' => { | |
| 641 | result.id = .{ .StringLiteral = .utf_32 }; | |
| 642 | state = .StringLiteral; | |
| 643 | }, | |
| 644 | else => { | |
| 645 | self.index -= 1; | |
| 646 | state = .Identifier; | |
| 647 | }, | |
| 648 | }, | |
| 649 | .L => switch (c) { | |
| 650 | '\'' => { | |
| 651 | result.id = .{ .CharLiteral = .wide }; | |
| 652 | state = .CharLiteralStart; | |
| 653 | }, | |
| 654 | '\"' => { | |
| 655 | result.id = .{ .StringLiteral = .wide }; | |
| 656 | state = .StringLiteral; | |
| 657 | }, | |
| 658 | else => { | |
| 659 | self.index -= 1; | |
| 660 | state = .Identifier; | |
| 661 | }, | |
| 662 | }, | |
| 663 | .StringLiteral => switch (c) { | |
| 664 | '\\' => { | |
| 665 | string = true; | |
| 666 | state = .EscapeSequence; | |
| 667 | }, | |
| 668 | '"' => { | |
| 669 | self.index += 1; | |
| 670 | break; | |
| 671 | }, | |
| 672 | '\n', '\r' => { | |
| 673 | result.id = .Invalid; | |
| 674 | break; | |
| 675 | }, | |
| 676 | else => {}, | |
| 677 | }, | |
| 678 | .CharLiteralStart => switch (c) { | |
| 679 | '\\' => { | |
| 680 | string = false; | |
| 681 | state = .EscapeSequence; | |
| 682 | }, | |
| 683 | '\'', '\n' => { | |
| 684 | result.id = .Invalid; | |
| 685 | break; | |
| 686 | }, | |
| 687 | else => { | |
| 688 | state = .CharLiteral; | |
| 689 | }, | |
| 690 | }, | |
| 691 | .CharLiteral => switch (c) { | |
| 692 | '\\' => { | |
| 693 | string = false; | |
| 694 | state = .EscapeSequence; | |
| 695 | }, | |
| 696 | '\'' => { | |
| 697 | self.index += 1; | |
| 698 | break; | |
| 699 | }, | |
| 700 | '\n' => { | |
| 701 | result.id = .Invalid; | |
| 702 | break; | |
| 703 | }, | |
| 704 | else => {}, | |
| 705 | }, | |
| 706 | .EscapeSequence => switch (c) { | |
| 707 | '\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v', '\n' => { | |
| 708 | state = if (string) .StringLiteral else .CharLiteral; | |
| 709 | }, | |
| 710 | '\r' => { | |
| 711 | state = .CrEscape; | |
| 712 | }, | |
| 713 | '0'...'7' => { | |
| 714 | counter = 1; | |
| 715 | state = .OctalEscape; | |
| 716 | }, | |
| 717 | 'x' => { | |
| 718 | state = .HexEscape; | |
| 719 | }, | |
| 720 | 'u' => { | |
| 721 | counter = 4; | |
| 722 | state = .OctalEscape; | |
| 723 | }, | |
| 724 | 'U' => { | |
| 725 | counter = 8; | |
| 726 | state = .OctalEscape; | |
| 727 | }, | |
| 728 | else => { | |
| 729 | result.id = .Invalid; | |
| 730 | break; | |
| 731 | }, | |
| 732 | }, | |
| 733 | .CrEscape => switch (c) { | |
| 734 | '\n' => { | |
| 735 | state = if (string) .StringLiteral else .CharLiteral; | |
| 736 | }, | |
| 737 | else => { | |
| 738 | result.id = .Invalid; | |
| 739 | break; | |
| 740 | }, | |
| 741 | }, | |
| 742 | .OctalEscape => switch (c) { | |
| 743 | '0'...'7' => { | |
| 744 | counter += 1; | |
| 745 | if (counter == 3) { | |
| 746 | state = if (string) .StringLiteral else .CharLiteral; | |
| 747 | } | |
| 748 | }, | |
| 749 | else => { | |
| 750 | self.index -= 1; | |
| 751 | state = if (string) .StringLiteral else .CharLiteral; | |
| 752 | }, | |
| 753 | }, | |
| 754 | .HexEscape => switch (c) { | |
| 755 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | |
| 756 | else => { | |
| 757 | self.index -= 1; | |
| 758 | state = if (string) .StringLiteral else .CharLiteral; | |
| 759 | }, | |
| 760 | }, | |
| 761 | .UnicodeEscape => switch (c) { | |
| 762 | '0'...'9', 'a'...'f', 'A'...'F' => { | |
| 763 | counter -= 1; | |
| 764 | if (counter == 0) { | |
| 765 | state = if (string) .StringLiteral else .CharLiteral; | |
| 766 | } | |
| 767 | }, | |
| 768 | else => { | |
| 769 | if (counter != 0) { | |
| 770 | result.id = .Invalid; | |
| 771 | break; | |
| 772 | } | |
| 773 | self.index -= 1; | |
| 774 | state = if (string) .StringLiteral else .CharLiteral; | |
| 775 | }, | |
| 776 | }, | |
| 777 | .Identifier => switch (c) { | |
| 778 | 'a'...'z', 'A'...'Z', '_', '0'...'9', '$' => {}, | |
| 779 | else => { | |
| 780 | result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; | |
| 781 | if (self.prev_tok_id == .Hash) | |
| 782 | self.pp_directive = true; | |
| 783 | break; | |
| 784 | }, | |
| 785 | }, | |
| 786 | .Equal => switch (c) { | |
| 787 | '=' => { | |
| 788 | result.id = .EqualEqual; | |
| 789 | self.index += 1; | |
| 790 | break; | |
| 791 | }, | |
| 792 | else => { | |
| 793 | result.id = .Equal; | |
| 794 | break; | |
| 795 | }, | |
| 796 | }, | |
| 797 | .Bang => switch (c) { | |
| 798 | '=' => { | |
| 799 | result.id = .BangEqual; | |
| 800 | self.index += 1; | |
| 801 | break; | |
| 802 | }, | |
| 803 | else => { | |
| 804 | result.id = .Bang; | |
| 805 | break; | |
| 806 | }, | |
| 807 | }, | |
| 808 | .Pipe => switch (c) { | |
| 809 | '=' => { | |
| 810 | result.id = .PipeEqual; | |
| 811 | self.index += 1; | |
| 812 | break; | |
| 813 | }, | |
| 814 | '|' => { | |
| 815 | result.id = .PipePipe; | |
| 816 | self.index += 1; | |
| 817 | break; | |
| 818 | }, | |
| 819 | else => { | |
| 820 | result.id = .Pipe; | |
| 821 | break; | |
| 822 | }, | |
| 823 | }, | |
| 824 | .Percent => switch (c) { | |
| 825 | '=' => { | |
| 826 | result.id = .PercentEqual; | |
| 827 | self.index += 1; | |
| 828 | break; | |
| 829 | }, | |
| 830 | else => { | |
| 831 | result.id = .Percent; | |
| 832 | break; | |
| 833 | }, | |
| 834 | }, | |
| 835 | .Asterisk => switch (c) { | |
| 836 | '=' => { | |
| 837 | result.id = .AsteriskEqual; | |
| 838 | self.index += 1; | |
| 839 | break; | |
| 840 | }, | |
| 841 | else => { | |
| 842 | result.id = .Asterisk; | |
| 843 | break; | |
| 844 | }, | |
| 845 | }, | |
| 846 | .Plus => switch (c) { | |
| 847 | '=' => { | |
| 848 | result.id = .PlusEqual; | |
| 849 | self.index += 1; | |
| 850 | break; | |
| 851 | }, | |
| 852 | '+' => { | |
| 853 | result.id = .PlusPlus; | |
| 854 | self.index += 1; | |
| 855 | break; | |
| 856 | }, | |
| 857 | else => { | |
| 858 | result.id = .Plus; | |
| 859 | break; | |
| 860 | }, | |
| 861 | }, | |
| 862 | .MacroString => switch (c) { | |
| 863 | '>' => { | |
| 864 | result.id = .MacroString; | |
| 865 | self.index += 1; | |
| 866 | break; | |
| 867 | }, | |
| 868 | else => {}, | |
| 869 | }, | |
| 870 | .AngleBracketLeft => switch (c) { | |
| 871 | '<' => { | |
| 872 | state = .AngleBracketAngleBracketLeft; | |
| 873 | }, | |
| 874 | '=' => { | |
| 875 | result.id = .AngleBracketLeftEqual; | |
| 876 | self.index += 1; | |
| 877 | break; | |
| 878 | }, | |
| 879 | else => { | |
| 880 | result.id = .AngleBracketLeft; | |
| 881 | break; | |
| 882 | }, | |
| 883 | }, | |
| 884 | .AngleBracketAngleBracketLeft => switch (c) { | |
| 885 | '=' => { | |
| 886 | result.id = .AngleBracketAngleBracketLeftEqual; | |
| 887 | self.index += 1; | |
| 888 | break; | |
| 889 | }, | |
| 890 | else => { | |
| 891 | result.id = .AngleBracketAngleBracketLeft; | |
| 892 | break; | |
| 893 | }, | |
| 894 | }, | |
| 895 | .AngleBracketRight => switch (c) { | |
| 896 | '>' => { | |
| 897 | state = .AngleBracketAngleBracketRight; | |
| 898 | }, | |
| 899 | '=' => { | |
| 900 | result.id = .AngleBracketRightEqual; | |
| 901 | self.index += 1; | |
| 902 | break; | |
| 903 | }, | |
| 904 | else => { | |
| 905 | result.id = .AngleBracketRight; | |
| 906 | break; | |
| 907 | }, | |
| 908 | }, | |
| 909 | .AngleBracketAngleBracketRight => switch (c) { | |
| 910 | '=' => { | |
| 911 | result.id = .AngleBracketAngleBracketRightEqual; | |
| 912 | self.index += 1; | |
| 913 | break; | |
| 914 | }, | |
| 915 | else => { | |
| 916 | result.id = .AngleBracketAngleBracketRight; | |
| 917 | break; | |
| 918 | }, | |
| 919 | }, | |
| 920 | .Caret => switch (c) { | |
| 921 | '=' => { | |
| 922 | result.id = .CaretEqual; | |
| 923 | self.index += 1; | |
| 924 | break; | |
| 925 | }, | |
| 926 | else => { | |
| 927 | result.id = .Caret; | |
| 928 | break; | |
| 929 | }, | |
| 930 | }, | |
| 931 | .Period => switch (c) { | |
| 932 | '.' => { | |
| 933 | state = .Period2; | |
| 934 | }, | |
| 935 | '0'...'9' => { | |
| 936 | state = .FloatFraction; | |
| 937 | }, | |
| 938 | else => { | |
| 939 | result.id = .Period; | |
| 940 | break; | |
| 941 | }, | |
| 942 | }, | |
| 943 | .Period2 => switch (c) { | |
| 944 | '.' => { | |
| 945 | result.id = .Ellipsis; | |
| 946 | self.index += 1; | |
| 947 | break; | |
| 948 | }, | |
| 949 | else => { | |
| 950 | result.id = .Period; | |
| 951 | self.index -= 1; | |
| 952 | break; | |
| 953 | }, | |
| 954 | }, | |
| 955 | .Minus => switch (c) { | |
| 956 | '>' => { | |
| 957 | result.id = .Arrow; | |
| 958 | self.index += 1; | |
| 959 | break; | |
| 960 | }, | |
| 961 | '=' => { | |
| 962 | result.id = .MinusEqual; | |
| 963 | self.index += 1; | |
| 964 | break; | |
| 965 | }, | |
| 966 | '-' => { | |
| 967 | result.id = .MinusMinus; | |
| 968 | self.index += 1; | |
| 969 | break; | |
| 970 | }, | |
| 971 | else => { | |
| 972 | result.id = .Minus; | |
| 973 | break; | |
| 974 | }, | |
| 975 | }, | |
| 976 | .Slash => switch (c) { | |
| 977 | '/' => { | |
| 978 | state = .LineComment; | |
| 979 | }, | |
| 980 | '*' => { | |
| 981 | state = .MultiLineComment; | |
| 982 | }, | |
| 983 | '=' => { | |
| 984 | result.id = .SlashEqual; | |
| 985 | self.index += 1; | |
| 986 | break; | |
| 987 | }, | |
| 988 | else => { | |
| 989 | result.id = .Slash; | |
| 990 | break; | |
| 991 | }, | |
| 992 | }, | |
| 993 | .Ampersand => switch (c) { | |
| 994 | '&' => { | |
| 995 | result.id = .AmpersandAmpersand; | |
| 996 | self.index += 1; | |
| 997 | break; | |
| 998 | }, | |
| 999 | '=' => { | |
| 1000 | result.id = .AmpersandEqual; | |
| 1001 | self.index += 1; | |
| 1002 | break; | |
| 1003 | }, | |
| 1004 | else => { | |
| 1005 | result.id = .Ampersand; | |
| 1006 | break; | |
| 1007 | }, | |
| 1008 | }, | |
| 1009 | .Hash => switch (c) { | |
| 1010 | '#' => { | |
| 1011 | result.id = .HashHash; | |
| 1012 | self.index += 1; | |
| 1013 | break; | |
| 1014 | }, | |
| 1015 | else => { | |
| 1016 | result.id = .Hash; | |
| 1017 | break; | |
| 1018 | }, | |
| 1019 | }, | |
| 1020 | .LineComment => switch (c) { | |
| 1021 | '\n' => { | |
| 1022 | result.id = .LineComment; | |
| 1023 | break; | |
| 1024 | }, | |
| 1025 | else => {}, | |
| 1026 | }, | |
| 1027 | .MultiLineComment => switch (c) { | |
| 1028 | '*' => { | |
| 1029 | state = .MultiLineCommentAsterisk; | |
| 1030 | }, | |
| 1031 | else => {}, | |
| 1032 | }, | |
| 1033 | .MultiLineCommentAsterisk => switch (c) { | |
| 1034 | '/' => { | |
| 1035 | result.id = .MultiLineComment; | |
| 1036 | self.index += 1; | |
| 1037 | break; | |
| 1038 | }, | |
| 1039 | else => { | |
| 1040 | state = .MultiLineComment; | |
| 1041 | }, | |
| 1042 | }, | |
| 1043 | .Zero => switch (c) { | |
| 1044 | '0'...'9' => { | |
| 1045 | state = .IntegerLiteralOct; | |
| 1046 | }, | |
| 1047 | 'b', 'B' => { | |
| 1048 | state = .IntegerLiteralBinaryFirst; | |
| 1049 | }, | |
| 1050 | 'x', 'X' => { | |
| 1051 | state = .IntegerLiteralHexFirst; | |
| 1052 | }, | |
| 1053 | '.' => { | |
| 1054 | state = .FloatFraction; | |
| 1055 | }, | |
| 1056 | else => { | |
| 1057 | state = .IntegerSuffix; | |
| 1058 | self.index -= 1; | |
| 1059 | }, | |
| 1060 | }, | |
| 1061 | .IntegerLiteralOct => switch (c) { | |
| 1062 | '0'...'7' => {}, | |
| 1063 | else => { | |
| 1064 | state = .IntegerSuffix; | |
| 1065 | self.index -= 1; | |
| 1066 | }, | |
| 1067 | }, | |
| 1068 | .IntegerLiteralBinaryFirst => switch (c) { | |
| 1069 | '0'...'7' => state = .IntegerLiteralBinary, | |
| 1070 | else => { | |
| 1071 | result.id = .Invalid; | |
| 1072 | break; | |
| 1073 | }, | |
| 1074 | }, | |
| 1075 | .IntegerLiteralBinary => switch (c) { | |
| 1076 | '0', '1' => {}, | |
| 1077 | else => { | |
| 1078 | state = .IntegerSuffix; | |
| 1079 | self.index -= 1; | |
| 1080 | }, | |
| 1081 | }, | |
| 1082 | .IntegerLiteralHexFirst => switch (c) { | |
| 1083 | '0'...'9', 'a'...'f', 'A'...'F' => state = .IntegerLiteralHex, | |
| 1084 | '.' => { | |
| 1085 | state = .FloatFractionHex; | |
| 1086 | }, | |
| 1087 | 'p', 'P' => { | |
| 1088 | state = .FloatExponent; | |
| 1089 | }, | |
| 1090 | else => { | |
| 1091 | result.id = .Invalid; | |
| 1092 | break; | |
| 1093 | }, | |
| 1094 | }, | |
| 1095 | .IntegerLiteralHex => switch (c) { | |
| 1096 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | |
| 1097 | '.' => { | |
| 1098 | state = .FloatFractionHex; | |
| 1099 | }, | |
| 1100 | 'p', 'P' => { | |
| 1101 | state = .FloatExponent; | |
| 1102 | }, | |
| 1103 | else => { | |
| 1104 | state = .IntegerSuffix; | |
| 1105 | self.index -= 1; | |
| 1106 | }, | |
| 1107 | }, | |
| 1108 | .IntegerLiteral => switch (c) { | |
| 1109 | '0'...'9' => {}, | |
| 1110 | '.' => { | |
| 1111 | state = .FloatFraction; | |
| 1112 | }, | |
| 1113 | 'e', 'E' => { | |
| 1114 | state = .FloatExponent; | |
| 1115 | }, | |
| 1116 | else => { | |
| 1117 | state = .IntegerSuffix; | |
| 1118 | self.index -= 1; | |
| 1119 | }, | |
| 1120 | }, | |
| 1121 | .IntegerSuffix => switch (c) { | |
| 1122 | 'u', 'U' => { | |
| 1123 | state = .IntegerSuffixU; | |
| 1124 | }, | |
| 1125 | 'l', 'L' => { | |
| 1126 | state = .IntegerSuffixL; | |
| 1127 | }, | |
| 1128 | else => { | |
| 1129 | result.id = .{ .IntegerLiteral = .none }; | |
| 1130 | break; | |
| 1131 | }, | |
| 1132 | }, | |
| 1133 | .IntegerSuffixU => switch (c) { | |
| 1134 | 'l', 'L' => { | |
| 1135 | state = .IntegerSuffixUL; | |
| 1136 | }, | |
| 1137 | else => { | |
| 1138 | result.id = .{ .IntegerLiteral = .u }; | |
| 1139 | break; | |
| 1140 | }, | |
| 1141 | }, | |
| 1142 | .IntegerSuffixL => switch (c) { | |
| 1143 | 'l', 'L' => { | |
| 1144 | state = .IntegerSuffixLL; | |
| 1145 | }, | |
| 1146 | 'u', 'U' => { | |
| 1147 | result.id = .{ .IntegerLiteral = .lu }; | |
| 1148 | self.index += 1; | |
| 1149 | break; | |
| 1150 | }, | |
| 1151 | else => { | |
| 1152 | result.id = .{ .IntegerLiteral = .l }; | |
| 1153 | break; | |
| 1154 | }, | |
| 1155 | }, | |
| 1156 | .IntegerSuffixLL => switch (c) { | |
| 1157 | 'u', 'U' => { | |
| 1158 | result.id = .{ .IntegerLiteral = .llu }; | |
| 1159 | self.index += 1; | |
| 1160 | break; | |
| 1161 | }, | |
| 1162 | else => { | |
| 1163 | result.id = .{ .IntegerLiteral = .ll }; | |
| 1164 | break; | |
| 1165 | }, | |
| 1166 | }, | |
| 1167 | .IntegerSuffixUL => switch (c) { | |
| 1168 | 'l', 'L' => { | |
| 1169 | result.id = .{ .IntegerLiteral = .llu }; | |
| 1170 | self.index += 1; | |
| 1171 | break; | |
| 1172 | }, | |
| 1173 | else => { | |
| 1174 | result.id = .{ .IntegerLiteral = .lu }; | |
| 1175 | break; | |
| 1176 | }, | |
| 1177 | }, | |
| 1178 | .FloatFraction => switch (c) { | |
| 1179 | '0'...'9' => {}, | |
| 1180 | 'e', 'E' => { | |
| 1181 | state = .FloatExponent; | |
| 1182 | }, | |
| 1183 | else => { | |
| 1184 | self.index -= 1; | |
| 1185 | state = .FloatSuffix; | |
| 1186 | }, | |
| 1187 | }, | |
| 1188 | .FloatFractionHex => switch (c) { | |
| 1189 | '0'...'9', 'a'...'f', 'A'...'F' => {}, | |
| 1190 | 'p', 'P' => { | |
| 1191 | state = .FloatExponent; | |
| 1192 | }, | |
| 1193 | else => { | |
| 1194 | result.id = .Invalid; | |
| 1195 | break; | |
| 1196 | }, | |
| 1197 | }, | |
| 1198 | .FloatExponent => switch (c) { | |
| 1199 | '+', '-' => { | |
| 1200 | state = .FloatExponentDigits; | |
| 1201 | }, | |
| 1202 | else => { | |
| 1203 | self.index -= 1; | |
| 1204 | state = .FloatExponentDigits; | |
| 1205 | }, | |
| 1206 | }, | |
| 1207 | .FloatExponentDigits => switch (c) { | |
| 1208 | '0'...'9' => { | |
| 1209 | counter += 1; | |
| 1210 | }, | |
| 1211 | else => { | |
| 1212 | if (counter == 0) { | |
| 1213 | result.id = .Invalid; | |
| 1214 | break; | |
| 1215 | } | |
| 1216 | self.index -= 1; | |
| 1217 | state = .FloatSuffix; | |
| 1218 | }, | |
| 1219 | }, | |
| 1220 | .FloatSuffix => switch (c) { | |
| 1221 | 'l', 'L' => { | |
| 1222 | result.id = .{ .FloatLiteral = .l }; | |
| 1223 | self.index += 1; | |
| 1224 | break; | |
| 1225 | }, | |
| 1226 | 'f', 'F' => { | |
| 1227 | result.id = .{ .FloatLiteral = .f }; | |
| 1228 | self.index += 1; | |
| 1229 | break; | |
| 1230 | }, | |
| 1231 | else => { | |
| 1232 | result.id = .{ .FloatLiteral = .none }; | |
| 1233 | break; | |
| 1234 | }, | |
| 1235 | }, | |
| 1236 | } | |
| 1237 | } else if (self.index == self.buffer.len) { | |
| 1238 | switch (state) { | |
| 1239 | .Start => {}, | |
| 1240 | .u, .u8, .U, .L, .Identifier => { | |
| 1241 | result.id = Token.getKeyword(self.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier; | |
| 1242 | }, | |
| 1243 | ||
| 1244 | .Cr, | |
| 1245 | .BackSlash, | |
| 1246 | .BackSlashCr, | |
| 1247 | .Period2, | |
| 1248 | .StringLiteral, | |
| 1249 | .CharLiteralStart, | |
| 1250 | .CharLiteral, | |
| 1251 | .EscapeSequence, | |
| 1252 | .CrEscape, | |
| 1253 | .OctalEscape, | |
| 1254 | .HexEscape, | |
| 1255 | .UnicodeEscape, | |
| 1256 | .MultiLineComment, | |
| 1257 | .MultiLineCommentAsterisk, | |
| 1258 | .FloatExponent, | |
| 1259 | .MacroString, | |
| 1260 | .IntegerLiteralBinaryFirst, | |
| 1261 | .IntegerLiteralHexFirst, | |
| 1262 | => result.id = .Invalid, | |
| 1263 | ||
| 1264 | .FloatExponentDigits => result.id = if (counter == 0) .Invalid else .{ .FloatLiteral = .none }, | |
| 1265 | ||
| 1266 | .FloatFraction, | |
| 1267 | .FloatFractionHex, | |
| 1268 | => result.id = .{ .FloatLiteral = .none }, | |
| 1269 | ||
| 1270 | .IntegerLiteralOct, | |
| 1271 | .IntegerLiteralBinary, | |
| 1272 | .IntegerLiteralHex, | |
| 1273 | .IntegerLiteral, | |
| 1274 | .IntegerSuffix, | |
| 1275 | .Zero, | |
| 1276 | => result.id = .{ .IntegerLiteral = .none }, | |
| 1277 | .IntegerSuffixU => result.id = .{ .IntegerLiteral = .u }, | |
| 1278 | .IntegerSuffixL => result.id = .{ .IntegerLiteral = .l }, | |
| 1279 | .IntegerSuffixLL => result.id = .{ .IntegerLiteral = .ll }, | |
| 1280 | .IntegerSuffixUL => result.id = .{ .IntegerLiteral = .lu }, | |
| 1281 | ||
| 1282 | .FloatSuffix => result.id = .{ .FloatLiteral = .none }, | |
| 1283 | .Equal => result.id = .Equal, | |
| 1284 | .Bang => result.id = .Bang, | |
| 1285 | .Minus => result.id = .Minus, | |
| 1286 | .Slash => result.id = .Slash, | |
| 1287 | .Ampersand => result.id = .Ampersand, | |
| 1288 | .Hash => result.id = .Hash, | |
| 1289 | .Period => result.id = .Period, | |
| 1290 | .Pipe => result.id = .Pipe, | |
| 1291 | .AngleBracketAngleBracketRight => result.id = .AngleBracketAngleBracketRight, | |
| 1292 | .AngleBracketRight => result.id = .AngleBracketRight, | |
| 1293 | .AngleBracketAngleBracketLeft => result.id = .AngleBracketAngleBracketLeft, | |
| 1294 | .AngleBracketLeft => result.id = .AngleBracketLeft, | |
| 1295 | .Plus => result.id = .Plus, | |
| 1296 | .Percent => result.id = .Percent, | |
| 1297 | .Caret => result.id = .Caret, | |
| 1298 | .Asterisk => result.id = .Asterisk, | |
| 1299 | .LineComment => result.id = .LineComment, | |
| 1300 | } | |
| 1301 | } | |
| 1302 | ||
| 1303 | self.prev_tok_id = result.id; | |
| 1304 | result.end = self.index; | |
| 1305 | return result; | |
| 1306 | } | |
| 1307 | }; | |
| 1308 | ||
| 1309 | test "operators" { | |
| 1310 | try expectTokens( | |
| 1311 | \\ ! != | || |= = == | |
| 1312 | \\ ( ) { } [ ] . .. ... | |
| 1313 | \\ ^ ^= + ++ += - -- -= | |
| 1314 | \\ * *= % %= -> : ; / /= | |
| 1315 | \\ , & && &= ? < <= << | |
| 1316 | \\ <<= > >= >> >>= ~ # ## | |
| 1317 | \\ | |
| 1318 | , &[_]Token.Id{ | |
| 1319 | .Bang, | |
| 1320 | .BangEqual, | |
| 1321 | .Pipe, | |
| 1322 | .PipePipe, | |
| 1323 | .PipeEqual, | |
| 1324 | .Equal, | |
| 1325 | .EqualEqual, | |
| 1326 | .Nl, | |
| 1327 | .LParen, | |
| 1328 | .RParen, | |
| 1329 | .LBrace, | |
| 1330 | .RBrace, | |
| 1331 | .LBracket, | |
| 1332 | .RBracket, | |
| 1333 | .Period, | |
| 1334 | .Period, | |
| 1335 | .Period, | |
| 1336 | .Ellipsis, | |
| 1337 | .Nl, | |
| 1338 | .Caret, | |
| 1339 | .CaretEqual, | |
| 1340 | .Plus, | |
| 1341 | .PlusPlus, | |
| 1342 | .PlusEqual, | |
| 1343 | .Minus, | |
| 1344 | .MinusMinus, | |
| 1345 | .MinusEqual, | |
| 1346 | .Nl, | |
| 1347 | .Asterisk, | |
| 1348 | .AsteriskEqual, | |
| 1349 | .Percent, | |
| 1350 | .PercentEqual, | |
| 1351 | .Arrow, | |
| 1352 | .Colon, | |
| 1353 | .Semicolon, | |
| 1354 | .Slash, | |
| 1355 | .SlashEqual, | |
| 1356 | .Nl, | |
| 1357 | .Comma, | |
| 1358 | .Ampersand, | |
| 1359 | .AmpersandAmpersand, | |
| 1360 | .AmpersandEqual, | |
| 1361 | .QuestionMark, | |
| 1362 | .AngleBracketLeft, | |
| 1363 | .AngleBracketLeftEqual, | |
| 1364 | .AngleBracketAngleBracketLeft, | |
| 1365 | .Nl, | |
| 1366 | .AngleBracketAngleBracketLeftEqual, | |
| 1367 | .AngleBracketRight, | |
| 1368 | .AngleBracketRightEqual, | |
| 1369 | .AngleBracketAngleBracketRight, | |
| 1370 | .AngleBracketAngleBracketRightEqual, | |
| 1371 | .Tilde, | |
| 1372 | .Hash, | |
| 1373 | .HashHash, | |
| 1374 | .Nl, | |
| 1375 | }); | |
| 1376 | } | |
| 1377 | ||
| 1378 | test "keywords" { | |
| 1379 | try expectTokens( | |
| 1380 | \\auto break case char const continue default do | |
| 1381 | \\double else enum extern float for goto if int | |
| 1382 | \\long register return short signed sizeof static | |
| 1383 | \\struct switch typedef union unsigned void volatile | |
| 1384 | \\while _Bool _Complex _Imaginary inline restrict _Alignas | |
| 1385 | \\_Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local | |
| 1386 | \\ | |
| 1387 | , &[_]Token.Id{ | |
| 1388 | .Keyword_auto, | |
| 1389 | .Keyword_break, | |
| 1390 | .Keyword_case, | |
| 1391 | .Keyword_char, | |
| 1392 | .Keyword_const, | |
| 1393 | .Keyword_continue, | |
| 1394 | .Keyword_default, | |
| 1395 | .Keyword_do, | |
| 1396 | .Nl, | |
| 1397 | .Keyword_double, | |
| 1398 | .Keyword_else, | |
| 1399 | .Keyword_enum, | |
| 1400 | .Keyword_extern, | |
| 1401 | .Keyword_float, | |
| 1402 | .Keyword_for, | |
| 1403 | .Keyword_goto, | |
| 1404 | .Keyword_if, | |
| 1405 | .Keyword_int, | |
| 1406 | .Nl, | |
| 1407 | .Keyword_long, | |
| 1408 | .Keyword_register, | |
| 1409 | .Keyword_return, | |
| 1410 | .Keyword_short, | |
| 1411 | .Keyword_signed, | |
| 1412 | .Keyword_sizeof, | |
| 1413 | .Keyword_static, | |
| 1414 | .Nl, | |
| 1415 | .Keyword_struct, | |
| 1416 | .Keyword_switch, | |
| 1417 | .Keyword_typedef, | |
| 1418 | .Keyword_union, | |
| 1419 | .Keyword_unsigned, | |
| 1420 | .Keyword_void, | |
| 1421 | .Keyword_volatile, | |
| 1422 | .Nl, | |
| 1423 | .Keyword_while, | |
| 1424 | .Keyword_bool, | |
| 1425 | .Keyword_complex, | |
| 1426 | .Keyword_imaginary, | |
| 1427 | .Keyword_inline, | |
| 1428 | .Keyword_restrict, | |
| 1429 | .Keyword_alignas, | |
| 1430 | .Nl, | |
| 1431 | .Keyword_alignof, | |
| 1432 | .Keyword_atomic, | |
| 1433 | .Keyword_generic, | |
| 1434 | .Keyword_noreturn, | |
| 1435 | .Keyword_static_assert, | |
| 1436 | .Keyword_thread_local, | |
| 1437 | .Nl, | |
| 1438 | }); | |
| 1439 | } | |
| 1440 | ||
| 1441 | test "preprocessor keywords" { | |
| 1442 | try expectTokens( | |
| 1443 | \\#include <test> | |
| 1444 | \\#define #include <1 | |
| 1445 | \\#ifdef | |
| 1446 | \\#ifndef | |
| 1447 | \\#error | |
| 1448 | \\#pragma | |
| 1449 | \\ | |
| 1450 | , &[_]Token.Id{ | |
| 1451 | .Hash, | |
| 1452 | .Keyword_include, | |
| 1453 | .MacroString, | |
| 1454 | .Nl, | |
| 1455 | .Hash, | |
| 1456 | .Keyword_define, | |
| 1457 | .Hash, | |
| 1458 | .Identifier, | |
| 1459 | .AngleBracketLeft, | |
| 1460 | .{ .IntegerLiteral = .none }, | |
| 1461 | .Nl, | |
| 1462 | .Hash, | |
| 1463 | .Keyword_ifdef, | |
| 1464 | .Nl, | |
| 1465 | .Hash, | |
| 1466 | .Keyword_ifndef, | |
| 1467 | .Nl, | |
| 1468 | .Hash, | |
| 1469 | .Keyword_error, | |
| 1470 | .Nl, | |
| 1471 | .Hash, | |
| 1472 | .Keyword_pragma, | |
| 1473 | .Nl, | |
| 1474 | }); | |
| 1475 | } | |
| 1476 | ||
| 1477 | test "line continuation" { | |
| 1478 | try expectTokens( | |
| 1479 | \\#define foo \ | |
| 1480 | \\ bar | |
| 1481 | \\"foo\ | |
| 1482 | \\ bar" | |
| 1483 | \\#define "foo" | |
| 1484 | \\ "bar" | |
| 1485 | \\#define "foo" \ | |
| 1486 | \\ "bar" | |
| 1487 | , &[_]Token.Id{ | |
| 1488 | .Hash, | |
| 1489 | .Keyword_define, | |
| 1490 | .Identifier, | |
| 1491 | .Identifier, | |
| 1492 | .Nl, | |
| 1493 | .{ .StringLiteral = .none }, | |
| 1494 | .Nl, | |
| 1495 | .Hash, | |
| 1496 | .Keyword_define, | |
| 1497 | .{ .StringLiteral = .none }, | |
| 1498 | .Nl, | |
| 1499 | .{ .StringLiteral = .none }, | |
| 1500 | .Nl, | |
| 1501 | .Hash, | |
| 1502 | .Keyword_define, | |
| 1503 | .{ .StringLiteral = .none }, | |
| 1504 | .{ .StringLiteral = .none }, | |
| 1505 | }); | |
| 1506 | } | |
| 1507 | ||
| 1508 | test "string prefix" { | |
| 1509 | try expectTokens( | |
| 1510 | \\"foo" | |
| 1511 | \\u"foo" | |
| 1512 | \\u8"foo" | |
| 1513 | \\U"foo" | |
| 1514 | \\L"foo" | |
| 1515 | \\'foo' | |
| 1516 | \\u'foo' | |
| 1517 | \\U'foo' | |
| 1518 | \\L'foo' | |
| 1519 | \\ | |
| 1520 | , &[_]Token.Id{ | |
| 1521 | .{ .StringLiteral = .none }, | |
| 1522 | .Nl, | |
| 1523 | .{ .StringLiteral = .utf_16 }, | |
| 1524 | .Nl, | |
| 1525 | .{ .StringLiteral = .utf_8 }, | |
| 1526 | .Nl, | |
| 1527 | .{ .StringLiteral = .utf_32 }, | |
| 1528 | .Nl, | |
| 1529 | .{ .StringLiteral = .wide }, | |
| 1530 | .Nl, | |
| 1531 | .{ .CharLiteral = .none }, | |
| 1532 | .Nl, | |
| 1533 | .{ .CharLiteral = .utf_16 }, | |
| 1534 | .Nl, | |
| 1535 | .{ .CharLiteral = .utf_32 }, | |
| 1536 | .Nl, | |
| 1537 | .{ .CharLiteral = .wide }, | |
| 1538 | .Nl, | |
| 1539 | }); | |
| 1540 | } | |
| 1541 | ||
| 1542 | test "num suffixes" { | |
| 1543 | try expectTokens( | |
| 1544 | \\ 1.0f 1.0L 1.0 .0 1. | |
| 1545 | \\ 0l 0lu 0ll 0llu 0 | |
| 1546 | \\ 1u 1ul 1ull 1 | |
| 1547 | \\ 0x 0b | |
| 1548 | \\ | |
| 1549 | , &[_]Token.Id{ | |
| 1550 | .{ .FloatLiteral = .f }, | |
| 1551 | .{ .FloatLiteral = .l }, | |
| 1552 | .{ .FloatLiteral = .none }, | |
| 1553 | .{ .FloatLiteral = .none }, | |
| 1554 | .{ .FloatLiteral = .none }, | |
| 1555 | .Nl, | |
| 1556 | .{ .IntegerLiteral = .l }, | |
| 1557 | .{ .IntegerLiteral = .lu }, | |
| 1558 | .{ .IntegerLiteral = .ll }, | |
| 1559 | .{ .IntegerLiteral = .llu }, | |
| 1560 | .{ .IntegerLiteral = .none }, | |
| 1561 | .Nl, | |
| 1562 | .{ .IntegerLiteral = .u }, | |
| 1563 | .{ .IntegerLiteral = .lu }, | |
| 1564 | .{ .IntegerLiteral = .llu }, | |
| 1565 | .{ .IntegerLiteral = .none }, | |
| 1566 | .Nl, | |
| 1567 | .Invalid, | |
| 1568 | .Invalid, | |
| 1569 | .Nl, | |
| 1570 | }); | |
| 1571 | } | |
| 1572 | ||
| 1573 | fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) !void { | |
| 1574 | var tokenizer = Tokenizer{ | |
| 1575 | .buffer = source, | |
| 1576 | }; | |
| 1577 | for (expected_tokens) |expected_token_id| { | |
| 1578 | const token = tokenizer.next(); | |
| 1579 | if (!std.meta.eql(token.id, expected_token_id)) { | |
| 1580 | std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) }); | |
| 1581 | } | |
| 1582 | } | |
| 1583 | const last_token = tokenizer.next(); | |
| 1584 | try std.testing.expect(last_token.id == .Eof); | |
| 1585 | } |
lib/std/zig/c_translation.zig+3-3| ... | ... | @@ -252,7 +252,7 @@ test "sizeof" { |
| 252 | 252 | try testing.expect(sizeof(anyopaque) == 1); |
| 253 | 253 | } |
| 254 | 254 | |
| 255 | pub const CIntLiteralBase = enum { decimal, octal, hexadecimal }; | |
| 255 | pub const CIntLiteralBase = enum { decimal, octal, hex }; | |
| 256 | 256 | |
| 257 | 257 | /// Deprecated: use `CIntLiteralBase` |
| 258 | 258 | pub const CIntLiteralRadix = CIntLiteralBase; |
| ... | ... | @@ -289,13 +289,13 @@ pub fn promoteIntLiteral( |
| 289 | 289 | } |
| 290 | 290 | |
| 291 | 291 | test "promoteIntLiteral" { |
| 292 | const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hexadecimal); | |
| 292 | const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hex); | |
| 293 | 293 | try testing.expectEqual(c_uint, @TypeOf(signed_hex)); |
| 294 | 294 | |
| 295 | 295 | if (math.maxInt(c_longlong) == math.maxInt(c_int)) return; |
| 296 | 296 | |
| 297 | 297 | const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal); |
| 298 | const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hexadecimal); | |
| 298 | const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hex); | |
| 299 | 299 | |
| 300 | 300 | if (math.maxInt(c_long) > math.maxInt(c_int)) { |
| 301 | 301 | try testing.expectEqual(c_long, @TypeOf(signed_decimal)); |
src/Compilation.zig+1-1| ... | ... | @@ -4194,7 +4194,7 @@ pub const CImportResult = struct { |
| 4194 | 4194 | /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked |
| 4195 | 4195 | /// a bit when we want to start using it from self-hosted. |
| 4196 | 4196 | pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { |
| 4197 | if (build_options.only_c) unreachable; // @cImport is not needed for bootstrapping | |
| 4197 | if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build"); | |
| 4198 | 4198 | const tracy_trace = trace(@src()); |
| 4199 | 4199 | defer tracy_trace.end(); |
| 4200 | 4200 |
src/main.zig+1-1| ... | ... | @@ -4286,7 +4286,7 @@ fn updateModule(comp: *Compilation) !void { |
| 4286 | 4286 | } |
| 4287 | 4287 | |
| 4288 | 4288 | fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void { |
| 4289 | if (build_options.only_c) unreachable; // translate-c is not needed for bootstrapping | |
| 4289 | if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build"); | |
| 4290 | 4290 | assert(comp.c_source_files.len == 1); |
| 4291 | 4291 | const c_source_file = comp.c_source_files[0]; |
| 4292 | 4292 |
src/stubs/aro_builtins.zig+3-1| ... | ... | @@ -22,7 +22,9 @@ pub fn with(comptime Properties: type) type { |
| 22 | 22 | return .{}; |
| 23 | 23 | } |
| 24 | 24 | pub fn tagFromName(name: []const u8) ?Tag { |
| 25 | return @enumFromInt(name.len); | |
| 25 | var res: u16 = 0; | |
| 26 | for (name) |c| res +%= c; | |
| 27 | return @enumFromInt(res); | |
| 26 | 28 | } |
| 27 | 29 | pub const NameBuf = struct { |
| 28 | 30 | pub fn span(_: *const NameBuf) []const u8 { |
src/translate_c.zig+305-261| ... | ... | @@ -1,13 +1,13 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const testing = std.testing; |
| 3 | 3 | const assert = std.debug.assert; |
| 4 | const clang = @import("clang.zig"); | |
| 5 | const ctok = std.c.tokenizer; | |
| 6 | const CToken = std.c.Token; | |
| 7 | 4 | const mem = std.mem; |
| 8 | 5 | const math = std.math; |
| 9 | 6 | const meta = std.meta; |
| 10 | 7 | const CallingConvention = std.builtin.CallingConvention; |
| 8 | const clang = @import("clang.zig"); | |
| 9 | const aro = @import("aro"); | |
| 10 | const CToken = aro.Tokenizer.Token; | |
| 11 | 11 | const ast = @import("translate_c/ast.zig"); |
| 12 | 12 | const Node = ast.Node; |
| 13 | 13 | const Tag = Node.Tag; |
| ... | ... | @@ -190,19 +190,21 @@ pub fn translate( |
| 190 | 190 | |
| 191 | 191 | /// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens) |
| 192 | 192 | /// Macros of this form will not be translated. |
| 193 | fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool { | |
| 194 | const source = getMacroText(unit, c, macro); | |
| 195 | var tokenizer = std.c.Tokenizer{ | |
| 196 | .buffer = source, | |
| 193 | fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) !bool { | |
| 194 | const source = try getMacroText(unit, c, macro); | |
| 195 | var tokenizer: aro.Tokenizer = .{ | |
| 196 | .buf = source, | |
| 197 | .source = .unused, | |
| 198 | .langopts = .{}, | |
| 197 | 199 | }; |
| 198 | const name_tok = tokenizer.next(); | |
| 200 | const name_tok = tokenizer.nextNoWS(); | |
| 199 | 201 | const name = source[name_tok.start..name_tok.end]; |
| 200 | 202 | |
| 201 | const first_tok = tokenizer.next(); | |
| 203 | const first_tok = tokenizer.nextNoWS(); | |
| 202 | 204 | // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by |
| 203 | 205 | // the tokenizer. |
| 204 | 206 | // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier) |
| 205 | if (first_tok.id == .Eof) return false; | |
| 207 | if (first_tok.id == .eof) return false; | |
| 206 | 208 | return mem.eql(u8, name, source[first_tok.start..first_tok.end]); |
| 207 | 209 | } |
| 208 | 210 | |
| ... | ... | @@ -223,7 +225,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { |
| 223 | 225 | const raw_name = macro.getName_getNameStart(); |
| 224 | 226 | const name = try c.str(raw_name); |
| 225 | 227 | |
| 226 | if (!isSelfDefinedMacro(ast_unit, c, macro)) { | |
| 228 | if (!try isSelfDefinedMacro(ast_unit, c, macro)) { | |
| 227 | 229 | try c.global_names.put(c.gpa, name, {}); |
| 228 | 230 | } |
| 229 | 231 | }, |
| ... | ... | @@ -5159,16 +5161,16 @@ pub const PatternList = struct { |
| 5159 | 5161 | /// Assumes that `ms` represents a tokenized function-like macro. |
| 5160 | 5162 | fn buildArgsHash(allocator: mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void { |
| 5161 | 5163 | assert(ms.tokens.len > 2); |
| 5162 | assert(ms.tokens[0].id == .Identifier); | |
| 5163 | assert(ms.tokens[1].id == .LParen); | |
| 5164 | assert(ms.tokens[0].id == .identifier or ms.tokens[0].id == .extended_identifier); | |
| 5165 | assert(ms.tokens[1].id == .l_paren); | |
| 5164 | 5166 | |
| 5165 | 5167 | var i: usize = 2; |
| 5166 | 5168 | while (true) : (i += 1) { |
| 5167 | 5169 | const token = ms.tokens[i]; |
| 5168 | 5170 | switch (token.id) { |
| 5169 | .RParen => break, | |
| 5170 | .Comma => continue, | |
| 5171 | .Identifier => { | |
| 5171 | .r_paren => break, | |
| 5172 | .comma => continue, | |
| 5173 | .identifier, .extended_identifier => { | |
| 5172 | 5174 | const identifier = ms.slice(token); |
| 5173 | 5175 | try hash.put(allocator, identifier, i); |
| 5174 | 5176 | }, |
| ... | ... | @@ -5220,18 +5222,18 @@ pub const PatternList = struct { |
| 5220 | 5222 | if (args_hash.count() != self.args_hash.count()) return false; |
| 5221 | 5223 | |
| 5222 | 5224 | var i: usize = 2; |
| 5223 | while (self.tokens[i].id != .RParen) : (i += 1) {} | |
| 5225 | while (self.tokens[i].id != .r_paren) : (i += 1) {} | |
| 5224 | 5226 | |
| 5225 | 5227 | const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens }; |
| 5226 | 5228 | while (i < self.tokens.len) : (i += 1) { |
| 5227 | 5229 | const pattern_token = self.tokens[i]; |
| 5228 | 5230 | const macro_token = ms.tokens[i]; |
| 5229 | if (meta.activeTag(pattern_token.id) != meta.activeTag(macro_token.id)) return false; | |
| 5231 | if (pattern_token.id != macro_token.id) return false; | |
| 5230 | 5232 | |
| 5231 | 5233 | const pattern_bytes = pattern_slicer.slice(pattern_token); |
| 5232 | 5234 | const macro_bytes = ms.slice(macro_token); |
| 5233 | 5235 | switch (pattern_token.id) { |
| 5234 | .Identifier => { | |
| 5236 | .identifier, .extended_identifier => { | |
| 5235 | 5237 | const pattern_arg_index = self.args_hash.get(pattern_bytes); |
| 5236 | 5238 | const macro_arg_index = args_hash.get(macro_bytes); |
| 5237 | 5239 | |
| ... | ... | @@ -5243,7 +5245,7 @@ pub const PatternList = struct { |
| 5243 | 5245 | return false; |
| 5244 | 5246 | } |
| 5245 | 5247 | }, |
| 5246 | .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => { | |
| 5248 | .string_literal, .char_literal, .pp_num => { | |
| 5247 | 5249 | if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false; |
| 5248 | 5250 | }, |
| 5249 | 5251 | else => { |
| ... | ... | @@ -5359,13 +5361,13 @@ const MacroCtx = struct { |
| 5359 | 5361 | return self.list[self.i].id; |
| 5360 | 5362 | } |
| 5361 | 5363 | |
| 5362 | fn skip(self: *MacroCtx, c: *Context, expected_id: std.meta.Tag(CToken.Id)) ParseError!void { | |
| 5364 | fn skip(self: *MacroCtx, c: *Context, expected_id: CToken.Id) ParseError!void { | |
| 5363 | 5365 | const next_id = self.next().?; |
| 5364 | if (next_id != expected_id) { | |
| 5366 | if (next_id != expected_id and !(expected_id == .identifier and next_id == .extended_identifier)) { | |
| 5365 | 5367 | try self.fail( |
| 5366 | 5368 | c, |
| 5367 | 5369 | "unable to translate C expr: expected '{s}' instead got '{s}'", |
| 5368 | .{ CToken.Id.symbolName(expected_id), next_id.symbol() }, | |
| 5370 | .{ expected_id.symbol(), next_id.symbol() }, | |
| 5369 | 5371 | ); |
| 5370 | 5372 | return error.ParseError; |
| 5371 | 5373 | } |
| ... | ... | @@ -5396,12 +5398,12 @@ const MacroCtx = struct { |
| 5396 | 5398 | while (i < self.list.len) : (i += 1) { |
| 5397 | 5399 | const token = self.list[i]; |
| 5398 | 5400 | switch (token.id) { |
| 5399 | .Period, .Arrow => i += 1, // skip next token since field identifiers can be unknown | |
| 5400 | .Keyword_struct, .Keyword_union, .Keyword_enum => if (!last_is_type_kw) { | |
| 5401 | .period, .arrow => i += 1, // skip next token since field identifiers can be unknown | |
| 5402 | .keyword_struct, .keyword_union, .keyword_enum => if (!last_is_type_kw) { | |
| 5401 | 5403 | last_is_type_kw = true; |
| 5402 | 5404 | continue; |
| 5403 | 5405 | }, |
| 5404 | .Identifier => { | |
| 5406 | .identifier, .extended_identifier => { | |
| 5405 | 5407 | const identifier = slicer.slice(token); |
| 5406 | 5408 | const is_param = for (params) |param| { |
| 5407 | 5409 | if (param.name != null and mem.eql(u8, identifier, param.name.?)) break true; |
| ... | ... | @@ -5422,31 +5424,38 @@ const MacroCtx = struct { |
| 5422 | 5424 | }; |
| 5423 | 5425 | |
| 5424 | 5426 | fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void { |
| 5425 | var tokenizer = std.c.Tokenizer{ | |
| 5426 | .buffer = source, | |
| 5427 | var tokenizer: aro.Tokenizer = .{ | |
| 5428 | .buf = source, | |
| 5429 | .source = .unused, | |
| 5430 | .langopts = .{}, | |
| 5427 | 5431 | }; |
| 5428 | 5432 | while (true) { |
| 5429 | 5433 | const tok = tokenizer.next(); |
| 5430 | 5434 | switch (tok.id) { |
| 5431 | .Nl, .Eof => { | |
| 5435 | .whitespace => continue, | |
| 5436 | .nl, .eof => { | |
| 5432 | 5437 | try tok_list.append(tok); |
| 5433 | 5438 | break; |
| 5434 | 5439 | }, |
| 5435 | .LineComment, .MultiLineComment => continue, | |
| 5436 | 5440 | else => {}, |
| 5437 | 5441 | } |
| 5438 | 5442 | try tok_list.append(tok); |
| 5439 | 5443 | } |
| 5440 | 5444 | } |
| 5441 | 5445 | |
| 5442 | fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 { | |
| 5446 | fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) ![]const u8 { | |
| 5443 | 5447 | const begin_loc = macro.getSourceRange_getBegin(); |
| 5444 | 5448 | const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit); |
| 5445 | 5449 | |
| 5446 | 5450 | const begin_c = c.source_manager.getCharacterData(begin_loc); |
| 5447 | 5451 | const end_c = c.source_manager.getCharacterData(end_loc); |
| 5448 | 5452 | const slice_len = @intFromPtr(end_c) - @intFromPtr(begin_c); |
| 5449 | return begin_c[0..slice_len]; | |
| 5453 | ||
| 5454 | var comp = aro.Compilation.init(c.gpa); | |
| 5455 | defer comp.deinit(); | |
| 5456 | const result = comp.addSourceFromBuffer("", begin_c[0..slice_len]) catch return error.OutOfMemory; | |
| 5457 | ||
| 5458 | return c.arena.dupe(u8, result.buf); | |
| 5450 | 5459 | } |
| 5451 | 5460 | |
| 5452 | 5461 | fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| ... | ... | @@ -5471,7 +5480,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5471 | 5480 | continue; |
| 5472 | 5481 | } |
| 5473 | 5482 | |
| 5474 | const source = getMacroText(unit, c, macro); | |
| 5483 | const source = try getMacroText(unit, c, macro); | |
| 5475 | 5484 | |
| 5476 | 5485 | try tokenizeMacro(source, &tok_list); |
| 5477 | 5486 | |
| ... | ... | @@ -5485,7 +5494,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5485 | 5494 | |
| 5486 | 5495 | var macro_fn = false; |
| 5487 | 5496 | switch (macro_ctx.peek().?) { |
| 5488 | .Identifier => { | |
| 5497 | .identifier, .extended_identifier => { | |
| 5489 | 5498 | // if it equals itself, ignore. for example, from stdio.h: |
| 5490 | 5499 | // #define stdin stdin |
| 5491 | 5500 | const tok = macro_ctx.list[1]; |
| ... | ... | @@ -5494,7 +5503,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5494 | 5503 | continue; |
| 5495 | 5504 | } |
| 5496 | 5505 | }, |
| 5497 | .Nl, .Eof => { | |
| 5506 | .nl, .eof => { | |
| 5498 | 5507 | // this means it is a macro without a value |
| 5499 | 5508 | // We define it as an empty string so that it can still be used with ++ |
| 5500 | 5509 | const str_node = try Tag.string_literal.create(c.arena, "\"\""); |
| ... | ... | @@ -5503,7 +5512,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void { |
| 5503 | 5512 | try c.global_scope.blank_macros.put(name, {}); |
| 5504 | 5513 | continue; |
| 5505 | 5514 | }, |
| 5506 | .LParen => { | |
| 5515 | .l_paren => { | |
| 5507 | 5516 | // if the name is immediately followed by a '(' then it is a function |
| 5508 | 5517 | macro_fn = macro_ctx.list[0].end == macro_ctx.list[1].start; |
| 5509 | 5518 | }, |
| ... | ... | @@ -5534,7 +5543,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5534 | 5543 | // Check if the macro only uses other blank macros. |
| 5535 | 5544 | while (true) { |
| 5536 | 5545 | switch (m.peek().?) { |
| 5537 | .Identifier => { | |
| 5546 | .identifier, .extended_identifier => { | |
| 5538 | 5547 | const tok = m.list[m.i + 1]; |
| 5539 | 5548 | const slice = m.source[tok.start..tok.end]; |
| 5540 | 5549 | if (c.global_scope.blank_macros.contains(slice)) { |
| ... | ... | @@ -5542,7 +5551,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5542 | 5551 | continue; |
| 5543 | 5552 | } |
| 5544 | 5553 | }, |
| 5545 | .Eof, .Nl => { | |
| 5554 | .eof, .nl => { | |
| 5546 | 5555 | try c.global_scope.blank_macros.put(m.name, {}); |
| 5547 | 5556 | const init_node = try Tag.string_literal.create(c.arena, "\"\""); |
| 5548 | 5557 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); |
| ... | ... | @@ -5556,7 +5565,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5556 | 5565 | |
| 5557 | 5566 | const init_node = try parseCExpr(c, m, scope); |
| 5558 | 5567 | const last = m.next().?; |
| 5559 | if (last != .Eof and last != .Nl) | |
| 5568 | if (last != .eof and last != .nl) | |
| 5560 | 5569 | return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); |
| 5561 | 5570 | |
| 5562 | 5571 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); |
| ... | ... | @@ -5578,14 +5587,16 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5578 | 5587 | defer block_scope.deinit(); |
| 5579 | 5588 | const scope = &block_scope.base; |
| 5580 | 5589 | |
| 5581 | try m.skip(c, .LParen); | |
| 5590 | try m.skip(c, .l_paren); | |
| 5582 | 5591 | |
| 5583 | 5592 | var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa); |
| 5584 | 5593 | defer fn_params.deinit(); |
| 5585 | 5594 | |
| 5586 | 5595 | while (true) { |
| 5587 | if (m.peek().? != .Identifier) break; | |
| 5588 | _ = m.next(); | |
| 5596 | switch (m.peek().?) { | |
| 5597 | .identifier, .extended_identifier => _ = m.next(), | |
| 5598 | else => break, | |
| 5599 | } | |
| 5589 | 5600 | |
| 5590 | 5601 | const mangled_name = try block_scope.makeMangledName(c, m.slice()); |
| 5591 | 5602 | try fn_params.append(.{ |
| ... | ... | @@ -5594,11 +5605,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5594 | 5605 | .type = Tag.@"anytype".init(), |
| 5595 | 5606 | }); |
| 5596 | 5607 | try block_scope.discardVariable(c, mangled_name); |
| 5597 | if (m.peek().? != .Comma) break; | |
| 5608 | if (m.peek().? != .comma) break; | |
| 5598 | 5609 | _ = m.next(); |
| 5599 | 5610 | } |
| 5600 | 5611 | |
| 5601 | try m.skip(c, .RParen); | |
| 5612 | try m.skip(c, .r_paren); | |
| 5602 | 5613 | |
| 5603 | 5614 | if (m.checkTranslatableMacro(scope, fn_params.items)) |err| switch (err) { |
| 5604 | 5615 | .undefined_identifier => |ident| return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident}), |
| ... | ... | @@ -5607,7 +5618,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 5607 | 5618 | |
| 5608 | 5619 | const expr = try parseCExpr(c, m, scope); |
| 5609 | 5620 | const last = m.next().?; |
| 5610 | if (last != .Eof and last != .Nl) | |
| 5621 | if (last != .eof and last != .nl) | |
| 5611 | 5622 | return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()}); |
| 5612 | 5623 | |
| 5613 | 5624 | const typeof_arg = if (expr.castTag(.block)) |some| blk: { |
| ... | ... | @@ -5644,7 +5655,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5644 | 5655 | defer block_scope.deinit(); |
| 5645 | 5656 | |
| 5646 | 5657 | const node = try parseCCondExpr(c, m, &block_scope.base); |
| 5647 | if (m.next().? != .Comma) { | |
| 5658 | if (m.next().? != .comma) { | |
| 5648 | 5659 | m.i -= 1; |
| 5649 | 5660 | return node; |
| 5650 | 5661 | } |
| ... | ... | @@ -5656,7 +5667,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5656 | 5667 | try block_scope.statements.append(ignore); |
| 5657 | 5668 | |
| 5658 | 5669 | last = try parseCCondExpr(c, m, &block_scope.base); |
| 5659 | if (m.next().? != .Comma) { | |
| 5670 | if (m.next().? != .comma) { | |
| 5660 | 5671 | m.i -= 1; |
| 5661 | 5672 | break; |
| 5662 | 5673 | } |
| ... | ... | @@ -5670,118 +5681,135 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 5670 | 5681 | return try block_scope.complete(c); |
| 5671 | 5682 | } |
| 5672 | 5683 | |
| 5673 | fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { | |
| 5674 | var lit_bytes = m.slice(); | |
| 5684 | fn parseCNumLit(ctx: *Context, m: *MacroCtx) ParseError!Node { | |
| 5685 | const lit_bytes = m.slice(); | |
| 5686 | var bytes = try std.ArrayListUnmanaged(u8).initCapacity(ctx.arena, lit_bytes.len + 3); | |
| 5675 | 5687 | |
| 5676 | switch (m.list[m.i].id) { | |
| 5677 | .IntegerLiteral => |suffix| { | |
| 5678 | var base: []const u8 = "decimal"; | |
| 5679 | if (lit_bytes.len >= 2 and lit_bytes[0] == '0') { | |
| 5680 | switch (lit_bytes[1]) { | |
| 5681 | '0'...'7' => { | |
| 5682 | // Octal | |
| 5683 | lit_bytes = try std.fmt.allocPrint(c.arena, "0o{s}", .{lit_bytes[1..]}); | |
| 5684 | base = "octal"; | |
| 5685 | }, | |
| 5686 | 'X' => { | |
| 5687 | // Hexadecimal with capital X, valid in C but not in Zig | |
| 5688 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); | |
| 5689 | base = "hexadecimal"; | |
| 5690 | }, | |
| 5691 | 'x' => { | |
| 5692 | base = "hexadecimal"; | |
| 5693 | }, | |
| 5694 | else => {}, | |
| 5695 | } | |
| 5696 | } | |
| 5697 | ||
| 5698 | const type_node = try Tag.type.create(c.arena, switch (suffix) { | |
| 5699 | .none => "c_int", | |
| 5700 | .u => "c_uint", | |
| 5701 | .l => "c_long", | |
| 5702 | .lu => "c_ulong", | |
| 5703 | .ll => "c_longlong", | |
| 5704 | .llu => "c_ulonglong", | |
| 5705 | .f => unreachable, | |
| 5706 | }); | |
| 5707 | lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (suffix) { | |
| 5708 | .none => @as(u8, 0), | |
| 5709 | .u, .l => 1, | |
| 5710 | .lu, .ll => 2, | |
| 5711 | .llu => 3, | |
| 5712 | .f => unreachable, | |
| 5713 | }]; | |
| 5714 | ||
| 5715 | const value = std.fmt.parseInt(i128, lit_bytes, 0) catch math.maxInt(i128); | |
| 5716 | ||
| 5717 | // make the output less noisy by skipping promoteIntLiteral where | |
| 5718 | // it's guaranteed to not be required because of C standard type constraints | |
| 5719 | const guaranteed_to_fit = switch (suffix) { | |
| 5720 | .none => math.cast(i16, value) != null, | |
| 5721 | .u => math.cast(u16, value) != null, | |
| 5722 | .l => math.cast(i32, value) != null, | |
| 5723 | .lu => math.cast(u32, value) != null, | |
| 5724 | .ll => math.cast(i64, value) != null, | |
| 5725 | .llu => math.cast(u64, value) != null, | |
| 5726 | .f => unreachable, | |
| 5727 | }; | |
| 5728 | ||
| 5729 | const literal_node = try transCreateNodeNumber(c, lit_bytes, .int); | |
| 5688 | const prefix = aro.Tree.Token.NumberPrefix.fromString(lit_bytes); | |
| 5689 | switch (prefix) { | |
| 5690 | .binary => bytes.appendSliceAssumeCapacity("0b"), | |
| 5691 | .octal => bytes.appendSliceAssumeCapacity("0o"), | |
| 5692 | .hex => bytes.appendSliceAssumeCapacity("0x"), | |
| 5693 | .decimal => {}, | |
| 5694 | } | |
| 5730 | 5695 | |
| 5731 | if (guaranteed_to_fit) { | |
| 5732 | return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = literal_node }); | |
| 5733 | } else { | |
| 5734 | return Tag.helpers_promoteIntLiteral.create(c.arena, .{ | |
| 5735 | .type = type_node, | |
| 5736 | .value = literal_node, | |
| 5737 | .base = try Tag.enum_literal.create(c.arena, base), | |
| 5738 | }); | |
| 5696 | const after_prefix = lit_bytes[prefix.stringLen()..]; | |
| 5697 | const after_int = for (after_prefix, 0..) |c, i| switch (c) { | |
| 5698 | '.' => { | |
| 5699 | if (i == 0) { | |
| 5700 | bytes.appendAssumeCapacity('0'); | |
| 5739 | 5701 | } |
| 5702 | break after_prefix[i..]; | |
| 5740 | 5703 | }, |
| 5741 | .FloatLiteral => |suffix| { | |
| 5742 | if (suffix != .none) lit_bytes = lit_bytes[0 .. lit_bytes.len - 1]; | |
| 5743 | ||
| 5744 | if (lit_bytes.len >= 2 and std.ascii.eqlIgnoreCase(lit_bytes[0..2], "0x")) { | |
| 5745 | if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { | |
| 5746 | if (dot_index == 2) { | |
| 5747 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x0{s}", .{lit_bytes[2..]}); | |
| 5748 | } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isHex(lit_bytes[dot_index + 1])) { | |
| 5749 | // If the literal lacks a digit after the `.`, we need to | |
| 5750 | // add one since `0x1.p10` would be invalid syntax in Zig. | |
| 5751 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}0{s}", .{ | |
| 5752 | lit_bytes[2 .. dot_index + 1], | |
| 5753 | lit_bytes[dot_index + 1 ..], | |
| 5754 | }); | |
| 5755 | } | |
| 5756 | } | |
| 5704 | 'e', 'E' => { | |
| 5705 | if (prefix != .hex) break after_prefix[i..]; | |
| 5706 | bytes.appendAssumeCapacity(c); | |
| 5707 | }, | |
| 5708 | 'p', 'P' => break after_prefix[i..], | |
| 5709 | '0'...'9', 'a'...'d', 'A'...'D', 'f', 'F' => { | |
| 5710 | if (!prefix.digitAllowed(c)) break after_prefix[i..]; | |
| 5711 | bytes.appendAssumeCapacity(c); | |
| 5712 | }, | |
| 5713 | '\'' => { | |
| 5714 | bytes.appendAssumeCapacity('_'); | |
| 5715 | }, | |
| 5716 | else => break after_prefix[i..], | |
| 5717 | } else ""; | |
| 5757 | 5718 | |
| 5758 | if (lit_bytes[1] == 'X') { | |
| 5759 | // Hexadecimal with capital X, valid in C but not in Zig | |
| 5760 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{s}", .{lit_bytes[2..]}); | |
| 5761 | } | |
| 5762 | } else if (mem.indexOfScalar(u8, lit_bytes, '.')) |dot_index| { | |
| 5763 | if (dot_index == 0) { | |
| 5764 | lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes}); | |
| 5765 | } else if (dot_index + 1 == lit_bytes.len or !std.ascii.isDigit(lit_bytes[dot_index + 1])) { | |
| 5766 | // If the literal lacks a digit after the `.`, we need to | |
| 5767 | // add one since `1.` or `1.e10` would be invalid syntax in Zig. | |
| 5768 | lit_bytes = try std.fmt.allocPrint(c.arena, "{s}0{s}", .{ | |
| 5769 | lit_bytes[0 .. dot_index + 1], | |
| 5770 | lit_bytes[dot_index + 1 ..], | |
| 5771 | }); | |
| 5772 | } | |
| 5719 | const after_frac = frac: { | |
| 5720 | if (after_int.len == 0 or after_int[0] != '.') break :frac after_int; | |
| 5721 | bytes.appendAssumeCapacity('.'); | |
| 5722 | for (after_int[1..], 1..) |c, i| { | |
| 5723 | if (c == '\'') { | |
| 5724 | bytes.appendAssumeCapacity('_'); | |
| 5725 | continue; | |
| 5773 | 5726 | } |
| 5727 | if (!prefix.digitAllowed(c)) break :frac after_int[i..]; | |
| 5728 | bytes.appendAssumeCapacity(c); | |
| 5729 | } | |
| 5730 | break :frac ""; | |
| 5731 | }; | |
| 5732 | ||
| 5733 | const suffix_str = exponent: { | |
| 5734 | if (after_frac.len == 0) break :exponent after_frac; | |
| 5735 | switch (after_frac[0]) { | |
| 5736 | 'e', 'E' => {}, | |
| 5737 | 'p', 'P' => if (prefix != .hex) break :exponent after_frac, | |
| 5738 | else => break :exponent after_frac, | |
| 5739 | } | |
| 5740 | bytes.appendAssumeCapacity(after_frac[0]); | |
| 5741 | for (after_frac[1..], 1..) |c, i| switch (c) { | |
| 5742 | '+', '-', '0'...'9' => { | |
| 5743 | bytes.appendAssumeCapacity(c); | |
| 5744 | }, | |
| 5745 | '\'' => { | |
| 5746 | bytes.appendAssumeCapacity('_'); | |
| 5747 | }, | |
| 5748 | else => break :exponent after_frac[i..], | |
| 5749 | }; | |
| 5750 | break :exponent ""; | |
| 5751 | }; | |
| 5752 | ||
| 5753 | const is_float = after_int.len != suffix_str.len; | |
| 5754 | const suffix = aro.Tree.Token.NumberSuffix.fromString(suffix_str, if (is_float) .float else .int) orelse { | |
| 5755 | try m.fail(ctx, "invalid number suffix: '{s}'", .{suffix_str}); | |
| 5756 | return error.ParseError; | |
| 5757 | }; | |
| 5758 | if (suffix.isImaginary()) { | |
| 5759 | try m.fail(ctx, "TODO: imaginary literals", .{}); | |
| 5760 | return error.ParseError; | |
| 5761 | } | |
| 5762 | if (suffix.isBitInt()) { | |
| 5763 | try m.fail(ctx, "TODO: _BitInt literals", .{}); | |
| 5764 | return error.ParseError; | |
| 5765 | } | |
| 5766 | ||
| 5767 | if (is_float) { | |
| 5768 | const type_node = try Tag.type.create(ctx.arena, switch (suffix) { | |
| 5769 | .F16 => "f16", | |
| 5770 | .F => "f32", | |
| 5771 | .None => "f64", | |
| 5772 | .L => "c_longdouble", | |
| 5773 | .W => "f80", | |
| 5774 | .Q, .F128 => "f128", | |
| 5775 | else => unreachable, | |
| 5776 | }); | |
| 5777 | const rhs = try Tag.float_literal.create(ctx.arena, bytes.items); | |
| 5778 | return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = rhs }); | |
| 5779 | } else { | |
| 5780 | const type_node = try Tag.type.create(ctx.arena, switch (suffix) { | |
| 5781 | .None => "c_int", | |
| 5782 | .U => "c_uint", | |
| 5783 | .L => "c_long", | |
| 5784 | .UL => "c_ulong", | |
| 5785 | .LL => "c_longlong", | |
| 5786 | .ULL => "c_ulonglong", | |
| 5787 | else => unreachable, | |
| 5788 | }); | |
| 5789 | const value = std.fmt.parseInt(i128, bytes.items, 0) catch math.maxInt(i128); | |
| 5790 | ||
| 5791 | // make the output less noisy by skipping promoteIntLiteral where | |
| 5792 | // it's guaranteed to not be required because of C standard type constraints | |
| 5793 | const guaranteed_to_fit = switch (suffix) { | |
| 5794 | .None => math.cast(i16, value) != null, | |
| 5795 | .U => math.cast(u16, value) != null, | |
| 5796 | .L => math.cast(i32, value) != null, | |
| 5797 | .UL => math.cast(u32, value) != null, | |
| 5798 | .LL => math.cast(i64, value) != null, | |
| 5799 | .ULL => math.cast(u64, value) != null, | |
| 5800 | else => unreachable, | |
| 5801 | }; | |
| 5774 | 5802 | |
| 5775 | const type_node = try Tag.type.create(c.arena, switch (suffix) { | |
| 5776 | .f => "f32", | |
| 5777 | .none => "f64", | |
| 5778 | .l => "c_longdouble", | |
| 5779 | else => unreachable, | |
| 5803 | const literal_node = try Tag.integer_literal.create(ctx.arena, bytes.items); | |
| 5804 | if (guaranteed_to_fit) { | |
| 5805 | return Tag.as.create(ctx.arena, .{ .lhs = type_node, .rhs = literal_node }); | |
| 5806 | } else { | |
| 5807 | return Tag.helpers_promoteIntLiteral.create(ctx.arena, .{ | |
| 5808 | .type = type_node, | |
| 5809 | .value = literal_node, | |
| 5810 | .base = try Tag.enum_literal.create(ctx.arena, @tagName(prefix)), | |
| 5780 | 5811 | }); |
| 5781 | const rhs = try transCreateNodeNumber(c, lit_bytes, .float); | |
| 5782 | return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); | |
| 5783 | }, | |
| 5784 | else => unreachable, | |
| 5812 | } | |
| 5785 | 5813 | } |
| 5786 | 5814 | } |
| 5787 | 5815 | |
| ... | ... | @@ -5800,17 +5828,17 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5800 | 5828 | } else return source; |
| 5801 | 5829 | var bytes = try ctx.arena.alloc(u8, source.len * 2); |
| 5802 | 5830 | var state: enum { |
| 5803 | Start, | |
| 5804 | Escape, | |
| 5805 | Hex, | |
| 5806 | Octal, | |
| 5807 | } = .Start; | |
| 5831 | start, | |
| 5832 | escape, | |
| 5833 | hex, | |
| 5834 | octal, | |
| 5835 | } = .start; | |
| 5808 | 5836 | var i: usize = 0; |
| 5809 | 5837 | var count: u8 = 0; |
| 5810 | 5838 | var num: u8 = 0; |
| 5811 | 5839 | for (source) |c| { |
| 5812 | 5840 | switch (state) { |
| 5813 | .Escape => { | |
| 5841 | .escape => { | |
| 5814 | 5842 | switch (c) { |
| 5815 | 5843 | 'n', 'r', 't', '\\', '\'', '\"' => { |
| 5816 | 5844 | bytes[i] = c; |
| ... | ... | @@ -5818,11 +5846,11 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5818 | 5846 | '0'...'7' => { |
| 5819 | 5847 | count += 1; |
| 5820 | 5848 | num += c - '0'; |
| 5821 | state = .Octal; | |
| 5849 | state = .octal; | |
| 5822 | 5850 | bytes[i] = 'x'; |
| 5823 | 5851 | }, |
| 5824 | 5852 | 'x' => { |
| 5825 | state = .Hex; | |
| 5853 | state = .hex; | |
| 5826 | 5854 | bytes[i] = 'x'; |
| 5827 | 5855 | }, |
| 5828 | 5856 | 'a' => { |
| ... | ... | @@ -5867,10 +5895,10 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5867 | 5895 | }, |
| 5868 | 5896 | } |
| 5869 | 5897 | i += 1; |
| 5870 | if (state == .Escape) | |
| 5871 | state = .Start; | |
| 5898 | if (state == .escape) | |
| 5899 | state = .start; | |
| 5872 | 5900 | }, |
| 5873 | .Start => { | |
| 5901 | .start => { | |
| 5874 | 5902 | if (c == '\t') { |
| 5875 | 5903 | bytes[i] = '\\'; |
| 5876 | 5904 | i += 1; |
| ... | ... | @@ -5879,12 +5907,12 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5879 | 5907 | continue; |
| 5880 | 5908 | } |
| 5881 | 5909 | if (c == '\\') { |
| 5882 | state = .Escape; | |
| 5910 | state = .escape; | |
| 5883 | 5911 | } |
| 5884 | 5912 | bytes[i] = c; |
| 5885 | 5913 | i += 1; |
| 5886 | 5914 | }, |
| 5887 | .Hex => { | |
| 5915 | .hex => { | |
| 5888 | 5916 | switch (c) { |
| 5889 | 5917 | '0'...'9' => { |
| 5890 | 5918 | num = std.math.mul(u8, num, 16) catch { |
| ... | ... | @@ -5911,15 +5939,15 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5911 | 5939 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); |
| 5912 | 5940 | num = 0; |
| 5913 | 5941 | if (c == '\\') |
| 5914 | state = .Escape | |
| 5942 | state = .escape | |
| 5915 | 5943 | else |
| 5916 | state = .Start; | |
| 5944 | state = .start; | |
| 5917 | 5945 | bytes[i] = c; |
| 5918 | 5946 | i += 1; |
| 5919 | 5947 | }, |
| 5920 | 5948 | } |
| 5921 | 5949 | }, |
| 5922 | .Octal => { | |
| 5950 | .octal => { | |
| 5923 | 5951 | const accept_digit = switch (c) { |
| 5924 | 5952 | // The maximum length of a octal literal is 3 digits |
| 5925 | 5953 | '0'...'7' => count < 3, |
| ... | ... | @@ -5938,16 +5966,16 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { |
| 5938 | 5966 | num = 0; |
| 5939 | 5967 | count = 0; |
| 5940 | 5968 | if (c == '\\') |
| 5941 | state = .Escape | |
| 5969 | state = .escape | |
| 5942 | 5970 | else |
| 5943 | state = .Start; | |
| 5971 | state = .start; | |
| 5944 | 5972 | bytes[i] = c; |
| 5945 | 5973 | i += 1; |
| 5946 | 5974 | } |
| 5947 | 5975 | }, |
| 5948 | 5976 | } |
| 5949 | 5977 | } |
| 5950 | if (state == .Hex or state == .Octal) | |
| 5978 | if (state == .hex or state == .octal) | |
| 5951 | 5979 | i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); |
| 5952 | 5980 | return bytes[0..i]; |
| 5953 | 5981 | } |
| ... | ... | @@ -5972,7 +6000,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N |
| 5972 | 6000 | const tok = m.next().?; |
| 5973 | 6001 | const slice = m.slice(); |
| 5974 | 6002 | switch (tok) { |
| 5975 | .CharLiteral => { | |
| 6003 | .char_literal, | |
| 6004 | .char_literal_utf_8, | |
| 6005 | .char_literal_utf_16, | |
| 6006 | .char_literal_utf_32, | |
| 6007 | .char_literal_wide, | |
| 6008 | => { | |
| 5976 | 6009 | if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) { |
| 5977 | 6010 | return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m)); |
| 5978 | 6011 | } else { |
| ... | ... | @@ -5980,13 +6013,18 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N |
| 5980 | 6013 | return Tag.integer_literal.create(c.arena, str); |
| 5981 | 6014 | } |
| 5982 | 6015 | }, |
| 5983 | .StringLiteral => { | |
| 6016 | .string_literal, | |
| 6017 | .string_literal_utf_16, | |
| 6018 | .string_literal_utf_8, | |
| 6019 | .string_literal_utf_32, | |
| 6020 | .string_literal_wide, | |
| 6021 | => { | |
| 5984 | 6022 | return Tag.string_literal.create(c.arena, try escapeUnprintables(c, m)); |
| 5985 | 6023 | }, |
| 5986 | .IntegerLiteral, .FloatLiteral => { | |
| 6024 | .pp_num => { | |
| 5987 | 6025 | return parseCNumLit(c, m); |
| 5988 | 6026 | }, |
| 5989 | .Identifier => { | |
| 6027 | .identifier, .extended_identifier => { | |
| 5990 | 6028 | if (c.global_scope.blank_macros.contains(slice)) { |
| 5991 | 6029 | return parseCPrimaryExprInner(c, m, scope); |
| 5992 | 6030 | } |
| ... | ... | @@ -5996,10 +6034,10 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N |
| 5996 | 6034 | scope.skipVariableDiscard(identifier.castTag(.identifier).?.data); |
| 5997 | 6035 | return identifier; |
| 5998 | 6036 | }, |
| 5999 | .LParen => { | |
| 6037 | .l_paren => { | |
| 6000 | 6038 | const inner_node = try parseCExpr(c, m, scope); |
| 6001 | 6039 | |
| 6002 | try m.skip(c, .RParen); | |
| 6040 | try m.skip(c, .r_paren); | |
| 6003 | 6041 | return inner_node; |
| 6004 | 6042 | }, |
| 6005 | 6043 | else => { |
| ... | ... | @@ -6022,8 +6060,13 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6022 | 6060 | // after a primary expression. |
| 6023 | 6061 | while (true) { |
| 6024 | 6062 | switch (m.peek().?) { |
| 6025 | .StringLiteral => {}, | |
| 6026 | .Identifier => { | |
| 6063 | .string_literal, | |
| 6064 | .string_literal_utf_16, | |
| 6065 | .string_literal_utf_8, | |
| 6066 | .string_literal_utf_32, | |
| 6067 | .string_literal_wide, | |
| 6068 | => {}, | |
| 6069 | .identifier, .extended_identifier => { | |
| 6027 | 6070 | const tok = m.list[m.i + 1]; |
| 6028 | 6071 | const slice = m.source[tok.start..tok.end]; |
| 6029 | 6072 | if (c.global_scope.blank_macros.contains(slice)) { |
| ... | ... | @@ -6057,20 +6100,20 @@ fn macroIntToBool(c: *Context, node: Node) !Node { |
| 6057 | 6100 | |
| 6058 | 6101 | fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6059 | 6102 | const node = try parseCOrExpr(c, m, scope); |
| 6060 | if (m.peek().? != .QuestionMark) { | |
| 6103 | if (m.peek().? != .question_mark) { | |
| 6061 | 6104 | return node; |
| 6062 | 6105 | } |
| 6063 | 6106 | _ = m.next(); |
| 6064 | 6107 | |
| 6065 | 6108 | const then_body = try parseCOrExpr(c, m, scope); |
| 6066 | try m.skip(c, .Colon); | |
| 6109 | try m.skip(c, .colon); | |
| 6067 | 6110 | const else_body = try parseCCondExpr(c, m, scope); |
| 6068 | 6111 | return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body }); |
| 6069 | 6112 | } |
| 6070 | 6113 | |
| 6071 | 6114 | fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6072 | 6115 | var node = try parseCAndExpr(c, m, scope); |
| 6073 | while (m.next().? == .PipePipe) { | |
| 6116 | while (m.next().? == .pipe_pipe) { | |
| 6074 | 6117 | const lhs = try macroIntToBool(c, node); |
| 6075 | 6118 | const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope)); |
| 6076 | 6119 | node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6081,7 +6124,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6081 | 6124 | |
| 6082 | 6125 | fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6083 | 6126 | var node = try parseCBitOrExpr(c, m, scope); |
| 6084 | while (m.next().? == .AmpersandAmpersand) { | |
| 6127 | while (m.next().? == .ampersand_ampersand) { | |
| 6085 | 6128 | const lhs = try macroIntToBool(c, node); |
| 6086 | 6129 | const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope)); |
| 6087 | 6130 | node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6092,7 +6135,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6092 | 6135 | |
| 6093 | 6136 | fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6094 | 6137 | var node = try parseCBitXorExpr(c, m, scope); |
| 6095 | while (m.next().? == .Pipe) { | |
| 6138 | while (m.next().? == .pipe) { | |
| 6096 | 6139 | const lhs = try macroIntFromBool(c, node); |
| 6097 | 6140 | const rhs = try macroIntFromBool(c, try parseCBitXorExpr(c, m, scope)); |
| 6098 | 6141 | node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6103,7 +6146,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6103 | 6146 | |
| 6104 | 6147 | fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6105 | 6148 | var node = try parseCBitAndExpr(c, m, scope); |
| 6106 | while (m.next().? == .Caret) { | |
| 6149 | while (m.next().? == .caret) { | |
| 6107 | 6150 | const lhs = try macroIntFromBool(c, node); |
| 6108 | 6151 | const rhs = try macroIntFromBool(c, try parseCBitAndExpr(c, m, scope)); |
| 6109 | 6152 | node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6114,7 +6157,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6114 | 6157 | |
| 6115 | 6158 | fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6116 | 6159 | var node = try parseCEqExpr(c, m, scope); |
| 6117 | while (m.next().? == .Ampersand) { | |
| 6160 | while (m.next().? == .ampersand) { | |
| 6118 | 6161 | const lhs = try macroIntFromBool(c, node); |
| 6119 | 6162 | const rhs = try macroIntFromBool(c, try parseCEqExpr(c, m, scope)); |
| 6120 | 6163 | node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6127,13 +6170,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6127 | 6170 | var node = try parseCRelExpr(c, m, scope); |
| 6128 | 6171 | while (true) { |
| 6129 | 6172 | switch (m.peek().?) { |
| 6130 | .BangEqual => { | |
| 6173 | .bang_equal => { | |
| 6131 | 6174 | _ = m.next(); |
| 6132 | 6175 | const lhs = try macroIntFromBool(c, node); |
| 6133 | 6176 | const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope)); |
| 6134 | 6177 | node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6135 | 6178 | }, |
| 6136 | .EqualEqual => { | |
| 6179 | .equal_equal => { | |
| 6137 | 6180 | _ = m.next(); |
| 6138 | 6181 | const lhs = try macroIntFromBool(c, node); |
| 6139 | 6182 | const rhs = try macroIntFromBool(c, try parseCRelExpr(c, m, scope)); |
| ... | ... | @@ -6148,25 +6191,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6148 | 6191 | var node = try parseCShiftExpr(c, m, scope); |
| 6149 | 6192 | while (true) { |
| 6150 | 6193 | switch (m.peek().?) { |
| 6151 | .AngleBracketRight => { | |
| 6194 | .angle_bracket_right => { | |
| 6152 | 6195 | _ = m.next(); |
| 6153 | 6196 | const lhs = try macroIntFromBool(c, node); |
| 6154 | 6197 | const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); |
| 6155 | 6198 | node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6156 | 6199 | }, |
| 6157 | .AngleBracketRightEqual => { | |
| 6200 | .angle_bracket_right_equal => { | |
| 6158 | 6201 | _ = m.next(); |
| 6159 | 6202 | const lhs = try macroIntFromBool(c, node); |
| 6160 | 6203 | const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); |
| 6161 | 6204 | node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6162 | 6205 | }, |
| 6163 | .AngleBracketLeft => { | |
| 6206 | .angle_bracket_left => { | |
| 6164 | 6207 | _ = m.next(); |
| 6165 | 6208 | const lhs = try macroIntFromBool(c, node); |
| 6166 | 6209 | const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); |
| 6167 | 6210 | node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6168 | 6211 | }, |
| 6169 | .AngleBracketLeftEqual => { | |
| 6212 | .angle_bracket_left_equal => { | |
| 6170 | 6213 | _ = m.next(); |
| 6171 | 6214 | const lhs = try macroIntFromBool(c, node); |
| 6172 | 6215 | const rhs = try macroIntFromBool(c, try parseCShiftExpr(c, m, scope)); |
| ... | ... | @@ -6181,13 +6224,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6181 | 6224 | var node = try parseCAddSubExpr(c, m, scope); |
| 6182 | 6225 | while (true) { |
| 6183 | 6226 | switch (m.peek().?) { |
| 6184 | .AngleBracketAngleBracketLeft => { | |
| 6227 | .angle_bracket_angle_bracket_left => { | |
| 6185 | 6228 | _ = m.next(); |
| 6186 | 6229 | const lhs = try macroIntFromBool(c, node); |
| 6187 | 6230 | const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope)); |
| 6188 | 6231 | node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6189 | 6232 | }, |
| 6190 | .AngleBracketAngleBracketRight => { | |
| 6233 | .angle_bracket_angle_bracket_right => { | |
| 6191 | 6234 | _ = m.next(); |
| 6192 | 6235 | const lhs = try macroIntFromBool(c, node); |
| 6193 | 6236 | const rhs = try macroIntFromBool(c, try parseCAddSubExpr(c, m, scope)); |
| ... | ... | @@ -6202,13 +6245,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6202 | 6245 | var node = try parseCMulExpr(c, m, scope); |
| 6203 | 6246 | while (true) { |
| 6204 | 6247 | switch (m.peek().?) { |
| 6205 | .Plus => { | |
| 6248 | .plus => { | |
| 6206 | 6249 | _ = m.next(); |
| 6207 | 6250 | const lhs = try macroIntFromBool(c, node); |
| 6208 | 6251 | const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope)); |
| 6209 | 6252 | node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6210 | 6253 | }, |
| 6211 | .Minus => { | |
| 6254 | .minus => { | |
| 6212 | 6255 | _ = m.next(); |
| 6213 | 6256 | const lhs = try macroIntFromBool(c, node); |
| 6214 | 6257 | const rhs = try macroIntFromBool(c, try parseCMulExpr(c, m, scope)); |
| ... | ... | @@ -6223,17 +6266,17 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6223 | 6266 | var node = try parseCCastExpr(c, m, scope); |
| 6224 | 6267 | while (true) { |
| 6225 | 6268 | switch (m.next().?) { |
| 6226 | .Asterisk => { | |
| 6269 | .asterisk => { | |
| 6227 | 6270 | const lhs = try macroIntFromBool(c, node); |
| 6228 | 6271 | const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); |
| 6229 | 6272 | node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); |
| 6230 | 6273 | }, |
| 6231 | .Slash => { | |
| 6274 | .slash => { | |
| 6232 | 6275 | const lhs = try macroIntFromBool(c, node); |
| 6233 | 6276 | const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); |
| 6234 | 6277 | node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .div, .lhs = lhs, .rhs = rhs }); |
| 6235 | 6278 | }, |
| 6236 | .Percent => { | |
| 6279 | .percent => { | |
| 6237 | 6280 | const lhs = try macroIntFromBool(c, node); |
| 6238 | 6281 | const rhs = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); |
| 6239 | 6282 | node = try Tag.macro_arithmetic.create(c.arena, .{ .op = .rem, .lhs = lhs, .rhs = rhs }); |
| ... | ... | @@ -6248,17 +6291,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6248 | 6291 | |
| 6249 | 6292 | fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6250 | 6293 | switch (m.next().?) { |
| 6251 | .LParen => { | |
| 6294 | .l_paren => { | |
| 6252 | 6295 | if (try parseCTypeName(c, m, scope, true)) |type_name| { |
| 6253 | 6296 | while (true) { |
| 6254 | 6297 | const next_token = m.next().?; |
| 6255 | 6298 | switch (next_token) { |
| 6256 | .RParen => break, | |
| 6299 | .r_paren => break, | |
| 6257 | 6300 | else => |next_tag| { |
| 6258 | 6301 | // Skip trailing blank defined before the RParen. |
| 6259 | if (next_tag == .Identifier and c.global_scope.blank_macros.contains(m.slice())) { | |
| 6302 | if ((next_tag == .identifier or next_tag == .extended_identifier) and | |
| 6303 | c.global_scope.blank_macros.contains(m.slice())) | |
| 6260 | 6304 | continue; |
| 6261 | } | |
| 6305 | ||
| 6262 | 6306 | try m.fail( |
| 6263 | 6307 | c, |
| 6264 | 6308 | "unable to translate C expr: expected ')' instead got '{s}'", |
| ... | ... | @@ -6268,7 +6312,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6268 | 6312 | }, |
| 6269 | 6313 | } |
| 6270 | 6314 | } |
| 6271 | if (m.peek().? == .LBrace) { | |
| 6315 | if (m.peek().? == .l_brace) { | |
| 6272 | 6316 | // initializer list |
| 6273 | 6317 | return parseCPostfixExpr(c, m, scope, type_name); |
| 6274 | 6318 | } |
| ... | ... | @@ -6294,7 +6338,7 @@ fn parseCTypeName(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) Pa |
| 6294 | 6338 | fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_fail: bool) ParseError!?Node { |
| 6295 | 6339 | const tok = m.next().?; |
| 6296 | 6340 | switch (tok) { |
| 6297 | .Identifier => { | |
| 6341 | .identifier, .extended_identifier => { | |
| 6298 | 6342 | if (c.global_scope.blank_macros.contains(m.slice())) { |
| 6299 | 6343 | return try parseCSpecifierQualifierList(c, m, scope, allow_fail); |
| 6300 | 6344 | } |
| ... | ... | @@ -6304,25 +6348,25 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_ |
| 6304 | 6348 | return try Tag.identifier.create(c.arena, mangled_name); |
| 6305 | 6349 | } |
| 6306 | 6350 | }, |
| 6307 | .Keyword_void => return try Tag.type.create(c.arena, "anyopaque"), | |
| 6308 | .Keyword_bool => return try Tag.type.create(c.arena, "bool"), | |
| 6309 | .Keyword_char, | |
| 6310 | .Keyword_int, | |
| 6311 | .Keyword_short, | |
| 6312 | .Keyword_long, | |
| 6313 | .Keyword_float, | |
| 6314 | .Keyword_double, | |
| 6315 | .Keyword_signed, | |
| 6316 | .Keyword_unsigned, | |
| 6317 | .Keyword_complex, | |
| 6351 | .keyword_void => return try Tag.type.create(c.arena, "anyopaque"), | |
| 6352 | .keyword_bool => return try Tag.type.create(c.arena, "bool"), | |
| 6353 | .keyword_char, | |
| 6354 | .keyword_int, | |
| 6355 | .keyword_short, | |
| 6356 | .keyword_long, | |
| 6357 | .keyword_float, | |
| 6358 | .keyword_double, | |
| 6359 | .keyword_signed, | |
| 6360 | .keyword_unsigned, | |
| 6361 | .keyword_complex, | |
| 6318 | 6362 | => { |
| 6319 | 6363 | m.i -= 1; |
| 6320 | 6364 | return try parseCNumericType(c, m); |
| 6321 | 6365 | }, |
| 6322 | .Keyword_enum, .Keyword_struct, .Keyword_union => { | |
| 6366 | .keyword_enum, .keyword_struct, .keyword_union => { | |
| 6323 | 6367 | // struct Foo will be declared as struct_Foo by transRecordDecl |
| 6324 | 6368 | const slice = m.slice(); |
| 6325 | try m.skip(c, .Identifier); | |
| 6369 | try m.skip(c, .identifier); | |
| 6326 | 6370 | |
| 6327 | 6371 | const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() }); |
| 6328 | 6372 | return try Tag.identifier.create(c.arena, name); |
| ... | ... | @@ -6364,15 +6408,15 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node { |
| 6364 | 6408 | var i: u8 = 0; |
| 6365 | 6409 | while (i < math.maxInt(u8)) : (i += 1) { |
| 6366 | 6410 | switch (m.next().?) { |
| 6367 | .Keyword_double => kw.double += 1, | |
| 6368 | .Keyword_long => kw.long += 1, | |
| 6369 | .Keyword_int => kw.int += 1, | |
| 6370 | .Keyword_float => kw.float += 1, | |
| 6371 | .Keyword_short => kw.short += 1, | |
| 6372 | .Keyword_char => kw.char += 1, | |
| 6373 | .Keyword_unsigned => kw.unsigned += 1, | |
| 6374 | .Keyword_signed => kw.signed += 1, | |
| 6375 | .Keyword_complex => kw.complex += 1, | |
| 6411 | .keyword_double => kw.double += 1, | |
| 6412 | .keyword_long => kw.long += 1, | |
| 6413 | .keyword_int => kw.int += 1, | |
| 6414 | .keyword_float => kw.float += 1, | |
| 6415 | .keyword_short => kw.short += 1, | |
| 6416 | .keyword_char => kw.char += 1, | |
| 6417 | .keyword_unsigned => kw.unsigned += 1, | |
| 6418 | .keyword_signed => kw.signed += 1, | |
| 6419 | .keyword_complex => kw.complex += 1, | |
| 6376 | 6420 | else => { |
| 6377 | 6421 | m.i -= 1; |
| 6378 | 6422 | break; |
| ... | ... | @@ -6442,11 +6486,11 @@ fn parseCNumericType(c: *Context, m: *MacroCtx) ParseError!Node { |
| 6442 | 6486 | |
| 6443 | 6487 | fn parseCAbstractDeclarator(c: *Context, m: *MacroCtx, node: Node) ParseError!Node { |
| 6444 | 6488 | switch (m.next().?) { |
| 6445 | .Asterisk => { | |
| 6489 | .asterisk => { | |
| 6446 | 6490 | // last token of `node` |
| 6447 | 6491 | const prev_id = m.list[m.i - 1].id; |
| 6448 | 6492 | |
| 6449 | if (prev_id == .Keyword_void) { | |
| 6493 | if (prev_id == .keyword_void) { | |
| 6450 | 6494 | const ptr = try Tag.single_pointer.create(c.arena, .{ |
| 6451 | 6495 | .is_const = false, |
| 6452 | 6496 | .is_volatile = false, |
| ... | ... | @@ -6472,28 +6516,28 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6472 | 6516 | var node = type_name orelse try parseCPrimaryExpr(c, m, scope); |
| 6473 | 6517 | while (true) { |
| 6474 | 6518 | switch (m.next().?) { |
| 6475 | .Period => { | |
| 6476 | try m.skip(c, .Identifier); | |
| 6519 | .period => { | |
| 6520 | try m.skip(c, .identifier); | |
| 6477 | 6521 | |
| 6478 | 6522 | node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() }); |
| 6479 | 6523 | }, |
| 6480 | .Arrow => { | |
| 6481 | try m.skip(c, .Identifier); | |
| 6524 | .arrow => { | |
| 6525 | try m.skip(c, .identifier); | |
| 6482 | 6526 | |
| 6483 | 6527 | const deref = try Tag.deref.create(c.arena, node); |
| 6484 | 6528 | node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() }); |
| 6485 | 6529 | }, |
| 6486 | .LBracket => { | |
| 6530 | .l_bracket => { | |
| 6487 | 6531 | const index_val = try macroIntFromBool(c, try parseCExpr(c, m, scope)); |
| 6488 | 6532 | const index = try Tag.as.create(c.arena, .{ |
| 6489 | 6533 | .lhs = try Tag.type.create(c.arena, "usize"), |
| 6490 | 6534 | .rhs = try Tag.int_cast.create(c.arena, index_val), |
| 6491 | 6535 | }); |
| 6492 | 6536 | node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index }); |
| 6493 | try m.skip(c, .RBracket); | |
| 6537 | try m.skip(c, .r_bracket); | |
| 6494 | 6538 | }, |
| 6495 | .LParen => { | |
| 6496 | if (m.peek().? == .RParen) { | |
| 6539 | .l_paren => { | |
| 6540 | if (m.peek().? == .r_paren) { | |
| 6497 | 6541 | m.i += 1; |
| 6498 | 6542 | node = try Tag.call.create(c.arena, .{ .lhs = node, .args = &[0]Node{} }); |
| 6499 | 6543 | } else { |
| ... | ... | @@ -6504,8 +6548,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6504 | 6548 | try args.append(arg); |
| 6505 | 6549 | const next_id = m.next().?; |
| 6506 | 6550 | switch (next_id) { |
| 6507 | .Comma => {}, | |
| 6508 | .RParen => break, | |
| 6551 | .comma => {}, | |
| 6552 | .r_paren => break, | |
| 6509 | 6553 | else => { |
| 6510 | 6554 | try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()}); |
| 6511 | 6555 | return error.ParseError; |
| ... | ... | @@ -6515,24 +6559,24 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6515 | 6559 | node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) }); |
| 6516 | 6560 | } |
| 6517 | 6561 | }, |
| 6518 | .LBrace => { | |
| 6562 | .l_brace => { | |
| 6519 | 6563 | // Check for designated field initializers |
| 6520 | if (m.peek().? == .Period) { | |
| 6564 | if (m.peek().? == .period) { | |
| 6521 | 6565 | var init_vals = std.ArrayList(ast.Payload.ContainerInitDot.Initializer).init(c.gpa); |
| 6522 | 6566 | defer init_vals.deinit(); |
| 6523 | 6567 | |
| 6524 | 6568 | while (true) { |
| 6525 | try m.skip(c, .Period); | |
| 6526 | try m.skip(c, .Identifier); | |
| 6569 | try m.skip(c, .period); | |
| 6570 | try m.skip(c, .identifier); | |
| 6527 | 6571 | const name = m.slice(); |
| 6528 | try m.skip(c, .Equal); | |
| 6572 | try m.skip(c, .equal); | |
| 6529 | 6573 | |
| 6530 | 6574 | const val = try parseCCondExpr(c, m, scope); |
| 6531 | 6575 | try init_vals.append(.{ .name = name, .value = val }); |
| 6532 | 6576 | const next_id = m.next().?; |
| 6533 | 6577 | switch (next_id) { |
| 6534 | .Comma => {}, | |
| 6535 | .RBrace => break, | |
| 6578 | .comma => {}, | |
| 6579 | .r_brace => break, | |
| 6536 | 6580 | else => { |
| 6537 | 6581 | try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()}); |
| 6538 | 6582 | return error.ParseError; |
| ... | ... | @@ -6552,8 +6596,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6552 | 6596 | try init_vals.append(val); |
| 6553 | 6597 | const next_id = m.next().?; |
| 6554 | 6598 | switch (next_id) { |
| 6555 | .Comma => {}, | |
| 6556 | .RBrace => break, | |
| 6599 | .comma => {}, | |
| 6600 | .r_brace => break, | |
| 6557 | 6601 | else => { |
| 6558 | 6602 | try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()}); |
| 6559 | 6603 | return error.ParseError; |
| ... | ... | @@ -6563,7 +6607,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6563 | 6607 | const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items)); |
| 6564 | 6608 | node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node }); |
| 6565 | 6609 | }, |
| 6566 | .PlusPlus, .MinusMinus => { | |
| 6610 | .plus_plus, .minus_minus => { | |
| 6567 | 6611 | try m.fail(c, "TODO postfix inc/dec expr", .{}); |
| 6568 | 6612 | return error.ParseError; |
| 6569 | 6613 | }, |
| ... | ... | @@ -6577,47 +6621,47 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node) |
| 6577 | 6621 | |
| 6578 | 6622 | fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { |
| 6579 | 6623 | switch (m.next().?) { |
| 6580 | .Bang => { | |
| 6624 | .bang => { | |
| 6581 | 6625 | const operand = try macroIntToBool(c, try parseCCastExpr(c, m, scope)); |
| 6582 | 6626 | return Tag.not.create(c.arena, operand); |
| 6583 | 6627 | }, |
| 6584 | .Minus => { | |
| 6628 | .minus => { | |
| 6585 | 6629 | const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); |
| 6586 | 6630 | return Tag.negate.create(c.arena, operand); |
| 6587 | 6631 | }, |
| 6588 | .Plus => return try parseCCastExpr(c, m, scope), | |
| 6589 | .Tilde => { | |
| 6632 | .plus => return try parseCCastExpr(c, m, scope), | |
| 6633 | .tilde => { | |
| 6590 | 6634 | const operand = try macroIntFromBool(c, try parseCCastExpr(c, m, scope)); |
| 6591 | 6635 | return Tag.bit_not.create(c.arena, operand); |
| 6592 | 6636 | }, |
| 6593 | .Asterisk => { | |
| 6637 | .asterisk => { | |
| 6594 | 6638 | const operand = try parseCCastExpr(c, m, scope); |
| 6595 | 6639 | return Tag.deref.create(c.arena, operand); |
| 6596 | 6640 | }, |
| 6597 | .Ampersand => { | |
| 6641 | .ampersand => { | |
| 6598 | 6642 | const operand = try parseCCastExpr(c, m, scope); |
| 6599 | 6643 | return Tag.address_of.create(c.arena, operand); |
| 6600 | 6644 | }, |
| 6601 | .Keyword_sizeof => { | |
| 6602 | const operand = if (m.peek().? == .LParen) blk: { | |
| 6645 | .keyword_sizeof => { | |
| 6646 | const operand = if (m.peek().? == .l_paren) blk: { | |
| 6603 | 6647 | _ = m.next(); |
| 6604 | 6648 | const inner = (try parseCTypeName(c, m, scope, false)).?; |
| 6605 | try m.skip(c, .RParen); | |
| 6649 | try m.skip(c, .r_paren); | |
| 6606 | 6650 | break :blk inner; |
| 6607 | 6651 | } else try parseCUnaryExpr(c, m, scope); |
| 6608 | 6652 | |
| 6609 | 6653 | return Tag.helpers_sizeof.create(c.arena, operand); |
| 6610 | 6654 | }, |
| 6611 | .Keyword_alignof => { | |
| 6655 | .keyword_alignof => { | |
| 6612 | 6656 | // TODO this won't work if using <stdalign.h>'s |
| 6613 | 6657 | // #define alignof _Alignof |
| 6614 | try m.skip(c, .LParen); | |
| 6658 | try m.skip(c, .l_paren); | |
| 6615 | 6659 | const operand = (try parseCTypeName(c, m, scope, false)).?; |
| 6616 | try m.skip(c, .RParen); | |
| 6660 | try m.skip(c, .r_paren); | |
| 6617 | 6661 | |
| 6618 | 6662 | return Tag.alignof.create(c.arena, operand); |
| 6619 | 6663 | }, |
| 6620 | .PlusPlus, .MinusMinus => { | |
| 6664 | .plus_plus, .minus_minus => { | |
| 6621 | 6665 | try m.fail(c, "TODO unary inc/dec expr", .{}); |
| 6622 | 6666 | return error.ParseError; |
| 6623 | 6667 | }, |
test/translate_c.zig+7-7| ... | ... | @@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 424 | 424 | \\ }); |
| 425 | 425 | \\} |
| 426 | 426 | , |
| 427 | \\pub const B = A(@as(f32, 0.0)); | |
| 427 | \\pub const B = A(@as(f32, 0)); | |
| 428 | 428 | }); |
| 429 | 429 | |
| 430 | 430 | cases.add("complex switch", |
| ... | ... | @@ -633,7 +633,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 633 | 633 | cases.add("#define hex literal with capital X", |
| 634 | 634 | \\#define VAL 0XF00D |
| 635 | 635 | , &[_][]const u8{ |
| 636 | \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hexadecimal); | |
| 636 | \\pub const VAL = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xF00D, .hex); | |
| 637 | 637 | }); |
| 638 | 638 | |
| 639 | 639 | cases.add("anonymous struct & unions", |
| ... | ... | @@ -1243,12 +1243,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1243 | 1243 | \\extern const long double my_extended_precision_longdouble = 1.0000000000000003l; |
| 1244 | 1244 | , &([_][]const u8{ |
| 1245 | 1245 | "pub const foo = @as(f32, 3.14);", |
| 1246 | "pub const bar = @as(c_longdouble, 16.0e-2);", | |
| 1246 | "pub const bar = @as(c_longdouble, 16.e-2);", | |
| 1247 | 1247 | "pub const FOO = @as(f64, 0.12345);", |
| 1248 | 1248 | "pub const BAR = @as(f64, 0.12345);", |
| 1249 | 1249 | "pub const baz = @as(f64, 1e1);", |
| 1250 | 1250 | "pub const BAZ = @as(f32, 42e-3);", |
| 1251 | "pub const foobar = -@as(c_longdouble, 73.0);", | |
| 1251 | "pub const foobar = -@as(c_longdouble, 73);", | |
| 1252 | 1252 | "pub export const my_float: f32 = 1.0;", |
| 1253 | 1253 | "pub export const my_double: f64 = 1.0;", |
| 1254 | 1254 | "pub export const my_longdouble: c_longdouble = 1.0;", |
| ... | ... | @@ -1272,7 +1272,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1272 | 1272 | "pub const BAR = -@as(f32, 0x8F.BP5);", |
| 1273 | 1273 | "pub const FOOBAR = @as(f64, 0x0P+0);", |
| 1274 | 1274 | "pub const BAZ = -@as(f64, 0x0.0a5dp+12);", |
| 1275 | "pub const FOOBAZ = @as(c_longdouble, 0xfE.0P-1);", | |
| 1275 | "pub const FOOBAZ = @as(c_longdouble, 0xfE.P-1);", | |
| 1276 | 1276 | }); |
| 1277 | 1277 | |
| 1278 | 1278 | cases.add("comments", |
| ... | ... | @@ -3730,7 +3730,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3730 | 3730 | , &[_][]const u8{ |
| 3731 | 3731 | \\pub const NULL = @import("std").zig.c_translation.cast(?*anyopaque, @as(c_int, 0)); |
| 3732 | 3732 | , |
| 3733 | \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hexadecimal)); | |
| 3733 | \\pub const FOO = @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex)); | |
| 3734 | 3734 | }); |
| 3735 | 3735 | |
| 3736 | 3736 | if (builtin.abi == .msvc) { |
| ... | ... | @@ -3812,7 +3812,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3812 | 3812 | \\pub const MAY_NEED_PROMOTION_1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 10241024, .decimal); |
| 3813 | 3813 | \\pub const MAY_NEED_PROMOTION_2 = @import("std").zig.c_translation.promoteIntLiteral(c_long, 307230723072, .decimal); |
| 3814 | 3814 | \\pub const MAY_NEED_PROMOTION_3 = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 819281928192, .decimal); |
| 3815 | \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hexadecimal); | |
| 3815 | \\pub const MAY_NEED_PROMOTION_HEX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000000, .hex); | |
| 3816 | 3816 | \\pub const MAY_NEED_PROMOTION_OCT = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0o20000000000, .octal); |
| 3817 | 3817 | }); |
| 3818 | 3818 |