|
52 | 52 | import java.io.IOException;
|
53 | 53 | import java.nio.file.Files;
|
54 | 54 | import java.nio.file.Path;
|
| 55 | +import java.nio.file.Paths; |
55 | 56 | import java.util.ArrayList;
|
56 | 57 | import java.util.Arrays;
|
57 | 58 | import java.util.Collections;
|
|
62 | 63 | import java.util.function.IntFunction;
|
63 | 64 | import java.util.stream.Collectors;
|
64 | 65 | import java.util.stream.IntStream;
|
| 66 | +import java.util.stream.Stream; |
65 | 67 |
|
66 | 68 | import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltinRegistry;
|
67 | 69 | import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiBuiltin;
|
@@ -480,13 +482,60 @@ private static boolean generateBuiltinRegistry(List<CApiBuiltinDesc> javaBuiltin
|
480 | 482 | return writeGenerated(Path.of("com.oracle.graal.python", "src", "com", "oracle", "graal", "python", "builtins", "modules", "cext", "PythonCextBuiltinRegistry.java"), lines);
|
481 | 483 | }
|
482 | 484 |
|
| 485 | + private static void checkUnimplementedAPI(Path path, List<CApiBuiltinDesc> additionalBuiltins) { |
| 486 | + List<String> lines; |
| 487 | + try { |
| 488 | + lines = Files.readAllLines(path); |
| 489 | + } catch (IOException e) { |
| 490 | + System.out.println(" Error while reading " + path + ": " + e.getMessage()); |
| 491 | + return; |
| 492 | + } |
| 493 | + boolean msg = false; |
| 494 | + for (CApiBuiltinDesc builtin : additionalBuiltins) { |
| 495 | + if (builtin.call == NotImplemented) { |
| 496 | + for (int i = 0; i < lines.size(); i++) { |
| 497 | + String line = lines.get(i); |
| 498 | + int offset = line.indexOf(builtin.name); |
| 499 | + // avoid recognizing, e.g. "_PyObject_CallMethodId" in |
| 500 | + // "_PyObject_CallMethodIdNoArgs" |
| 501 | + if (offset > 0 && Character.isUnicodeIdentifierPart(line.charAt(offset - 1))) { |
| 502 | + continue; |
| 503 | + } |
| 504 | + if (offset + builtin.name.length() < line.length() && Character.isUnicodeIdentifierPart(line.charAt(offset + builtin.name.length()))) { |
| 505 | + continue; |
| 506 | + } |
| 507 | + if (line.contains(builtin.name)) { |
| 508 | + if (!msg) { |
| 509 | + msg = true; |
| 510 | + System.out.println("Checking " + path); |
| 511 | + } |
| 512 | + System.out.println(" " + builtin.name + " used in " + path + " line " + (i + 1) + ": " + line); |
| 513 | + } |
| 514 | + } |
| 515 | + } |
| 516 | + } |
| 517 | + } |
| 518 | + |
483 | 519 | /**
|
484 | 520 | * Entry point for the "mx python-capi-forwards" command.
|
485 | 521 | */
|
486 | 522 | public static void main(String[] args) throws IOException {
|
487 | 523 | List<CApiBuiltinDesc> javaBuiltins = CApiFunction.getJavaBuiltinDefinitions();
|
488 | 524 | List<CApiBuiltinDesc> additionalBuiltins = CApiFunction.getOtherBuiltinDefinitions();
|
489 | 525 |
|
| 526 | + /* |
| 527 | + * Calling with arguments "check <path>" will recursively check all files in the path for |
| 528 | + * unimplemented C API functions. |
| 529 | + */ |
| 530 | + if (args.length == 2 && "check".equals(args[0])) { |
| 531 | + System.out.println("Checking usages of unimplemented API:"); |
| 532 | + String path = args[1]; |
| 533 | + try (Stream<Path> stream = Files.walk(Paths.get(path))) { |
| 534 | + stream.filter(Files::isRegularFile).forEach(p -> checkUnimplementedAPI(p, additionalBuiltins)); |
| 535 | + } |
| 536 | + return; |
| 537 | + } |
| 538 | + |
490 | 539 | List<CApiBuiltinDesc> allBuiltins = new ArrayList<>();
|
491 | 540 | allBuiltins.addAll(additionalBuiltins);
|
492 | 541 | for (var entry : javaBuiltins) {
|
|
0 commit comments