def test_consume_part_of_current_line__consume_all_characters(self): for source_string, expectation in self.test_cases_for_consume_all_characters_of_current_line: with self.subTest(msg='consume_part_of_current_line: ' + repr(source_string)): source = ParseSource(source_string) source.consume_part_of_current_line(len(source.current_line_text)) expectation.apply_with_message(self, source, 'consume_part_of_current_line:{}'.format(repr(source_string)))
def parse_from_source(self, source: ParseSource) -> SetupPhaseInstruction: args = source.remaining_part_of_current_line source.consume_current_line() components = args.split() if len(components) != self.num_args: raise ValueError('Expecting {} args. Found {} args'.format(self.num_args, len(components))) return self._parse(components)
def parse_token_or_none_on_current_line(source: ParseSource, argument_description: str = 'argument') -> Token: """ Parses a single, optional token from remaining part of current line. Tokens must be separated by space. :param source: Must have a current line. Initial space is consumed. Text for token is consumed. :raise SingleInstructionInvalidArgumentException: The token has invalid syntax """ source.consume_initial_space_on_current_line() if source.is_at_eol: return None part_of_current_line = source.remaining_part_of_current_line source_io = io.StringIO(part_of_current_line) lexer = shlex.shlex(source_io, posix=True) lexer.whitespace_split = True token_type = _derive_token_type(lexer, source.remaining_part_of_current_line[0]) try: token_string = lexer.get_token() except ValueError as ex: msg = 'Invalid {}: {}'.format(argument_description, str(ex)) raise SingleInstructionInvalidArgumentException(msg) source_string = _get_source_string_and_consume_token_characters(source, source_io) return Token(token_type, token_string, source_string)
def parse_token_or_none_on_current_line(source: ParseSource, argument_description: str = 'argument' ) -> Token: """ Parses a single, optional token from remaining part of current line. Tokens must be separated by space. :param source: Must have a current line. Initial space is consumed. Text for token is consumed. :raise SingleInstructionInvalidArgumentException: The token has invalid syntax """ source.consume_initial_space_on_current_line() if source.is_at_eol: return None part_of_current_line = source.remaining_part_of_current_line source_io = io.StringIO(part_of_current_line) lexer = shlex.shlex(source_io, posix=True) lexer.whitespace_split = True token_type = _derive_token_type(lexer, source.remaining_part_of_current_line[0]) try: token_string = lexer.get_token() except ValueError as ex: msg = 'Invalid {}: {}'.format(argument_description, str(ex)) raise SingleInstructionInvalidArgumentException(msg) source_string = _get_source_string_and_consume_token_characters( source, source_io) return Token(token_type, token_string, source_string)
def test_only_newline2(self): source = ParseSource('\n\n') source.consume_current_line() self.assertFalse(source.is_at_eof) self.assertTrue(source.has_current_line, 'has_current_line') self._assert_is_at_eol(source) self._assert_current_line_is(2, '', source)
def test_catch_up_with(self): test_cases = [ ('consume part of current line', ['abc'], lambda parse_source: parse_source.consume(1), lambda parse_source: parse_source.consume(2) ), ('copy consumes current line/with existing following line', ['abc', 'def'], lambda parse_source: None, lambda parse_source: parse_source.consume_current_line() ), ('copy consumes current line/which is the last line', ['abc'], lambda parse_source: None, lambda parse_source: parse_source.consume_current_line() ), ('copy consumes num characters that stretches to the following line', ['123', '456'], lambda parse_source: None, lambda parse_source: parse_source.consume(5) ), ('copy consumes all remaining characters', ['123', '456'], lambda parse_source: None, lambda parse_source: parse_source.consume(7) ), ] for test_name, original_source_lines, original_setup, copy_modifier in test_cases: with self.subTest(test_name): # ARRANGE # original = ParseSource('\n'.join(original_source_lines)) original_setup(original) # ACT # copy = original.copy copy_modifier(copy) original.catch_up_with(copy) # ASSERT # self.assertEqual(copy.is_at_eof, original.is_at_eof, 'is_at_eof') self.assertEqual(copy.remaining_source, original.remaining_source, 'remaining_source') self.assertEqual(copy.has_current_line, original.has_current_line, 'has_current_line') if original.has_current_line: self.assertEqual(copy.current_line_number, original.current_line_number, 'current_line_number') self.assertEqual(copy.remaining_part_of_current_line, original.remaining_part_of_current_line, 'remaining_part_of_current_line') self.assertEqual(copy.column_index, original.column_index, 'column_index') self.assertEqual(copy.is_at_eol, original.is_at_eol, 'is_at_eol')
def _advance_source(source: ParseSource): if source.has_current_line: if not source.is_at_eol__except_for_space: source.consume(len(source.remaining_part_of_current_line)) misc_utils.raise_superfluous_arguments( source.remaining_part_of_current_line.strip()) source.consume_current_line()
def test_single_line_source(self): source = ParseSource('single line') self._assert_current_line_and_remaining_part_of_it_is(1, 'single line', source) self.assertEqual('single line', source.remaining_source, 'remaining source') source.consume_current_line() self._assert_is_at_eof(source)
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ParsedInstruction: current_line = source.current_line source.consume_current_line() instruction = ActPhaseInstructionThatRecords( fs_location_info.current_source_file, current_line.text) return ParsedInstruction(line_sequence_from_line(current_line), InstructionInfo(instruction, None))
def _get_source_string_and_consume_token_characters( source: ParseSource, source_io: io.StringIO) -> str: num_chars_consumed = source_io.tell() if source.remaining_part_of_current_line[num_chars_consumed - 1].isspace(): num_chars_consumed -= 1 ret_val = source.remaining_source[:num_chars_consumed] source.consume_part_of_current_line(num_chars_consumed) return ret_val
def _get_source_string_and_consume_token_characters(source: ParseSource, source_io: io.StringIO) -> str: num_chars_consumed = source_io.tell() if source.remaining_part_of_current_line[num_chars_consumed - 1].isspace(): num_chars_consumed -= 1 ret_val = source.remaining_source[:num_chars_consumed] source.consume_part_of_current_line(num_chars_consumed) return ret_val
def test_first_line_is_empty(self): source = ParseSource('\n' + 'second line') self._assert_current_line_and_remaining_part_of_it_is(1, '', source) source.consume_current_line() self._assert_current_line_and_remaining_part_of_it_is(2, 'second line', source) self.assertEqual('second line', source.remaining_source, 'remaining source') source.consume_current_line() self._assert_is_at_eof(source)
def test_consume_current_line(self): test_cases = [ ('single line', assert_source(is_at_eof=asrt.is_true, has_current_line=asrt.is_false, remaining_source=asrt.equals('')) ), ('', assert_source(is_at_eof=asrt.is_true, has_current_line=asrt.is_false) ), ('first line\nsecond line', assert_source(is_at_eof=asrt.is_false, has_current_line=asrt.is_true, is_at_eol=asrt.is_false, is_at_eol__except_for_space=asrt.is_false, current_line_number=asrt.equals(2), current_line_text=asrt.equals('second line'), column_index=asrt.equals(0), remaining_source=asrt.equals('second line')) ), ('single line\n', assert_source(is_at_eof=asrt.is_true, has_current_line=asrt.is_true, is_at_eol=asrt.is_true, is_at_eol__except_for_space=asrt.is_true, current_line_number=asrt.equals(2), current_line_text=asrt.equals(''), column_index=asrt.equals(0), remaining_source=asrt.equals('')) ), ('\n', assert_source(is_at_eof=asrt.is_true, has_current_line=asrt.is_true, is_at_eol=asrt.is_true, is_at_eol__except_for_space=asrt.is_true, current_line_number=asrt.equals(2), current_line_text=asrt.equals(''), column_index=asrt.equals(0), remaining_source=asrt.equals('')) ), ('\nsecond line', assert_source(is_at_eof=asrt.is_false, has_current_line=asrt.is_true, is_at_eol=asrt.is_false, is_at_eol__except_for_space=asrt.is_false, current_line_number=asrt.equals(2), current_line_text=asrt.equals('second line'), column_index=asrt.equals(0), remaining_source=asrt.equals('second line')) ), ] for source_string, expectation in test_cases: with self.subTest(msg='consume current line: ' + repr(source_string)): source = ParseSource(source_string) source.consume_current_line() expectation.apply_with_message(self, source, 'consume_current_line:{}'.format(repr(source_string)))
def token_stream_from_parse_source(parse_source: ParseSource): """ Gives a :class:`TokenStream` backed by the given :class:`ParseSource`. The source of the :class:`TokenStream` is the remaining sources of the :class:`ParseSource` """ ts = new_token_stream(parse_source.remaining_source) yield ts parse_source.consume(ts.position)
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> model.Instruction: first_line = source.current_line name = self._extract_name(source) parser = self._lookup_parser(first_line, name) source.consume_part_of_current_line(len(name)) source.consume_initial_space_on_current_line() return self._parse(fs_location_info, source, parser, name)
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> model.Instruction: err_msg_constructor = _ErrMsgSourceConstructor(source) name = self._extract_name(source) parser = self._lookup_parser(source.current_line, name) source.consume_part_of_current_line(len(name)) source.consume_initial_space_on_current_line() return self._parse(fs_location_info, source, parser, name, err_msg_constructor)
def parse_from_parse_source(source: ParseSource, conf: RelOptionArgumentConfiguration = CONFIGURATION) -> StringOrFileRefResolver: with from_parse_source(source, consume_last_line_if_is_at_eol_after_parse=False) as token_parser: ret_val = parse_from_token_parser(token_parser, conf) if ret_val.source_type is SourceType.HERE_DOC: if source.is_at_eol: source.consume_current_line() return ret_val
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ParsedInstruction: current_line = source.current_line source.consume_current_line() instruction = ActPhaseInstructionThatRecords(fs_location_info.current_source_file, current_line.text) return ParsedInstruction(line_sequence_from_line(current_line), InstructionInfo(instruction, None))
def from_remaining_part_of_current_line_of_parse_source(parse_source: ParseSource): """ Gives a :class:`TokenParserPrime` backed by the given :class:`ParseSource`. The source of the :class:`TokenParserPrime` is the remaining part of the current line of the :class:`ParseSource` """ tp = new_token_parser(parse_source.remaining_part_of_current_line, first_line_number=parse_source.current_line_number) yield tp parse_source.consume(tp.token_stream.position)
def parse_string_sdv_from_parse_source(source: ParseSource, conf: Configuration = DEFAULT_CONFIGURATION) -> StringSdv: """ :param source: Has a current line :raises SingleInstructionInvalidArgumentException: If cannot parse a PathDdv """ ts = new_token_stream(source.remaining_part_of_current_line) ret_val = parse_string_sdv(ts, conf) source.consume(ts.position) return ret_val
def _syntax_error_if_not_at_eof(source: parse_source.ParseSource): if source.is_at_eof: return if source.is_at_eol__except_for_space: source.consume_current_line() _syntax_error_if_not_at_eof(source) else: raise ParseException.of_str( 'Superfluous arguments of {PROGRAM}: {src}'.format( PROGRAM=syntax_elements.PROGRAM_SYNTAX_ELEMENT.singular_name, src=source.remaining_part_of_current_line))
def test_consume_part_of_current_line(self): source = ParseSource('first line' + '\n' + 'second line') source.consume_part_of_current_line(len('first') + 1) self._assert_current_line_is(1, 'first line', source) self.assertEqual('line', source.remaining_part_of_current_line, 'Remaining part of current line') self.assertEqual('line' + '\n' + 'second line', source.remaining_source, 'Remaining source') self.assertFalse(source.is_at_eof, 'is_at_eof') self.assertFalse(source.is_at_eol, 'is_at_eol')
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ParsedInstruction: first_line = source.current_line source_copy = source.copy description = _DescriptionExtractor(source_copy).apply() self._consume_space_and_comment_lines(source_copy, first_line) ret_val = parse_and_compute_source(self.instruction_parser, fs_location_info, source_copy, description) source.catch_up_with(source_copy) return ret_val
def test_consume_part_of_current_line__until_end_of_line_of_last_line(self): source = ParseSource('first line') source.consume_part_of_current_line(len('first line')) self._assert_current_line_is(1, 'first line', source) self.assertTrue(source.is_at_eol, 'is_at_eol') self.assertTrue(source.is_at_eof, 'is_at_eof') self.assertEqual('', source.remaining_part_of_current_line, 'Remaining part of current line') self.assertEqual('', source.remaining_source, 'Remaining source')
def remaining_source(remaining_contents_of_first_line: str, following_lines: Sequence[str] = ()) -> ParseSource: """ :param remaining_contents_of_first_line: Part of the first line that has not been consumed. :return: Source with some initial content of the first line that has been consumed. """ previous_content = 'previous content ' remaining_content = '\n'.join([remaining_contents_of_first_line] + list(following_lines)) content = previous_content + remaining_content ret_val = ParseSource(content) ret_val.consume_part_of_current_line(len(previous_content)) return ret_val
def test_two_line_source(self): original_source = 'first line' + '\n' + 'second line' source = ParseSource(original_source) self._assert_current_line_and_remaining_part_of_it_is(1, 'first line', source) self.assertEqual(original_source, source.remaining_source, 'remaining source') source.consume_current_line() self._assert_current_line_and_remaining_part_of_it_is(2, 'second line', source) self.assertEqual('second line', source.remaining_source, 'remaining source') source.consume_current_line() self._assert_is_at_eof(source)
def from_remaining_part_of_current_line_of_parse_source( parse_source: ParseSource) -> ContextManager[TokenParser]: """ Gives a :class:`TokenParser` backed by the given :class:`ParseSource`. The source of the :class:`TokenParser` is the remaining part of the current line of the :class:`ParseSource` """ tp = new_token_parser(parse_source.remaining_part_of_current_line, first_line_number=parse_source.current_line_number) try: yield tp finally: parse_source.consume(tp.token_stream.position)
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> sut.ParsedInstruction: first_line_number = source.current_line_number dummy_source = line_source.LineSequence(first_line_number, (source.current_line_text,)) is_instruction = False while not source.is_at_eof and source.current_line_text.startswith(self.instruction_line_identifier): source.consume_current_line() is_instruction = True if not is_instruction: raise ValueError('Not an instruction') return sut.ParsedInstruction(dummy_source, InstructionInfo(Instruction(), None))
def test_consume_with_invalid_arguments(self): test_cases = [ ('a', 0, 2), ('a', 1, 1), ('a\nb', 0, 4), ('a\nb', 1, 3), ] for source, num_chars_on_current_line_to_consume_before_check, num_chars in test_cases: with self.subTest(source=source, num_chars=num_chars): source = ParseSource(source) source.consume_part_of_current_line(num_chars_on_current_line_to_consume_before_check) with self.assertRaises(ValueError): source.consume(num_chars)
def _consume_and_return_current_line(source: ParseSource, line_predicate_for_line_to_consume: Callable[[str], bool], ) -> line_source.LineSequence: current_line = source.current_line lines = [current_line.text] source.consume_current_line() while source.has_current_line and line_predicate_for_line_to_consume(source.current_line_text): lines.append(source.current_line_text) source.consume_current_line() return line_source.LineSequence(current_line.line_number, tuple(lines))
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> sut.ParsedInstruction: first_line_number = source.current_line_number dummy_source = line_source.LineSequence(first_line_number, (source.current_line_text, )) is_instruction = False while not source.is_at_eof and source.current_line_text.startswith( self.instruction_line_identifier): source.consume_current_line() is_instruction = True if not is_instruction: raise ValueError('Not an instruction') return sut.ParsedInstruction(dummy_source, InstructionInfo(Instruction(), None))
def _consume_and_return_current_line( source: ParseSource, line_predicate_for_line_to_consume: Callable[[str], bool], ) -> line_source.LineSequence: current_line = source.current_line lines = [current_line.text] source.consume_current_line() while source.has_current_line and line_predicate_for_line_to_consume( source.current_line_text): lines.append(source.current_line_text) source.consume_current_line() return line_source.LineSequence(current_line.line_number, tuple(lines))
def __init__(self, instructions: Sequence[ActPhaseInstruction]): self.instructions = instructions single_line_parser = ParserForSingleLineUsingStandardSyntax() single_line = single_line_parser.apply(instructions) single_line = single_line.strip() self._source = ParseSource(single_line) self._path_parser = parse_path.PathParser(RELATIVITY_CONFIGURATION)
def test_all_fail_unrecognized_element_SHOULD_be_raised_WHEN_all_parsers_fail_and_last_parser_raises_UE( self): # ARRANGE # source_text = 'first line' err_msg = 'error message in exception' cases = [ NameAndValue('one parser', [ SectionElementParserThatRaisesUnrecognizedSectionElementSourceError( err_msg) ]), NameAndValue('more than one parser - first parser returns None', [ SectionElementParserThatReturnsNone(), SectionElementParserThatRaisesUnrecognizedSectionElementSourceError( err_msg) ]), ] for case in cases: with self.subTest(case.name): source = ParseSource(source_text) parser = sut.ParserFromSequenceOfParsers(case.value) # ACT # with self.assertRaises( UnrecognizedSectionElementSourceError) as cm: parser.parse(ARBITRARY_FS_LOCATION_INFO, source) self.assertEqual(err_msg, cm.exception.message, 'error message in exception')
def _consume_instruction_source(source: ParseSource) -> line_source.LineSequence: current_line = source.current_line_text if is_multi_line_instruction_line(current_line): first_line_number = source.current_line_number lines = [current_line] source.consume_current_line() # Eat additional lines while source.has_current_line: current_line = source.current_line_text if is_multi_line_instruction_line(current_line): lines.append(current_line) source.consume_current_line() else: break return line_source.LineSequence(first_line_number, tuple(lines)) else: return consume_current_line_and_return_it_as_line_sequence(source)
def apply(self, test_case: TestCaseFileReference, test_case_plain_source: str) -> test_case_doc.TestCase: file_parser = test_case_parser.new_parser( self._test_case_parsing_setup) source = ParseSource(test_case_plain_source) try: return file_parser.apply(test_case, source) except exceptions.ParseError as ex: ex.accept(_ParseErrorHandler())
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ConfigurationPhaseInstruction: rest_of_line = source.remaining_part_of_current_line source.consume_current_line() argument = extract_single_eq_argument_string(_DIR_ARG.name, rest_of_line) path_arguments = split_arguments_list_string(argument) if len(path_arguments) > 1: raise SingleInstructionInvalidArgumentException('Too many arguments: ' + argument) try: path_argument = pathlib.Path(pathlib.PurePosixPath(path_arguments[0])) except ValueError as ex: raise SingleInstructionInvalidArgumentException('Invalid path syntax:\n' + str(ex)) return _Instruction(self.dir_to_set, fs_location_info.current_source_file.abs_path_of_dir_containing_last_file_base_name, path_argument)
def _consume_instruction_source( source: ParseSource) -> line_source.LineSequence: current_line = source.current_line_text if is_multi_line_instruction_line(current_line): first_line_number = source.current_line_number lines = [current_line] source.consume_current_line() # Eat additional lines while source.has_current_line: current_line = source.current_line_text if is_multi_line_instruction_line(current_line): lines.append(current_line) source.consume_current_line() else: break return line_source.LineSequence(first_line_number, tuple(lines)) else: return consume_current_line_and_return_it_as_line_sequence(source)
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ParsedInstruction: first_line_number = source.current_line_number current_line = source.current_line_text lines_read = [_un_escape(current_line)] source.consume_current_line() while not source.is_at_eof: current_line = source.current_line_text if syntax.is_section_header_line(current_line): break else: lines_read.append(_un_escape(current_line)) source.consume_current_line() line_sequence = LineSequence(first_line_number, tuple(lines_read)) return ParsedInstruction( line_sequence, InstructionInfo(SourceCodeInstruction(line_sequence), None))
def cases_wo_parentheses(expected_int: int) -> List[NSourceCase]: return [ NSourceCase( 'plain int', ParseSource(str(expected_int)), asrt_source.is_at_end_of_line(1), ), NSourceCase( 'plain int followed by other plain int', ParseSource(str(expected_int) + ' 77'), asrt_source.is_at_line(1, '77'), ), NSourceCase( 'plain int followed by end parenthesis', ParseSource(str(expected_int) + ' )'), asrt_source.is_at_line(1, ')'), ), ]
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> Optional[ParsedFileInclusionDirective]: parts = source.current_line_text.strip().split() if len(parts) == 0 or parts[0] != self._directive_token: return None directive_source = line_sequence_from_line(source.current_line) source.consume_current_line() if len(parts) == 1: raise RecognizedSectionElementSourceError(directive_source, 'Missing {} argument'.format(FILE_ARGUMENT_NAME)) if len(parts) != 2: raise RecognizedSectionElementSourceError(directive_source, 'Superfluous arguments: ' + ' '.join(parts[2:])) path = pathlib.Path(pathlib.PurePosixPath(parts[1])) return ParsedFileInclusionDirective(directive_source, [path])
def parse(self, fs_location_info: FileSystemLocationInfo, source: ParseSource) -> ParsedInstruction: first_line_number = source.current_line_number current_line = source.current_line_text lines_read = [_un_escape(current_line)] source.consume_current_line() while not source.is_at_eof: current_line = source.current_line_text if syntax.is_section_header_line(current_line): break else: lines_read.append(_un_escape(current_line)) source.consume_current_line() line_sequence = LineSequence(first_line_number, tuple(lines_read)) return ParsedInstruction(line_sequence, InstructionInfo(SourceCodeInstruction(line_sequence), None))
def runTest(self): # ARRANGE # conf = self.configuration arguments_str = _exe_file_syntax_str(conf, 'file.exe', 'remaining args') source = ParseSource(arguments_str) # ACT # exe_file = parse_executable_file_path.parser().parse(source) # ASSERT # with self._tcds_and_test_as_curr_dir( File.empty('file.exe')) as environment: self._assert_does_not_pass_validation(exe_file, environment)
def check_invalid_syntax__abs_stx( self, put: unittest.TestCase, invalid_source: AbstractSyntax, sub_test_identifiers: Mapping[str, Any] = MappingProxyType({}), ): for layout_case in STANDARD_LAYOUT_SPECS: parse_source = ParseSource(invalid_source.tokenization().layout( layout_case.value)) with put.subTest(zz_layout=layout_case.name, **sub_test_identifiers): self.check_invalid_arguments(put, parse_source)
def test_last_line_is_empty(self): source = ParseSource('first line' + '\n') self._assert_current_line_and_remaining_part_of_it_is(1, 'first line', source) source.consume_current_line() self._assert_current_line_and_remaining_part_of_it_is(2, '', source) source.consume_current_line() self._assert_is_at_eof(source)
def test_consume_initial_space(self): test_cases = [ (['', 'second line'], '', True), (['non-space', 'second line'], 'non-space', False), ([' ', 'second line'], '', True), ([' non-space', 'second line'], 'non-space', False), ] for lines, remaining_part, is_at_eol in test_cases: with self.subTest(): first_line = lines[0] source_lines = '\n'.join(lines) # ACT # source = ParseSource(source_lines) # ASSERT # source.consume_initial_space_on_current_line() assertion = assert_source(is_at_eol=asrt.equals(is_at_eol), remaining_part_of_current_line=asrt.equals(remaining_part), current_line_number=asrt.equals(1), current_line_text=asrt.equals(lines[0]), column_index=asrt.equals(len(first_line) - len(first_line.lstrip())) ) assertion.apply(self, source)
def _consume_space_and_comment_lines(source: ParseSource, first_line: Line): error_message = 'End-of-file reached without finding an instruction (following a description)' if source.is_at_eof: raise new_unrecognized_section_element_error_of_single_line(first_line, error_message) line_in_error_message = first_line source.consume_initial_space_on_current_line() if not source.is_at_eol: return source.consume_current_line() while not source.is_at_eof: if syntax.is_empty_or_comment_line(source.current_line_text): line_in_error_message = source.current_line source.consume_current_line() else: source.consume_initial_space_on_current_line() return raise new_unrecognized_section_element_error_of_single_line(line_in_error_message, error_message)
def from_parse_source(source: ParseSource, consume_last_line_if_is_at_eol_after_parse: bool = False, consume_last_line_if_is_at_eof_after_parse: bool = False): """ Gives a :class:`TokenParserPrime` backed by the given :class:`ParseSource`. The source of the :class:`TokenParserPrime` is the remaining sources of the :class:`ParseSource` """ tp = new_token_parser(source.remaining_source, first_line_number=source.current_line_number) yield tp source.consume(tp.token_stream.position) if consume_last_line_if_is_at_eol_after_parse and source.is_at_eol: source.consume_current_line() elif consume_last_line_if_is_at_eof_after_parse and source.is_at_eof: source.consume_current_line()
def consume_current_line_and_return_it_as_line_sequence(source: ParseSource) -> line_source.LineSequence: ret_val = line_source.LineSequence(source.current_line_number, (source.current_line_text,)) source.consume_current_line() return ret_val