def _parse_string(source: Source, string_regex=BASIC_STRING, separator='"') -> str: source.expect(separator) res = [] while True: if not source.consume_regex(string_regex): raise DoesNotMatch('Invalid string starting from {text}' .format(text=source._text[:100])) res.append(source.last_consumed) # start of some escape character if not source.consume('\\'): break # do nothing if new line chars encountered # corresponds to \ if source.consume_regex(NEWLINE_ESCAPE_CHARS_REGEX): pass # read unicode characters elif source.consume_regex(SHORT_UNICODE_REGEX) or source.consume_regex(LONG_UNICODE_REGEX): res.append(chr(int(source.last_consumed, 16))) else: # fail if no escape character follows source.expect_regex(ESCAPE_CHARS_REGEX) res.append(ESCAPES_MAPPING[source.last_consumed]) source.expect(separator) return ''.join(res)
def parse_line_comment(source: Source) -> Comment: source.expect('#') source.consume_regex(COMMENT_REGEX) text = source.last_consumed source.expect_regex(re.compile(r'(?P<res>\n|\Z)')) return Comment(text)
def parse_kv_entry(source: Source) -> KVEntry: key = parse_keyword(source) source.consume_regex(WHITESPACE_REGEX) source.expect('=') source.consume_regex(WHITESPACE_REGEX) val = parse_value(source) return KVEntry(key, val)
def _parse_literal_string(source: Source, string_regex=LITERAL_STRING, separator='\'') -> str: source.expect(separator) is_matched = source.consume_regex(string_regex) if not is_matched: raise DoesNotMatch() parsed_str = source.last_consumed source.expect(separator) return parsed_str
def _parse_inline_table(source: Source) -> InlineTable: table = InlineTable() source.expect('{') if not source.consume('}'): source.consume_regex(WHITESPACE_REGEX) kv_entry = parse_kv_entry(source) if source.last_consumed == '}': raise InvalidTomlError('Cannot have nested inline tables.') table[kv_entry.key] = kv_entry.val while source.consume(','): source.consume_regex(WHITESPACE_REGEX) kv_entry = parse_kv_entry(source) table[kv_entry.key] = kv_entry.val source.consume_regex(WHITESPACE_REGEX) source.expect('}') return table
def _parse_array(source: Source) -> List[ValueType]: array_type = None # type: type items = [] # type: List[ValueType] source.expect('[') try: while True: source.consume_regex(ENCLOSING_WHITESPACE_CHARS) parsed_val = parse_value(source) if array_type is not None and \ not isinstance(parsed_val, array_type): raise MixedTypesArray if array_type is None: array_type = type(parsed_val) items.append(parsed_val) source.consume_regex(ENCLOSING_WHITESPACE_CHARS) source.expect(',') except (ExpectationError, DoesNotMatch): pass source.consume_regex(ENCLOSING_WHITESPACE_CHARS) source.expect(']') return items
def test_expect_any_text_chunk_false(self): text = 'World' s = Source(text) with self.assertRaises(ExpectationError): s.expect('Hello')
def test_expect_any_text_chunk_true(self): text = 'Hello' s = Source(text) # not raises anything s.expect(text)
def parse_table(source: Source) -> ParsedTable: source.expect('[') keys = _parse_table_name(source) source.expect(']') return ParsedTable(keys)