| | 107 | |
| | 108 | @classmethod |
| | 109 | def create_token_source(cls, text): |
| | 110 | lex = cls(text) |
| | 111 | return TokenIterator(lex) |
| | 112 | |
| | 113 | |
| | 114 | class TokenIterator(object): |
| | 115 | |
| | 116 | def __init__(self, lex): |
| | 117 | self.lex = lex |
| | 118 | self.src = iter(lex) |
| | 119 | |
| | 120 | @property |
| | 121 | def current_literal(self): |
| | 122 | return self.lex.current_source.literal |
| | 123 | |
| | 124 | def __iter__(self): |
| | 125 | return self.src |
| | 126 | |
| | 127 | |
| | 128 | # imaplib has poor handling of 'literals' - it both fails to remove the |
| | 129 | # {size} marker, and fails to keep responses grouped into the same logical |
| | 130 | # 'line'. What we end up with is a list of response 'records', where each |
| | 131 | # record is either a simple string, or tuple of (str_with_lit, literal) - |
| | 132 | # where str_with_lit is a string with the {xxx} marker at its end. Note |
| | 133 | # that each elt of this list does *not* correspond 1:1 with the untagged |
| | 134 | # responses. |
| | 135 | # (http://bugs.python.org/issue5045 also has comments about this) |
| | 136 | # So: we have a special file-like object for each of these records. When |
| | 137 | # a string literal is finally processed, we peek into this file-like object |
| | 138 | # to grab the literal. |
| | 139 | class LiteralHandlingIter: |
| | 140 | def __init__(self, lexer, resp_record): |
| | 141 | self.pushed = None |
| | 142 | self.lexer = lexer |
| | 143 | if isinstance(resp_record, tuple): |
| | 144 | # A 'record' with a string which includes a literal marker, and |
| | 145 | # the literal itself. |
| | 146 | src_text, self.literal = resp_record |
| | 147 | assert src_text.endswith("}"), src_text |
| | 148 | self.src_text = self.literal |
| | 149 | else: |
| | 150 | # just a line with no literals. |
| | 151 | self.src_text = resp_record |
| | 152 | self.literal = None |
| | 153 | |
| | 154 | def __iter__(self): |
| | 155 | return iter(self.src_text) |
| | 156 | |