|
1 | 1 | #! /usr/bin/env python |
2 | 2 | """Generate C code from an ASDL description.""" |
3 | 3 |
|
4 | | -import os, sys |
| 4 | +import os |
| 5 | +import sys |
| 6 | + |
| 7 | +from argparse import ArgumentParser |
| 8 | +from pathlib import Path |
5 | 9 |
|
6 | 10 | import asdl |
7 | 11 |
|
8 | 12 | TABSIZE = 4 |
9 | 13 | MAX_COL = 80 |
| 14 | +AUTOGEN_MESSAGE = "/* File automatically generated by {}. */\n\n" |
10 | 15 |
|
11 | 16 | def get_c_type(name): |
12 | 17 | """Return a string for the C name of the type. |
@@ -1369,94 +1374,77 @@ def generate_module_def(f, mod): |
1369 | 1374 | f.write(' return 1;\n') |
1370 | 1375 | f.write('};\n\n') |
1371 | 1376 |
|
1372 | | - |
1373 | | -common_msg = "/* File automatically generated by %s. */\n\n" |
1374 | | - |
1375 | | -def main(srcfile, dump_module=False): |
1376 | | - argv0 = sys.argv[0] |
1377 | | - components = argv0.split(os.sep) |
1378 | | - # Always join with '/' so different OS does not keep changing the file |
1379 | | - argv0 = '/'.join(components[-2:]) |
1380 | | - auto_gen_msg = common_msg % argv0 |
1381 | | - mod = asdl.parse(srcfile) |
| 1377 | +def write_header(f, mod): |
| 1378 | + f.write('#ifndef Py_PYTHON_AST_H\n') |
| 1379 | + f.write('#define Py_PYTHON_AST_H\n') |
| 1380 | + f.write('#ifdef __cplusplus\n') |
| 1381 | + f.write('extern "C" {\n') |
| 1382 | + f.write('#endif\n') |
| 1383 | + f.write('\n') |
| 1384 | + f.write('#ifndef Py_LIMITED_API\n') |
| 1385 | + f.write('#include "asdl.h"\n') |
| 1386 | + f.write('\n') |
| 1387 | + f.write('#undef Yield /* undefine macro conflicting with <winbase.h> */\n') |
| 1388 | + f.write('\n') |
| 1389 | + c = ChainOfVisitors(TypeDefVisitor(f), |
| 1390 | + StructVisitor(f)) |
| 1391 | + c.visit(mod) |
| 1392 | + f.write("// Note: these macros affect function definitions, not only call sites.\n") |
| 1393 | + PrototypeVisitor(f).visit(mod) |
| 1394 | + f.write("\n") |
| 1395 | + f.write("PyObject* PyAST_mod2obj(mod_ty t);\n") |
| 1396 | + f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n") |
| 1397 | + f.write("int PyAST_Check(PyObject* obj);\n") |
| 1398 | + f.write("#endif /* !Py_LIMITED_API */\n") |
| 1399 | + f.write('\n') |
| 1400 | + f.write('#ifdef __cplusplus\n') |
| 1401 | + f.write('}\n') |
| 1402 | + f.write('#endif\n') |
| 1403 | + f.write('#endif /* !Py_PYTHON_AST_H */\n') |
| 1404 | + |
| 1405 | +def write_source(f, mod): |
| 1406 | + f.write('#include <stddef.h>\n') |
| 1407 | + f.write('\n') |
| 1408 | + f.write('#include "Python.h"\n') |
| 1409 | + f.write('#include "%s-ast.h"\n' % mod.name) |
| 1410 | + f.write('#include "structmember.h" // PyMemberDef\n') |
| 1411 | + f.write('\n') |
| 1412 | + |
| 1413 | + generate_module_def(f, mod) |
| 1414 | + |
| 1415 | + v = ChainOfVisitors( |
| 1416 | + PyTypesDeclareVisitor(f), |
| 1417 | + PyTypesVisitor(f), |
| 1418 | + Obj2ModPrototypeVisitor(f), |
| 1419 | + FunctionVisitor(f), |
| 1420 | + ObjVisitor(f), |
| 1421 | + Obj2ModVisitor(f), |
| 1422 | + ASTModuleVisitor(f), |
| 1423 | + PartingShots(f), |
| 1424 | + ) |
| 1425 | + v.visit(mod) |
| 1426 | + |
| 1427 | +def main(input_file, c_file, h_file, dump_module=False): |
| 1428 | + auto_gen_msg = AUTOGEN_MESSAGE.format("/".join(Path(__file__).parts[-2:])) |
| 1429 | + mod = asdl.parse(input_file) |
1382 | 1430 | if dump_module: |
1383 | 1431 | print('Parsed Module:') |
1384 | 1432 | print(mod) |
1385 | 1433 | if not asdl.check(mod): |
1386 | 1434 | sys.exit(1) |
1387 | | - if H_FILE: |
1388 | | - with open(H_FILE, "w") as f: |
1389 | | - f.write(auto_gen_msg) |
1390 | | - f.write('#ifndef Py_PYTHON_AST_H\n') |
1391 | | - f.write('#define Py_PYTHON_AST_H\n') |
1392 | | - f.write('#ifdef __cplusplus\n') |
1393 | | - f.write('extern "C" {\n') |
1394 | | - f.write('#endif\n') |
1395 | | - f.write('\n') |
1396 | | - f.write('#ifndef Py_LIMITED_API\n') |
1397 | | - f.write('#include "asdl.h"\n') |
1398 | | - f.write('\n') |
1399 | | - f.write('#undef Yield /* undefine macro conflicting with <winbase.h> */\n') |
1400 | | - f.write('\n') |
1401 | | - c = ChainOfVisitors(TypeDefVisitor(f), |
1402 | | - StructVisitor(f)) |
1403 | | - |
1404 | | - c.visit(mod) |
1405 | | - f.write("// Note: these macros affect function definitions, not only call sites.\n") |
1406 | | - PrototypeVisitor(f).visit(mod) |
1407 | | - f.write("\n") |
1408 | | - f.write("PyObject* PyAST_mod2obj(mod_ty t);\n") |
1409 | | - f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n") |
1410 | | - f.write("int PyAST_Check(PyObject* obj);\n") |
1411 | | - f.write("#endif /* !Py_LIMITED_API */\n") |
1412 | | - f.write('\n') |
1413 | | - f.write('#ifdef __cplusplus\n') |
1414 | | - f.write('}\n') |
1415 | | - f.write('#endif\n') |
1416 | | - f.write('#endif /* !Py_PYTHON_AST_H */\n') |
1417 | | - |
1418 | | - if C_FILE: |
1419 | | - with open(C_FILE, "w") as f: |
1420 | | - f.write(auto_gen_msg) |
1421 | | - f.write('#include <stddef.h>\n') |
1422 | | - f.write('\n') |
1423 | | - f.write('#include "Python.h"\n') |
1424 | | - f.write('#include "%s-ast.h"\n' % mod.name) |
1425 | | - f.write('#include "structmember.h" // PyMemberDef\n') |
1426 | | - f.write('\n') |
1427 | | - |
1428 | | - generate_module_def(f, mod) |
1429 | | - |
1430 | | - v = ChainOfVisitors( |
1431 | | - PyTypesDeclareVisitor(f), |
1432 | | - PyTypesVisitor(f), |
1433 | | - Obj2ModPrototypeVisitor(f), |
1434 | | - FunctionVisitor(f), |
1435 | | - ObjVisitor(f), |
1436 | | - Obj2ModVisitor(f), |
1437 | | - ASTModuleVisitor(f), |
1438 | | - PartingShots(f), |
1439 | | - ) |
1440 | | - v.visit(mod) |
| 1435 | + for file, writer in (c_file, write_source), (h_file, write_header): |
| 1436 | + if file is not None: |
| 1437 | + with file.open("w") as f: |
| 1438 | + f.write(auto_gen_msg) |
| 1439 | + writer(f, mod) |
| 1440 | + print(file, "regenerated.") |
1441 | 1441 |
|
1442 | 1442 | if __name__ == "__main__": |
1443 | | - import getopt |
1444 | | - |
1445 | | - H_FILE = '' |
1446 | | - C_FILE = '' |
1447 | | - dump_module = False |
1448 | | - opts, args = getopt.getopt(sys.argv[1:], "dh:c:") |
1449 | | - for o, v in opts: |
1450 | | - if o == '-h': |
1451 | | - H_FILE = v |
1452 | | - elif o == '-c': |
1453 | | - C_FILE = v |
1454 | | - elif o == '-d': |
1455 | | - dump_module = True |
1456 | | - if H_FILE and C_FILE: |
1457 | | - print('Must specify exactly one output file') |
1458 | | - sys.exit(1) |
1459 | | - elif len(args) != 1: |
1460 | | - print('Must specify single input file') |
1461 | | - sys.exit(1) |
1462 | | - main(args[0], dump_module) |
| 1443 | + parser = ArgumentParser() |
| 1444 | + parser.add_argument("input_file", type=Path) |
| 1445 | + parser.add_argument("-C", "--c-file", type=Path, default=None) |
| 1446 | + parser.add_argument("-H", "--h-file", type=Path, default=None) |
| 1447 | + parser.add_argument("-d", "--dump-module", action="store_true") |
| 1448 | + |
| 1449 | + options = parser.parse_args() |
| 1450 | + main(**vars(options)) |
0 commit comments