source.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #!/usr/bin/env python3
  2. # ex: set filetype=python:
  3. """Translate an XDR specification into executable code that
  4. can be compiled for the Linux kernel."""
  5. import logging
  6. from argparse import Namespace
  7. from lark import logger
  8. from lark.exceptions import VisitError
  9. from generators.source_top import XdrSourceTopGenerator
  10. from generators.enum import XdrEnumGenerator
  11. from generators.passthru import XdrPassthruGenerator
  12. from generators.pointer import XdrPointerGenerator
  13. from generators.program import XdrProgramGenerator
  14. from generators.typedef import XdrTypedefGenerator
  15. from generators.struct import XdrStructGenerator
  16. from generators.union import XdrUnionGenerator
  17. from xdr_ast import transform_parse_tree, _RpcProgram, Specification
  18. from xdr_ast import _XdrAst, _XdrEnum, _XdrPassthru, _XdrPointer
  19. from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion
  20. from xdr_parse import xdr_parser, set_xdr_annotate, set_xdr_enum_validation
  21. from xdr_parse import make_error_handler, XdrParseError
  22. from xdr_parse import handle_transform_error
  23. logger.setLevel(logging.INFO)
  24. def emit_source_decoder(node: _XdrAst, language: str, peer: str) -> None:
  25. """Emit one XDR decoder function for a source file"""
  26. if isinstance(node, _XdrEnum):
  27. gen = XdrEnumGenerator(language, peer)
  28. elif isinstance(node, _XdrPointer):
  29. gen = XdrPointerGenerator(language, peer)
  30. elif isinstance(node, _XdrTypedef):
  31. gen = XdrTypedefGenerator(language, peer)
  32. elif isinstance(node, _XdrStruct):
  33. gen = XdrStructGenerator(language, peer)
  34. elif isinstance(node, _XdrUnion):
  35. gen = XdrUnionGenerator(language, peer)
  36. elif isinstance(node, _RpcProgram):
  37. gen = XdrProgramGenerator(language, peer)
  38. else:
  39. return
  40. gen.emit_decoder(node)
  41. def emit_source_encoder(node: _XdrAst, language: str, peer: str) -> None:
  42. """Emit one XDR encoder function for a source file"""
  43. if isinstance(node, _XdrEnum):
  44. gen = XdrEnumGenerator(language, peer)
  45. elif isinstance(node, _XdrPointer):
  46. gen = XdrPointerGenerator(language, peer)
  47. elif isinstance(node, _XdrTypedef):
  48. gen = XdrTypedefGenerator(language, peer)
  49. elif isinstance(node, _XdrStruct):
  50. gen = XdrStructGenerator(language, peer)
  51. elif isinstance(node, _XdrUnion):
  52. gen = XdrUnionGenerator(language, peer)
  53. elif isinstance(node, _RpcProgram):
  54. gen = XdrProgramGenerator(language, peer)
  55. else:
  56. return
  57. gen.emit_encoder(node)
  58. def generate_server_source(filename: str, root: Specification, language: str) -> None:
  59. """Generate server-side source code"""
  60. gen = XdrSourceTopGenerator(language, "server")
  61. gen.emit_source(filename, root)
  62. for definition in root.definitions:
  63. if isinstance(definition.value, _XdrPassthru):
  64. passthru_gen = XdrPassthruGenerator(language, "server")
  65. passthru_gen.emit_decoder(definition.value)
  66. else:
  67. emit_source_decoder(definition.value, language, "server")
  68. for definition in root.definitions:
  69. if not isinstance(definition.value, _XdrPassthru):
  70. emit_source_encoder(definition.value, language, "server")
  71. def generate_client_source(filename: str, root: Specification, language: str) -> None:
  72. """Generate client-side source code"""
  73. gen = XdrSourceTopGenerator(language, "client")
  74. gen.emit_source(filename, root)
  75. for definition in root.definitions:
  76. if isinstance(definition.value, _XdrPassthru):
  77. passthru_gen = XdrPassthruGenerator(language, "client")
  78. passthru_gen.emit_decoder(definition.value)
  79. else:
  80. emit_source_encoder(definition.value, language, "client")
  81. for definition in root.definitions:
  82. if not isinstance(definition.value, _XdrPassthru):
  83. emit_source_decoder(definition.value, language, "client")
  84. # cel: todo: client needs PROC macros
  85. def subcmd(args: Namespace) -> int:
  86. """Generate encoder and decoder functions"""
  87. set_xdr_annotate(args.annotate)
  88. set_xdr_enum_validation(not args.no_enum_validation)
  89. parser = xdr_parser()
  90. with open(args.filename, encoding="utf-8") as f:
  91. source = f.read()
  92. try:
  93. parse_tree = parser.parse(
  94. source, on_error=make_error_handler(source, args.filename)
  95. )
  96. except XdrParseError:
  97. return 1
  98. try:
  99. ast = transform_parse_tree(parse_tree)
  100. except VisitError as e:
  101. handle_transform_error(e, source, args.filename)
  102. return 1
  103. match args.peer:
  104. case "server":
  105. generate_server_source(args.filename, ast, args.language)
  106. case "client":
  107. generate_client_source(args.filename, ast, args.language)
  108. case _:
  109. print("Code generation for", args.peer, "is not yet supported")
  110. return 0