"""Super-macros that apply other macros to their input."""fromcollections.abcimportSequencefrom.._utilsimportSliceView,TupleNewTypefrom..matchimportMacroMatchfrom..parseimportparse_macro_matcherfrom..tokensimportToken,TokenTreefrom.typesimportMacro,PartialMatchMacro
[docs]classMultiMacro(TupleNewType[Macro],Macro):"""A super-macro that applies each of its inner macros in sequence. :type args: Macro """def__call__(self,tokens:Sequence[Token])->Sequence[Token]|None:"""Transform a token sequence. Applies each macro in ``self`` in sequence. """changed=Falseformacroinself:if(new_tokens:=macro(tokens))isnotNone:tokens=new_tokenschanged=Trueifchanged:returntokensreturnNone
[docs]classLoopingMacro(TupleNewType[Macro],Macro):"""A super-macro that repeatedely applies its inner macros until none match. :type args: Macro """def__call__(self,tokens:Sequence[Token])->Sequence[Token]|None:"""Transform a token sequence. Tries each macro in sequence, starting over after each match. Stops once none of the macros match. """changed=FalsewhileTrue:formacroinself:if(new_tokens:=macro(tokens))isnotNone:tokens=new_tokenschanged=Truebreakelse:breakifchanged:returntokensreturnNone
[docs]classScanningMacro(TupleNewType[PartialMatchMacro],Macro):"""A super-macro that scans input and applies its inner macros as they match. This macro will only perform a single pass on the input. It can be combined with :class:`LoopingMacro` to recursively expand macros. :type args: PartialMatchMacro """_token_tree_matcher=parse_macro_matcher('$token_tree:tt')def__call__(self,tokens:Sequence[Token])->Sequence[Token]|None:"""Transform a token sequence."""tokens=SliceView(tokens)output:list[Token]=[]changed=Falsewhilelen(tokens)>0:formacroinself:new_tokens,match_size=macro(tokens)iflen(new_tokens)>0ormatch_size>0:output.extend(new_tokens)tokens=tokens[match_size:]changed=Truebreakelse:matchself._token_tree_matcher.match(tokens):caseMacroMatch(size=1):output.append(tokens.popleft())caseMacroMatch(size=match_size,captures={'token_tree':TokenTree((open_delim,*inner_tokens,close_delim))},):output.append(open_delim)if(transformed_inner:=self(inner_tokens))isnotNone:output.extend(transformed_inner)changed=Trueelse:output.extend(inner_tokens)output.append(close_delim)tokens=tokens[match_size:]ifchanged:returnoutputreturnNone