[docs]classMacroTranscriptionError(MacroError):"""Exception raised for macro transcription errors."""
MacroTranscriberItem:TypeAlias=Union[Token,'MacroTransciberSubstitution','MacroTranscriberRepeater']"""Union of types that can appear in a :class:`MacroTranscriber`."""
[docs]@dataclass(frozen=True,slots=True)classMacroTransciberSubstitution:"""A variable substitution in a transcriber."""name:str"""The name of the variable to substitute."""
[docs]classMacroTranscriber(TupleNewType[MacroTranscriberItem]):"""Transcribes a macro match to an output token stream. :type args: :class:`MacroTranscriberItem` """
[docs]deftranscribe(self,captures:MacroMatchCaptures,repitition_path:tuple[int,...]=())->Iterator[Token]:"""Transcribe the given match to an output token stream."""foriteminself:ifisinstance(item,Token):yielditemelifisinstance(item,MacroTransciberSubstitution):try:capture=captures[item.name]exceptKeyError:raiseMacroTranscriptionError(f'no macro variable named {item.name!r}')fromNoneforindexinrepitition_path:ifisinstance(capture,list):capture=capture[index]elif(isinstance(capture,MacroMatcherEmptyCapture)andcapture.depth>0):capture=MacroMatcherEmptyCapture(depth=capture.depth-1)else:breakifisinstance(capture,list)or(isinstance(item,MacroMatcherEmptyCapture)anditem.depth>0):raiseMacroTranscriptionError(f'macro variable {item.name!r} still repeating at this depth')ifisinstance(capture,Token):yieldcaptureelifisinstance(capture,TokenTree):yield fromcaptureelifisinstance(item,MacroTranscriberRepeater):yield fromitem.transcribe(captures,repitition_path)
[docs]@dataclass(frozen=True,slots=True)classMacroTranscriberRepeater:"""A repeated sub-transcriber."""transcriber:MacroTranscriber"""The transcriber to repeat."""sep:Token|None=None"""An optional separator token."""def_substitutions(self)->Iterator[str]:foriteminself.transcriber:ifisinstance(item,MacroTransciberSubstitution):yielditem.nameelifisinstance(item,MacroTranscriberRepeater):yield fromitem._substitutions()def_calc_repititions(self,captures:MacroMatchCaptures,repitition_path:tuple[int,...],)->int:"""Calculate how many times to repeat for the given match."""fornameinself._substitutions():try:capture=captures[name]exceptKeyError:raiseMacroTranscriptionError(f'no macro variable named {name!r}')fromNoneforindexinrepitition_path:ifnotisinstance(capture,list):breakcapture=capture[index]else:ifisinstance(capture,list):returnlen(capture)ifisinstance(capture,MacroMatcherEmptyCapture):return0raiseMacroTranscriptionError('no variables repeat at this depth')
[docs]deftranscribe(self,captures:MacroMatchCaptures,repitition_path:tuple[int,...]=())->Iterator[Token]:"""Transcribe the given match to an output token stream."""foriinrange(self._calc_repititions(captures,repitition_path)):ifi>0andself.sep:yieldself.sepyield fromself.transcriber.transcribe(captures,repitition_path+(i,),)