Coverage for trlc/nested.py: 100%
26 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-09-04 11:46 +0000
« 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/>.
21from abc import abstractmethod
23from trlc.ast import String_Literal
24from trlc.lexer import Lexer_Base, Source_Reference
27class Nested_Lexer(Lexer_Base):
28 def __init__(self, mh, literal):
29 assert isinstance(literal, String_Literal)
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('\\"', '"')
40 self.origin_location = literal.location
42 super().__init__(mh, text)
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
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 )
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 )
89 return loc
91 @abstractmethod
92 def file_location(self):
93 pass
95 @abstractmethod
96 def token(self):
97 pass