"""Utilities for defining and exporting procedural macros."""fromcollections.abcimportSequencefromfunctoolsimportpartialimporttokenizefrom..importMacroErrorfrom..matchimportMacroMatchfrom..parseimportparse_macro_matcherfrom..tokensimportToken,lex,stringifyEXPORTED_MACROS_NAME_TEMPLATE='__macro_polo_exported_{}_macros__'EXPORTED_FUNCTION_MACROS_NAME=EXPORTED_MACROS_NAME_TEMPLATE.format('function')EXPORTED_MODULE_MACROS_NAME=EXPORTED_MACROS_NAME_TEMPLATE.format('module')EXPORTED_DECORATOR_MACROS_NAME=EXPORTED_MACROS_NAME_TEMPLATE.format('decorator')_CLASS_OR_FUNC_MATCHER=parse_macro_matcher('$[(class)|(def)] $name:name')
[docs]defexport_proc_macro(parameters:Sequence[Token],tokens:Sequence[Token],export_dict_name:str)->Sequence[Token]|None:"""Decorator-style macro for exporting procedural macros."""matchparameters:case[]:export_name=Nonecase[Token(type=tokenize.STRING,string=export_name)]:passcase_:raiseMacroError('export function-style macro: expected name as parameter, 'f'got {stringify(parameters)!r}')match_CLASS_OR_FUNC_MATCHER.match(tokens):caseMacroMatch(captures={'name':Token(string=name)}):passcase_:first_line=stringify(tokens).splitlines()[0]raiseMacroError('export function-style macro: expected class or function definition, 'f'found {first_line!r}')ifexport_nameisNone:export_name=nameexport_tokens=lex(f'globals().setdefault({export_dict_name!r}, {{}}).update({export_name}={name})')return(*tokens,*export_tokens)