| author | |
| committer | |
| log | cf7a5b7a4a77181a4c90fc9a92df496cfb48c3cd |
| tree | c8614c7c0d818c2e787068498984792d7b70be00 |
| parent | e65b9e8f7bcc38943f48ed44560a22c62ca222ce |
| signature | Commit is signed but in an unrecognized format. |
4 files changed, 154 insertions(+), 105 deletions(-)
src-self-hosted/c_tokenizer.zig+55-53| ... | @@ -27,6 +27,7 @@ pub const CToken = struct { | ... | @@ -27,6 +27,7 @@ pub const CToken = struct { |
| 27 | Lt, | 27 | Lt, |
| 28 | Comma, | 28 | Comma, |
| 29 | Fn, | 29 | Fn, |
| 30 | Arrow, | ||
| 30 | }; | 31 | }; |
| 31 | 32 | ||
| 32 | pub const NumLitSuffix = enum { | 33 | pub const NumLitSuffix = enum { |
| ... | @@ -164,6 +165,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -164,6 +165,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 164 | NumLitIntSuffixL, | 165 | NumLitIntSuffixL, |
| 165 | NumLitIntSuffixLL, | 166 | NumLitIntSuffixLL, |
| 166 | NumLitIntSuffixUL, | 167 | NumLitIntSuffixUL, |
| 168 | Minus, | ||
| 169 | Done, | ||
| 167 | } = .Start; | 170 | } = .Start; |
| 168 | 171 | ||
| 169 | var result = CToken{ | 172 | var result = CToken{ |
| ... | @@ -178,9 +181,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -178,9 +181,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 178 | const c = chars[i.*]; | 181 | const c = chars[i.*]; |
| 179 | if (c == 0) { | 182 | if (c == 0) { |
| 180 | switch (state) { | 183 | switch (state) { |
| 181 | .Start => { | ||
| 182 | return result; | ||
| 183 | }, | ||
| 184 | .Identifier, | 184 | .Identifier, |
| 185 | .Decimal, | 185 | .Decimal, |
| 186 | .Hex, | 186 | .Hex, |
| ... | @@ -193,6 +193,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -193,6 +193,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 193 | result.bytes = chars[begin_index..i.*]; | 193 | result.bytes = chars[begin_index..i.*]; |
| 194 | return result; | 194 | return result; |
| 195 | }, | 195 | }, |
| 196 | .Start, | ||
| 197 | .Minus, | ||
| 198 | .Done, | ||
| 196 | .NumLitIntSuffixU, | 199 | .NumLitIntSuffixU, |
| 197 | .NumLitIntSuffixL, | 200 | .NumLitIntSuffixL, |
| 198 | .NumLitIntSuffixUL, | 201 | .NumLitIntSuffixUL, |
| ... | @@ -212,7 +215,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -212,7 +215,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 212 | => return error.TokenizingFailed, | 215 | => return error.TokenizingFailed, |
| 213 | } | 216 | } |
| 214 | } | 217 | } |
| 215 | i.* += 1; | ||
| 216 | switch (state) { | 218 | switch (state) { |
| 217 | .Start => { | 219 | .Start => { |
| 218 | switch (c) { | 220 | switch (c) { |
| ... | @@ -220,12 +222,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -220,12 +222,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 220 | '\'' => { | 222 | '\'' => { |
| 221 | state = .CharLit; | 223 | state = .CharLit; |
| 222 | result.id = .CharLit; | 224 | result.id = .CharLit; |
| 223 | begin_index = i.* - 1; | 225 | begin_index = i.*; |
| 224 | }, | 226 | }, |
| 225 | '\"' => { | 227 | '\"' => { |
| 226 | state = .String; | 228 | state = .String; |
| 227 | result.id = .StrLit; | 229 | result.id = .StrLit; |
| 228 | begin_index = i.* - 1; | 230 | begin_index = i.*; |
| 229 | }, | 231 | }, |
| 230 | '/' => { | 232 | '/' => { |
| 231 | state = .OpenComment; | 233 | state = .OpenComment; |
| ... | @@ -239,21 +241,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -239,21 +241,21 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 239 | 'a'...'z', 'A'...'Z', '_' => { | 241 | 'a'...'z', 'A'...'Z', '_' => { |
| 240 | state = .Identifier; | 242 | state = .Identifier; |
| 241 | result.id = .Identifier; | 243 | result.id = .Identifier; |
| 242 | begin_index = i.* - 1; | 244 | begin_index = i.*; |
| 243 | }, | 245 | }, |
| 244 | '1'...'9' => { | 246 | '1'...'9' => { |
| 245 | state = .Decimal; | 247 | state = .Decimal; |
| 246 | result.id = .NumLitInt; | 248 | result.id = .NumLitInt; |
| 247 | begin_index = i.* - 1; | 249 | begin_index = i.*; |
| 248 | }, | 250 | }, |
| 249 | '0' => { | 251 | '0' => { |
| 250 | state = .GotZero; | 252 | state = .GotZero; |
| 251 | result.id = .NumLitInt; | 253 | result.id = .NumLitInt; |
| 252 | begin_index = i.* - 1; | 254 | begin_index = i.*; |
| 253 | }, | 255 | }, |
| 254 | '.' => { | 256 | '.' => { |
| 255 | result.id = .Dot; | 257 | result.id = .Dot; |
| 256 | return result; | 258 | state = .Done; |
| 257 | }, | 259 | }, |
| 258 | '<' => { | 260 | '<' => { |
| 259 | result.id = .Lt; | 261 | result.id = .Lt; |
| ... | @@ -261,40 +263,52 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -261,40 +263,52 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 261 | }, | 263 | }, |
| 262 | '(' => { | 264 | '(' => { |
| 263 | result.id = .LParen; | 265 | result.id = .LParen; |
| 264 | return result; | 266 | state = .Done; |
| 265 | }, | 267 | }, |
| 266 | ')' => { | 268 | ')' => { |
| 267 | result.id = .RParen; | 269 | result.id = .RParen; |
| 268 | return result; | 270 | state = .Done; |
| 269 | }, | 271 | }, |
| 270 | '*' => { | 272 | '*' => { |
| 271 | result.id = .Asterisk; | 273 | result.id = .Asterisk; |
| 272 | return result; | 274 | state = .Done; |
| 273 | }, | 275 | }, |
| 274 | '-' => { | 276 | '-' => { |
| 277 | state = .Minus; | ||
| 275 | result.id = .Minus; | 278 | result.id = .Minus; |
| 276 | return result; | ||
| 277 | }, | 279 | }, |
| 278 | '!' => { | 280 | '!' => { |
| 279 | result.id = .Bang; | 281 | result.id = .Bang; |
| 280 | return result; | 282 | state = .Done; |
| 281 | }, | 283 | }, |
| 282 | '~' => { | 284 | '~' => { |
| 283 | result.id = .Tilde; | 285 | result.id = .Tilde; |
| 284 | return result; | 286 | state = .Done; |
| 285 | }, | 287 | }, |
| 286 | ',' => { | 288 | ',' => { |
| 287 | result.id = .Comma; | 289 | result.id = .Comma; |
| 288 | return result; | 290 | state = .Done; |
| 289 | }, | 291 | }, |
| 290 | else => return error.TokenizingFailed, | 292 | else => return error.TokenizingFailed, |
| 291 | } | 293 | } |
| 292 | }, | 294 | }, |
| 295 | .Done => return result, | ||
| 296 | .Minus => { | ||
| 297 | switch (c) { | ||
| 298 | '>' => { | ||
| 299 | result.id = .Arrow; | ||
| 300 | state = .Done; | ||
| 301 | }, | ||
| 302 | else => { | ||
| 303 | return result; | ||
| 304 | }, | ||
| 305 | } | ||
| 306 | }, | ||
| 293 | .GotLt => { | 307 | .GotLt => { |
| 294 | switch (c) { | 308 | switch (c) { |
| 295 | '<' => { | 309 | '<' => { |
| 296 | result.id = .Shl; | 310 | result.id = .Shl; |
| 297 | return result; | 311 | state = .Done; |
| 298 | }, | 312 | }, |
| 299 | else => { | 313 | else => { |
| 300 | return result; | 314 | return result; |
| ... | @@ -310,19 +324,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -310,19 +324,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 310 | 'f', | 324 | 'f', |
| 311 | 'F', | 325 | 'F', |
| 312 | => { | 326 | => { |
| 313 | i.* -= 1; | ||
| 314 | result.num_lit_suffix = .F; | 327 | result.num_lit_suffix = .F; |
| 315 | result.bytes = chars[begin_index..i.*]; | 328 | result.bytes = chars[begin_index..i.*]; |
| 316 | return result; | 329 | state = .Done; |
| 317 | }, | 330 | }, |
| 318 | 'l', 'L' => { | 331 | 'l', 'L' => { |
| 319 | i.* -= 1; | ||
| 320 | result.num_lit_suffix = .L; | 332 | result.num_lit_suffix = .L; |
| 321 | result.bytes = chars[begin_index..i.*]; | 333 | result.bytes = chars[begin_index..i.*]; |
| 322 | return result; | 334 | state = .Done; |
| 323 | }, | 335 | }, |
| 324 | else => { | 336 | else => { |
| 325 | i.* -= 1; | ||
| 326 | result.bytes = chars[begin_index..i.*]; | 337 | result.bytes = chars[begin_index..i.*]; |
| 327 | return result; | 338 | return result; |
| 328 | }, | 339 | }, |
| ... | @@ -352,16 +363,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -352,16 +363,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 352 | '0'...'9' => {}, | 363 | '0'...'9' => {}, |
| 353 | 'f', 'F' => { | 364 | 'f', 'F' => { |
| 354 | result.num_lit_suffix = .F; | 365 | result.num_lit_suffix = .F; |
| 355 | result.bytes = chars[begin_index .. i.* - 1]; | 366 | result.bytes = chars[begin_index..i.*]; |
| 356 | return result; | 367 | state = .Done; |
| 357 | }, | 368 | }, |
| 358 | 'l', 'L' => { | 369 | 'l', 'L' => { |
| 359 | result.num_lit_suffix = .L; | 370 | result.num_lit_suffix = .L; |
| 360 | result.bytes = chars[begin_index .. i.* - 1]; | 371 | result.bytes = chars[begin_index..i.*]; |
| 361 | return result; | 372 | state = .Done; |
| 362 | }, | 373 | }, |
| 363 | else => { | 374 | else => { |
| 364 | i.* -= 1; | ||
| 365 | result.bytes = chars[begin_index..i.*]; | 375 | result.bytes = chars[begin_index..i.*]; |
| 366 | return result; | 376 | return result; |
| 367 | }, | 377 | }, |
| ... | @@ -374,19 +384,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -374,19 +384,18 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 374 | 'u', 'U' => { | 384 | 'u', 'U' => { |
| 375 | state = .NumLitIntSuffixU; | 385 | state = .NumLitIntSuffixU; |
| 376 | result.num_lit_suffix = .U; | 386 | result.num_lit_suffix = .U; |
| 377 | result.bytes = chars[begin_index .. i.* - 1]; | 387 | result.bytes = chars[begin_index..i.*]; |
| 378 | }, | 388 | }, |
| 379 | 'l', 'L' => { | 389 | 'l', 'L' => { |
| 380 | state = .NumLitIntSuffixL; | 390 | state = .NumLitIntSuffixL; |
| 381 | result.num_lit_suffix = .L; | 391 | result.num_lit_suffix = .L; |
| 382 | result.bytes = chars[begin_index .. i.* - 1]; | 392 | result.bytes = chars[begin_index..i.*]; |
| 383 | }, | 393 | }, |
| 384 | '.' => { | 394 | '.' => { |
| 385 | result.id = .NumLitFloat; | 395 | result.id = .NumLitFloat; |
| 386 | state = .Float; | 396 | state = .Float; |
| 387 | }, | 397 | }, |
| 388 | else => { | 398 | else => { |
| 389 | i.* -= 1; | ||
| 390 | result.bytes = chars[begin_index..i.*]; | 399 | result.bytes = chars[begin_index..i.*]; |
| 391 | return result; | 400 | return result; |
| 392 | }, | 401 | }, |
| ... | @@ -407,12 +416,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -407,12 +416,12 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 407 | 'u', 'U' => { | 416 | 'u', 'U' => { |
| 408 | state = .NumLitIntSuffixU; | 417 | state = .NumLitIntSuffixU; |
| 409 | result.num_lit_suffix = .U; | 418 | result.num_lit_suffix = .U; |
| 410 | result.bytes = chars[begin_index .. i.* - 1]; | 419 | result.bytes = chars[begin_index..i.*]; |
| 411 | }, | 420 | }, |
| 412 | 'l', 'L' => { | 421 | 'l', 'L' => { |
| 413 | state = .NumLitIntSuffixL; | 422 | state = .NumLitIntSuffixL; |
| 414 | result.num_lit_suffix = .L; | 423 | result.num_lit_suffix = .L; |
| 415 | result.bytes = chars[begin_index .. i.* - 1]; | 424 | result.bytes = chars[begin_index..i.*]; |
| 416 | }, | 425 | }, |
| 417 | else => { | 426 | else => { |
| 418 | i.* -= 1; | 427 | i.* -= 1; |
| ... | @@ -425,7 +434,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -425,7 +434,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 425 | '0'...'7' => {}, | 434 | '0'...'7' => {}, |
| 426 | '8', '9' => return error.TokenizingFailed, | 435 | '8', '9' => return error.TokenizingFailed, |
| 427 | else => { | 436 | else => { |
| 428 | i.* -= 1; | ||
| 429 | result.bytes = chars[begin_index..i.*]; | 437 | result.bytes = chars[begin_index..i.*]; |
| 430 | return result; | 438 | return result; |
| 431 | }, | 439 | }, |
| ... | @@ -438,16 +446,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -438,16 +446,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 438 | // marks the number literal as unsigned | 446 | // marks the number literal as unsigned |
| 439 | state = .NumLitIntSuffixU; | 447 | state = .NumLitIntSuffixU; |
| 440 | result.num_lit_suffix = .U; | 448 | result.num_lit_suffix = .U; |
| 441 | result.bytes = chars[begin_index .. i.* - 1]; | 449 | result.bytes = chars[begin_index..i.*]; |
| 442 | }, | 450 | }, |
| 443 | 'l', 'L' => { | 451 | 'l', 'L' => { |
| 444 | // marks the number literal as long | 452 | // marks the number literal as long |
| 445 | state = .NumLitIntSuffixL; | 453 | state = .NumLitIntSuffixL; |
| 446 | result.num_lit_suffix = .L; | 454 | result.num_lit_suffix = .L; |
| 447 | result.bytes = chars[begin_index .. i.* - 1]; | 455 | result.bytes = chars[begin_index..i.*]; |
| 448 | }, | 456 | }, |
| 449 | else => { | 457 | else => { |
| 450 | i.* -= 1; | ||
| 451 | result.bytes = chars[begin_index..i.*]; | 458 | result.bytes = chars[begin_index..i.*]; |
| 452 | return result; | 459 | return result; |
| 453 | }, | 460 | }, |
| ... | @@ -461,16 +468,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -461,16 +468,15 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 461 | // marks the number literal as unsigned | 468 | // marks the number literal as unsigned |
| 462 | state = .NumLitIntSuffixU; | 469 | state = .NumLitIntSuffixU; |
| 463 | result.num_lit_suffix = .U; | 470 | result.num_lit_suffix = .U; |
| 464 | result.bytes = chars[begin_index .. i.* - 1]; | 471 | result.bytes = chars[begin_index..i.*]; |
| 465 | }, | 472 | }, |
| 466 | 'l', 'L' => { | 473 | 'l', 'L' => { |
| 467 | // marks the number literal as long | 474 | // marks the number literal as long |
| 468 | state = .NumLitIntSuffixL; | 475 | state = .NumLitIntSuffixL; |
| 469 | result.num_lit_suffix = .L; | 476 | result.num_lit_suffix = .L; |
| 470 | result.bytes = chars[begin_index .. i.* - 1]; | 477 | result.bytes = chars[begin_index..i.*]; |
| 471 | }, | 478 | }, |
| 472 | else => { | 479 | else => { |
| 473 | i.* -= 1; | ||
| 474 | result.bytes = chars[begin_index..i.*]; | 480 | result.bytes = chars[begin_index..i.*]; |
| 475 | return result; | 481 | return result; |
| 476 | }, | 482 | }, |
| ... | @@ -483,7 +489,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -483,7 +489,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 483 | state = .NumLitIntSuffixUL; | 489 | state = .NumLitIntSuffixUL; |
| 484 | }, | 490 | }, |
| 485 | else => { | 491 | else => { |
| 486 | i.* -= 1; | ||
| 487 | return result; | 492 | return result; |
| 488 | }, | 493 | }, |
| 489 | } | 494 | } |
| ... | @@ -496,10 +501,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -496,10 +501,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 496 | }, | 501 | }, |
| 497 | 'u', 'U' => { | 502 | 'u', 'U' => { |
| 498 | result.num_lit_suffix = .LU; | 503 | result.num_lit_suffix = .LU; |
| 499 | return result; | 504 | state = .Done; |
| 500 | }, | 505 | }, |
| 501 | else => { | 506 | else => { |
| 502 | i.* -= 1; | ||
| 503 | return result; | 507 | return result; |
| 504 | }, | 508 | }, |
| 505 | } | 509 | } |
| ... | @@ -508,10 +512,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -508,10 +512,9 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 508 | switch (c) { | 512 | switch (c) { |
| 509 | 'u', 'U' => { | 513 | 'u', 'U' => { |
| 510 | result.num_lit_suffix = .LLU; | 514 | result.num_lit_suffix = .LLU; |
| 511 | return result; | 515 | state = .Done; |
| 512 | }, | 516 | }, |
| 513 | else => { | 517 | else => { |
| 514 | i.* -= 1; | ||
| 515 | return result; | 518 | return result; |
| 516 | }, | 519 | }, |
| 517 | } | 520 | } |
| ... | @@ -523,7 +526,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -523,7 +526,6 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 523 | return result; | 526 | return result; |
| 524 | }, | 527 | }, |
| 525 | else => { | 528 | else => { |
| 526 | i.* -= 1; | ||
| 527 | return result; | 529 | return result; |
| 528 | }, | 530 | }, |
| 529 | } | 531 | } |
| ... | @@ -532,17 +534,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -532,17 +534,16 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 532 | switch (c) { | 534 | switch (c) { |
| 533 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, | 535 | '_', 'a'...'z', 'A'...'Z', '0'...'9' => {}, |
| 534 | else => { | 536 | else => { |
| 535 | i.* -= 1; | ||
| 536 | result.bytes = chars[begin_index..i.*]; | 537 | result.bytes = chars[begin_index..i.*]; |
| 537 | return result; | 538 | return result; |
| 538 | }, | 539 | }, |
| 539 | } | 540 | } |
| 540 | }, | 541 | }, |
| 541 | .String => { // TODO char escapes | 542 | .String => { |
| 542 | switch (c) { | 543 | switch (c) { |
| 543 | '\"' => { | 544 | '\"' => { |
| 544 | result.bytes = chars[begin_index..i.*]; | 545 | result.bytes = chars[begin_index .. i.* + 1]; |
| 545 | return result; | 546 | state = .Done; |
| 546 | }, | 547 | }, |
| 547 | else => {}, | 548 | else => {}, |
| 548 | } | 549 | } |
| ... | @@ -550,8 +551,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -550,8 +551,8 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 550 | .CharLit => { | 551 | .CharLit => { |
| 551 | switch (c) { | 552 | switch (c) { |
| 552 | '\'' => { | 553 | '\'' => { |
| 553 | result.bytes = chars[begin_index..i.*]; | 554 | result.bytes = chars[begin_index .. i.* + 1]; |
| 554 | return result; | 555 | state = .Done; |
| 555 | }, | 556 | }, |
| 556 | else => {}, | 557 | else => {}, |
| 557 | } | 558 | } |
| ... | @@ -566,7 +567,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -566,7 +567,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 566 | }, | 567 | }, |
| 567 | else => { | 568 | else => { |
| 568 | result.id = .Slash; | 569 | result.id = .Slash; |
| 569 | return result; | 570 | state = .Done; |
| 570 | }, | 571 | }, |
| 571 | } | 572 | } |
| 572 | }, | 573 | }, |
| ... | @@ -598,6 +599,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { | ... | @@ -598,6 +599,7 @@ fn next(chars: [*:0]const u8, i: *usize) !CToken { |
| 598 | } | 599 | } |
| 599 | }, | 600 | }, |
| 600 | } | 601 | } |
| 602 | i.* += 1; | ||
| 601 | } | 603 | } |
| 602 | unreachable; | 604 | unreachable; |
| 603 | } | 605 | } |
src-self-hosted/clang.zig+5-1| ... | @@ -1096,5 +1096,9 @@ pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiter | ... | @@ -1096,5 +1096,9 @@ pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiter |
| 1096 | pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; | 1096 | pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; |
| 1097 | pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; | 1097 | pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; |
| 1098 | 1098 | ||
| 1099 | pub extern fn ZigClangStmtExpr_getSubStmt( *const ZigClangStmtExpr) *const ZigClangCompoundStmt; | 1099 | pub extern fn ZigClangStmtExpr_getSubStmt(*const ZigClangStmtExpr) *const ZigClangCompoundStmt; |
| 1100 | |||
| 1101 | pub extern fn ZigClangMemberExpr_getBase(*const ZigClangMemberExpr) *const ZigClangExpr; | ||
| 1102 | pub extern fn ZigClangMemberExpr_isArrow(*const ZigClangMemberExpr) bool; | ||
| 1103 | pub extern fn ZigClangMemberExpr_getMemberDecl(*const ZigClangMemberExpr) *const ZigClangValueDecl; | ||
| 1100 | 1104 |
src-self-hosted/translate_c.zig+49-35| ... | @@ -49,9 +49,6 @@ const Scope = struct { | ... | @@ -49,9 +49,6 @@ const Scope = struct { |
| 49 | Root, | 49 | Root, |
| 50 | Condition, | 50 | Condition, |
| 51 | FnDef, | 51 | FnDef, |
| 52 | |||
| 53 | /// used when getting a member `a.b` | ||
| 54 | Ref, | ||
| 55 | Loop, | 52 | Loop, |
| 56 | }; | 53 | }; |
| 57 | 54 | ||
| ... | @@ -181,7 +178,6 @@ const Scope = struct { | ... | @@ -181,7 +178,6 @@ const Scope = struct { |
| 181 | fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { | 178 | fn getAlias(scope: *Scope, name: []const u8) ?[]const u8 { |
| 182 | return switch (scope.id) { | 179 | return switch (scope.id) { |
| 183 | .Root => null, | 180 | .Root => null, |
| 184 | .Ref => null, | ||
| 185 | .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), | 181 | .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), |
| 186 | .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), | 182 | .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), |
| 187 | .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), | 183 | .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), |
| ... | @@ -190,7 +186,6 @@ const Scope = struct { | ... | @@ -190,7 +186,6 @@ const Scope = struct { |
| 190 | 186 | ||
| 191 | fn contains(scope: *Scope, name: []const u8) bool { | 187 | fn contains(scope: *Scope, name: []const u8) bool { |
| 192 | return switch (scope.id) { | 188 | return switch (scope.id) { |
| 193 | .Ref => false, | ||
| 194 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), | 189 | .Root => @fieldParentPtr(Root, "base", scope).contains(name), |
| 195 | .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), | 190 | .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), |
| 196 | .Block => @fieldParentPtr(Block, "base", scope).contains(name), | 191 | .Block => @fieldParentPtr(Block, "base", scope).contains(name), |
| ... | @@ -230,7 +225,6 @@ const Context = struct { | ... | @@ -230,7 +225,6 @@ const Context = struct { |
| 230 | decl_table: DeclTable, | 225 | decl_table: DeclTable, |
| 231 | alias_list: AliasList, | 226 | alias_list: AliasList, |
| 232 | global_scope: *Scope.Root, | 227 | global_scope: *Scope.Root, |
| 233 | ptr_params: std.BufSet, | ||
| 234 | clang_context: *ZigClangASTContext, | 228 | clang_context: *ZigClangASTContext, |
| 235 | mangle_count: u64 = 0, | 229 | mangle_count: u64 = 0, |
| 236 | 230 | ||
| ... | @@ -316,7 +310,6 @@ pub fn translate( | ... | @@ -316,7 +310,6 @@ pub fn translate( |
| 316 | .decl_table = DeclTable.init(arena), | 310 | .decl_table = DeclTable.init(arena), |
| 317 | .alias_list = AliasList.init(arena), | 311 | .alias_list = AliasList.init(arena), |
| 318 | .global_scope = try arena.create(Scope.Root), | 312 | .global_scope = try arena.create(Scope.Root), |
| 319 | .ptr_params = std.BufSet.init(arena), | ||
| 320 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, | 313 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, |
| 321 | }; | 314 | }; |
| 322 | context.global_scope.* = Scope.Root.init(&context); | 315 | context.global_scope.* = Scope.Root.init(&context); |
| ... | @@ -856,6 +849,7 @@ fn transStmt( | ... | @@ -856,6 +849,7 @@ fn transStmt( |
| 856 | .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), | 849 | .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used), |
| 857 | .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), | 850 | .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used), |
| 858 | .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), | 851 | .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used), |
| 852 | .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used), | ||
| 859 | else => { | 853 | else => { |
| 860 | return revertAndWarn( | 854 | return revertAndWarn( |
| 861 | rp, | 855 | rp, |
| ... | @@ -1147,7 +1141,6 @@ fn transDeclRefExpr( | ... | @@ -1147,7 +1141,6 @@ fn transDeclRefExpr( |
| 1147 | const value_decl = ZigClangDeclRefExpr_getDecl(expr); | 1141 | const value_decl = ZigClangDeclRefExpr_getDecl(expr); |
| 1148 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); | 1142 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); |
| 1149 | const checked_name = if (scope.getAlias(name)) |a| a else name; | 1143 | const checked_name = if (scope.getAlias(name)) |a| a else name; |
| 1150 | if (lrvalue == .l_value) try rp.c.ptr_params.put(checked_name); | ||
| 1151 | return transCreateNodeIdentifier(rp.c, checked_name); | 1144 | return transCreateNodeIdentifier(rp.c, checked_name); |
| 1152 | } | 1145 | } |
| 1153 | 1146 | ||
| ... | @@ -1990,6 +1983,18 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, | ... | @@ -1990,6 +1983,18 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, |
| 1990 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | 1983 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| 1991 | } | 1984 | } |
| 1992 | 1985 | ||
| 1986 | fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberExpr, result_used: ResultUsed) TransError!*ast.Node { | ||
| 1987 | var container_node = try transExpr(rp, scope, ZigClangMemberExpr_getBase(stmt), .used, .r_value); | ||
| 1988 | |||
| 1989 | if (ZigClangMemberExpr_isArrow(stmt)) { | ||
| 1990 | container_node = try transCreateNodePtrDeref(rp.c, container_node); | ||
| 1991 | } | ||
| 1992 | |||
| 1993 | const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt)))); | ||
| 1994 | const node = try transCreateNodeFieldAccess(rp.c, container_node, name); | ||
| 1995 | return maybeSuppressResult(rp, scope, result_used, node); | ||
| 1996 | } | ||
| 1997 | |||
| 1993 | fn transCPtrCast( | 1998 | fn transCPtrCast( |
| 1994 | rp: RestorePoint, | 1999 | rp: RestorePoint, |
| 1995 | loc: ZigClangSourceLocation, | 2000 | loc: ZigClangSourceLocation, |
| ... | @@ -2213,8 +2218,8 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC | ... | @@ -2213,8 +2218,8 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC |
| 2213 | import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2218 | import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2214 | 2219 | ||
| 2215 | const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); | 2220 | const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); |
| 2216 | const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int"); | 2221 | const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); |
| 2217 | const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base); | 2222 | const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access); |
| 2218 | try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node); | 2223 | try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node); |
| 2219 | log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); | 2224 | log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); |
| 2220 | 2225 | ||
| ... | @@ -2446,7 +2451,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { | ... | @@ -2446,7 +2451,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { |
| 2446 | return node; | 2451 | return node; |
| 2447 | } | 2452 | } |
| 2448 | 2453 | ||
| 2449 | fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp { | 2454 | fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { |
| 2450 | const field_access_node = try c.a().create(ast.Node.InfixOp); | 2455 | const field_access_node = try c.a().create(ast.Node.InfixOp); |
| 2451 | field_access_node.* = .{ | 2456 | field_access_node.* = .{ |
| 2452 | .op_token = try appendToken(c, .Period, "."), | 2457 | .op_token = try appendToken(c, .Period, "."), |
| ... | @@ -2454,7 +2459,7 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c | ... | @@ -2454,7 +2459,7 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c |
| 2454 | .op = .Period, | 2459 | .op = .Period, |
| 2455 | .rhs = try transCreateNodeIdentifier(c, field_name), | 2460 | .rhs = try transCreateNodeIdentifier(c, field_name), |
| 2456 | }; | 2461 | }; |
| 2457 | return field_access_node; | 2462 | return &field_access_node.base; |
| 2458 | } | 2463 | } |
| 2459 | 2464 | ||
| 2460 | fn transCreateNodePrefixOp( | 2465 | fn transCreateNodePrefixOp( |
| ... | @@ -2924,9 +2929,9 @@ fn transCreateNodeShiftOp( | ... | @@ -2924,9 +2929,9 @@ fn transCreateNodeShiftOp( |
| 2924 | rp: RestorePoint, | 2929 | rp: RestorePoint, |
| 2925 | scope: *Scope, | 2930 | scope: *Scope, |
| 2926 | stmt: *const ZigClangBinaryOperator, | 2931 | stmt: *const ZigClangBinaryOperator, |
| 2927 | comptime op: ast.Node.InfixOp.Op, | 2932 | op: ast.Node.InfixOp.Op, |
| 2928 | comptime op_tok_id: std.zig.Token.Id, | 2933 | op_tok_id: std.zig.Token.Id, |
| 2929 | comptime bytes: []const u8, | 2934 | bytes: []const u8, |
| 2930 | ) !*ast.Node { | 2935 | ) !*ast.Node { |
| 2931 | std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight); | 2936 | std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight); |
| 2932 | 2937 | ||
| ... | @@ -2957,6 +2962,16 @@ fn transCreateNodeShiftOp( | ... | @@ -2957,6 +2962,16 @@ fn transCreateNodeShiftOp( |
| 2957 | return &node.base; | 2962 | return &node.base; |
| 2958 | } | 2963 | } |
| 2959 | 2964 | ||
| 2965 | fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { | ||
| 2966 | const node = try c.a().create(ast.Node.SuffixOp); | ||
| 2967 | node.* = .{ | ||
| 2968 | .lhs = .{ .node = lhs }, | ||
| 2969 | .op = .Deref, | ||
| 2970 | .rtoken = try appendToken(c, .PeriodAsterisk, ".*"), | ||
| 2971 | }; | ||
| 2972 | return &node.base; | ||
| 2973 | } | ||
| 2974 | |||
| 2960 | const RestorePoint = struct { | 2975 | const RestorePoint = struct { |
| 2961 | c: *Context, | 2976 | c: *Context, |
| 2962 | token_index: ast.TokenIndex, | 2977 | token_index: ast.TokenIndex, |
| ... | @@ -3862,16 +3877,21 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -3862,16 +3877,21 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3862 | .{}, | 3877 | .{}, |
| 3863 | ); | 3878 | ); |
| 3864 | 3879 | ||
| 3865 | const op_token = try appendToken(rp.c, .Period, "."); | 3880 | node = try transCreateNodeFieldAccess(rp.c, node, name_tok.bytes); |
| 3866 | const rhs = try transCreateNodeIdentifier(rp.c, name_tok.bytes); | 3881 | }, |
| 3867 | const access_node = try rp.c.a().create(ast.Node.InfixOp); | 3882 | .Arrow => { |
| 3868 | access_node.* = .{ | 3883 | const name_tok = it.next().?; |
| 3869 | .op_token = op_token, | 3884 | if (name_tok.id != .Identifier) |
| 3870 | .lhs = node, | 3885 | return revertAndWarn( |
| 3871 | .op = .Period, | 3886 | rp, |
| 3872 | .rhs = rhs, | 3887 | error.ParseError, |
| 3873 | }; | 3888 | source_loc, |
| 3874 | node = &access_node.base; | 3889 | "unable to translate C expr", |
| 3890 | .{}, | ||
| 3891 | ); | ||
| 3892 | |||
| 3893 | const deref = try transCreateNodePtrDeref(rp.c, node); | ||
| 3894 | node = try transCreateNodeFieldAccess(rp.c, deref, name_tok.bytes); | ||
| 3875 | }, | 3895 | }, |
| 3876 | .Asterisk => { | 3896 | .Asterisk => { |
| 3877 | if (it.peek().?.id == .RParen) { | 3897 | if (it.peek().?.id == .RParen) { |
| ... | @@ -3887,14 +3907,14 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -3887,14 +3907,14 @@ fn parseCSuffixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3887 | // expr * expr | 3907 | // expr * expr |
| 3888 | const op_token = try appendToken(rp.c, .Asterisk, "*"); | 3908 | const op_token = try appendToken(rp.c, .Asterisk, "*"); |
| 3889 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); | 3909 | const rhs = try parseCPrimaryExpr(rp, it, source_loc, scope); |
| 3890 | const bitshift_node = try rp.c.a().create(ast.Node.InfixOp); | 3910 | const mul_node = try rp.c.a().create(ast.Node.InfixOp); |
| 3891 | bitshift_node.* = .{ | 3911 | mul_node.* = .{ |
| 3892 | .op_token = op_token, | 3912 | .op_token = op_token, |
| 3893 | .lhs = node, | 3913 | .lhs = node, |
| 3894 | .op = .BitShiftLeft, | 3914 | .op = .BitShiftLeft, |
| 3895 | .rhs = rhs, | 3915 | .rhs = rhs, |
| 3896 | }; | 3916 | }; |
| 3897 | node = &bitshift_node.base; | 3917 | node = &mul_node.base; |
| 3898 | } | 3918 | } |
| 3899 | }, | 3919 | }, |
| 3900 | .Shl => { | 3920 | .Shl => { |
| ... | @@ -3938,13 +3958,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc | ... | @@ -3938,13 +3958,7 @@ fn parseCPrefixOpExpr(rp: RestorePoint, it: *ctok.TokenList.Iterator, source_loc |
| 3938 | }, | 3958 | }, |
| 3939 | .Asterisk => { | 3959 | .Asterisk => { |
| 3940 | const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); | 3960 | const prefix_op_expr = try parseCPrefixOpExpr(rp, it, source_loc, scope); |
| 3941 | const node = try rp.c.a().create(ast.Node.SuffixOp); | 3961 | return try transCreateNodePtrDeref(rp.c, prefix_op_expr); |
| 3942 | node.* = .{ | ||
| 3943 | .lhs = .{ .node = prefix_op_expr }, | ||
| 3944 | .op = .Deref, | ||
| 3945 | .rtoken = try appendToken(rp.c, .PeriodAsterisk, ".*"), | ||
| 3946 | }; | ||
| 3947 | return &node.base; | ||
| 3948 | }, | 3962 | }, |
| 3949 | else => { | 3963 | else => { |
| 3950 | _ = it.prev(); | 3964 | _ = it.prev(); |
test/translate_c.zig+45-16| ... | @@ -1494,6 +1494,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1494,6 +1494,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1494 | \\} | 1494 | \\} |
| 1495 | }); | 1495 | }); |
| 1496 | 1496 | ||
| 1497 | cases.add_2("field access expression", | ||
| 1498 | \\#define ARROW a->b | ||
| 1499 | \\#define DOT a.b | ||
| 1500 | \\extern struct Foo { | ||
| 1501 | \\ int b; | ||
| 1502 | \\}a; | ||
| 1503 | \\float b = 2.0f; | ||
| 1504 | \\int foo(void) { | ||
| 1505 | \\ struct Foo *c; | ||
| 1506 | \\ a.b; | ||
| 1507 | \\ c->b; | ||
| 1508 | \\} | ||
| 1509 | , &[_][]const u8{ | ||
| 1510 | \\pub const struct_Foo = extern struct { | ||
| 1511 | \\ b: c_int, | ||
| 1512 | \\}; | ||
| 1513 | \\pub extern var a: struct_Foo; | ||
| 1514 | \\pub export var b: f32 = 2; | ||
| 1515 | \\pub export fn foo() c_int { | ||
| 1516 | \\ var c: [*c]struct_Foo = undefined; | ||
| 1517 | \\ _ = a.b; | ||
| 1518 | \\ _ = c.*.b; | ||
| 1519 | \\} | ||
| 1520 | , | ||
| 1521 | \\pub const DOT = a.b; | ||
| 1522 | , | ||
| 1523 | \\pub const ARROW = a.*.b; | ||
| 1524 | }); | ||
| 1525 | |||
| 1497 | /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// | 1526 | /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// |
| 1498 | 1527 | ||
| 1499 | cases.addAllowWarnings("simple data types", | 1528 | cases.addAllowWarnings("simple data types", |
| ... | @@ -1702,22 +1731,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1702,22 +1731,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1702 | \\} | 1731 | \\} |
| 1703 | }); | 1732 | }); |
| 1704 | 1733 | ||
| 1705 | cases.addC("field access expression", | ||
| 1706 | \\struct Foo { | ||
| 1707 | \\ int field; | ||
| 1708 | \\}; | ||
| 1709 | \\int read_field(struct Foo *foo) { | ||
| 1710 | \\ return foo->field; | ||
| 1711 | \\} | ||
| 1712 | , &[_][]const u8{ | ||
| 1713 | \\pub const struct_Foo = extern struct { | ||
| 1714 | \\ field: c_int, | ||
| 1715 | \\}; | ||
| 1716 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { | ||
| 1717 | \\ return foo.*.field; | ||
| 1718 | \\} | ||
| 1719 | }); | ||
| 1720 | |||
| 1721 | cases.addC("array access", | 1734 | cases.addC("array access", |
| 1722 | \\int array[100]; | 1735 | \\int array[100]; |
| 1723 | \\int foo(int index) { | 1736 | \\int foo(int index) { |
| ... | @@ -2627,4 +2640,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -2627,4 +2640,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2627 | \\ }; | 2640 | \\ }; |
| 2628 | \\} | 2641 | \\} |
| 2629 | }); | 2642 | }); |
| 2643 | |||
| 2644 | cases.addC("field access expression", | ||
| 2645 | \\struct Foo { | ||
| 2646 | \\ int field; | ||
| 2647 | \\}; | ||
| 2648 | \\int read_field(struct Foo *foo) { | ||
| 2649 | \\ return foo->field; | ||
| 2650 | \\} | ||
| 2651 | , &[_][]const u8{ | ||
| 2652 | \\pub const struct_Foo = extern struct { | ||
| 2653 | \\ field: c_int, | ||
| 2654 | \\}; | ||
| 2655 | \\pub export fn read_field(foo: [*c]struct_Foo) c_int { | ||
| 2656 | \\ return foo.*.field; | ||
| 2657 | \\} | ||
| 2658 | }); | ||
| 2630 | } | 2659 | } |