Coverage for trlc/nested.py: 100%

26 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-09-04 11:46 +0000

1#!/usr/bin/env python3 

2# 

3# TRLC - Treat Requirements Like Code 

4# Copyright (C) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) 

5# 

6# This file is part of the TRLC Python Reference Implementation. 

7# 

8# TRLC is free software: you can redistribute it and/or modify it 

9# under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# TRLC is distributed in the hope that it will be useful, but WITHOUT 

14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 

15# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 

16# License for more details. 

17# 

18# You should have received a copy of the GNU General Public License 

19# along with TRLC. If not, see <https://www.gnu.org/licenses/>. 

20 

21from abc import abstractmethod 

22 

23from trlc.ast import String_Literal 

24from trlc.lexer import Lexer_Base, Source_Reference 

25 

26 

27class Nested_Lexer(Lexer_Base): 

28 def __init__(self, mh, literal): 

29 assert isinstance(literal, String_Literal) 

30 

31 origin_full_text = literal.location.text() 

32 self.origin_multi_string = origin_full_text.startswith(('"""', "'''")) 

33 if self.origin_multi_string: 

34 self.base_offset = 3 

35 text = origin_full_text[3:-3] 

36 else: 

37 self.base_offset = 1 

38 text = origin_full_text[1:-1].replace('\\"', '"') 

39 

40 self.origin_location = literal.location 

41 

42 super().__init__(mh, text) 

43 

44 def source_location(self, start_line, start_col, begin, end): 

45 assert 0 <= begin <= end < self.length 

46 assert start_line >= 1 

47 assert start_col >= 1 

48 

49 if self.origin_multi_string: 

50 loc = Source_Reference( 

51 lexer=self.origin_location.lexer, 

52 start_line=self.origin_location.line_no + (start_line - 1), 

53 start_col=( 

54 self.origin_location.col_no + self.base_offset 

55 if start_line == 1 

56 else start_col 

57 ), 

58 start_pos=(self.origin_location.start_pos + self.base_offset + begin), 

59 end_pos=(self.origin_location.start_pos + self.base_offset + end), 

60 ) 

61 

62 else: 

63 escapes_to_start = self.content[0:begin].count('"') 

64 escapes_to_end = escapes_to_start + self.content[begin : end + 1].count('"') 

65 assert start_line == 1 

66 loc = Source_Reference( 

67 lexer=self.origin_location.lexer, 

68 start_line=self.origin_location.line_no, 

69 start_col=( 

70 self.origin_location.col_no 

71 + self.base_offset 

72 + begin 

73 + escapes_to_start 

74 ), 

75 start_pos=( 

76 self.origin_location.start_pos 

77 + self.base_offset 

78 + begin 

79 + escapes_to_start 

80 ), 

81 end_pos=( 

82 self.origin_location.start_pos 

83 + self.base_offset 

84 + end 

85 + escapes_to_end 

86 ), 

87 ) 

88 

89 return loc 

90 

91 @abstractmethod 

92 def file_location(self): 

93 pass 

94 

95 @abstractmethod 

96 def token(self): 

97 pass