Selfie
Loading...
Searching...
No Matches
selfie_lib.SourceFile.SourceFile Class Reference

Classes

class  ToBeLiteral
 

Public Member Functions

None __init__ (self, str filename, str content)
 
 remove_selfie_once_comments (self)
 
str as_string (self)
 
Slice find_on_line (self, str to_find, int line_one_indexed)
 
None replace_on_line (self, int line_one_indexed, str find, str replace)
 
ToBeLiteral parse_to_be_like (self, int line_one_indexed)
 

Public Attributes

 TRIPLE_QUOTE
 

Static Public Attributes

str TRIPLE_QUOTE = '"""'
 

Protected Member Functions

 _parse_code (self, int line_one_indexed, int arg_start, str dot_fun_open_paren)
 
 _parse_string (self, int line_one_indexed, int arg_start, str dot_fun_open_paren)
 

Protected Attributes

 _content_slice
 

Detailed Description

Definition at line 8 of file SourceFile.py.

Constructor & Destructor Documentation

◆ __init__()

None selfie_lib.SourceFile.SourceFile.__init__ (   self,
str  filename,
str  content 
)

Definition at line 11 of file SourceFile.py.

11 def __init__(self, filename: str, content: str) -> None:
12 self.__unix_newlines: bool = "\r" not in content
13 self._content_slice: Slice = Slice(content.replace("\r\n", "\n"))
14 self.__language: Language = Language.from_filename(filename)
15 self.__escape_leading_whitespace = EscapeLeadingWhitespace.appropriate_for(
16 self._content_slice.__str__()
17 )
18

Member Function Documentation

◆ _parse_code()

selfie_lib.SourceFile.SourceFile._parse_code (   self,
int  line_one_indexed,
int  arg_start,
str  dot_fun_open_paren 
)
protected

Definition at line 177 of file SourceFile.py.

182 ):
183 # Initialize variables
184 parenthesis_count = 1
185 string_delimiter = None
186
187 # Iterate through the characters starting from the given index
188 for i in range(arg_start, len(self._content_slice)):
189 char = self._content_slice[i]
190
191 # Check if we are entering or leaving a string
192 if char in ["'", '"'] and self._content_slice[i - 1] != "\\":
193 if not string_delimiter:
194 string_delimiter = char
195 elif char == string_delimiter:
196 string_delimiter = None
197
198 # Skip characters inside strings
199 if string_delimiter:
200 continue
201
202 # Count parentheses
203 if char == "(":
204 parenthesis_count += 1
205 elif char == ")":
206 parenthesis_count -= 1
207
208 # If all parentheses are closed, return the current index
209 if parenthesis_count == 0:
210 end_paren = i
211 end_arg = i
212 return (end_paren, end_arg)
213 # else ...
214 raise AssertionError(
215 f"Appears to be an unclosed function call `{dot_fun_open_paren}` "
216 f"starting at line {line_one_indexed}"
217 )
218

◆ _parse_string()

selfie_lib.SourceFile.SourceFile._parse_string (   self,
int  line_one_indexed,
int  arg_start,
str  dot_fun_open_paren 
)
protected

Definition at line 219 of file SourceFile.py.

224 ):
225 if self._content_slice.subSequence(
226 arg_start, len(self._content_slice)
227 ).starts_with(self.TRIPLE_QUOTE):
228 end_arg = self._content_slice.indexOf(
229 self.TRIPLE_QUOTE, arg_start + len(self.TRIPLE_QUOTE)
230 )
231 if end_arg == -1:
232 raise AssertionError(
233 f"Appears to be an unclosed multiline string literal `{self.TRIPLE_QUOTE}` "
234 f"on line {line_one_indexed}"
235 )
236 else:
237 end_arg += len(self.TRIPLE_QUOTE)
238 end_paren = end_arg
239 else:
240 end_arg = arg_start + 1
241 while (
242 self._content_slice[end_arg] != '"'
243 or self._content_slice[end_arg - 1] == "\\"
244 ):
245 end_arg += 1
246 if end_arg == self._content_slice.__len__():
247 raise AssertionError(
248 f'Appears to be an unclosed string literal `"` '
249 f"on line {line_one_indexed}"
250 )
251 end_arg += 1
252 end_paren = end_arg
253 while self._content_slice[end_paren] != ")":
254 if not self._content_slice[end_paren].isspace():
255 raise AssertionError(
256 f"Non-primitive literal in `{dot_fun_open_paren}` starting at "
257 f"line {line_one_indexed}: error for character "
258 f"`{self._content_slice[end_paren]}` on line "
259 f"{self._content_slice.baseLineAtOffset(end_paren)}"
260 )
261 end_paren += 1
262 if end_paren == self._content_slice.__len__():
263 raise AssertionError(
264 f"Appears to be an unclosed function call `{dot_fun_open_paren}` "
265 f"starting at line {line_one_indexed}"
266 )
267 return (end_paren, end_arg)
268
269

◆ as_string()

str selfie_lib.SourceFile.SourceFile.as_string (   self)

Definition at line 49 of file SourceFile.py.

49 def as_string(self) -> str:
50 return (
51 self._content_slice.__str__()
52 if self.__unix_newlines
53 else self._content_slice.__str__().replace("\n", "\r\n")
54 )
55

◆ find_on_line()

Slice selfie_lib.SourceFile.SourceFile.find_on_line (   self,
str  to_find,
int  line_one_indexed 
)

Definition at line 113 of file SourceFile.py.

113 def find_on_line(self, to_find: str, line_one_indexed: int) -> Slice:
114 line_content = self._content_slice.unixLine(line_one_indexed)
115 idx = line_content.indexOf(to_find)
116 if idx == -1:
117 raise AssertionError(
118 f"Expected to find `{to_find}` on line {line_one_indexed}, but there was only `{line_content}`"
119 )
120 return line_content.subSequence(idx, idx + len(to_find))
121

◆ parse_to_be_like()

ToBeLiteral selfie_lib.SourceFile.SourceFile.parse_to_be_like (   self,
int  line_one_indexed 
)

Definition at line 129 of file SourceFile.py.

129 def parse_to_be_like(self, line_one_indexed: int) -> ToBeLiteral:
130 line_content = self._content_slice.unixLine(line_one_indexed)
131 dot_fun_open_paren = None
132
133 for to_be_like in TO_BE_LIKES:
134 idx = line_content.indexOf(to_be_like)
135 if idx != -1:
136 dot_fun_open_paren = to_be_like
137 break
138 if dot_fun_open_paren is None:
139 raise AssertionError(
140 f"Expected to find inline assertion on line {line_one_indexed}, but there was only `{line_content}`"
141 )
142
143 dot_function_call_in_place = line_content.indexOf(dot_fun_open_paren)
144 dot_function_call = dot_function_call_in_place + line_content.startIndex
145 arg_start = dot_function_call + len(dot_fun_open_paren)
146
147 if self._content_slice.__len__() == arg_start:
148 raise AssertionError(
149 f"Appears to be an unclosed function call `{dot_fun_open_paren}` "
150 f"on line {line_one_indexed}"
151 )
152 while self._content_slice[arg_start].isspace():
153 arg_start += 1
154 if self._content_slice.__len__() == arg_start:
155 raise AssertionError(
156 f"Appears to be an unclosed function call `{dot_fun_open_paren}` "
157 f"on line {line_one_indexed}"
158 )
159
160 if self._content_slice[arg_start] == '"':
161 (end_paren, end_arg) = self._parse_string(
162 line_one_indexed, arg_start, dot_fun_open_paren
163 )
164 else:
165 (end_paren, end_arg) = self._parse_code(
166 line_one_indexed, arg_start, dot_fun_open_paren
167 )
168 return self.ToBeLiteral(
169 self,
170 dot_fun_open_paren.replace("_TODO", ""),
171 self._content_slice.subSequence(dot_function_call, end_paren + 1),
172 self._content_slice.subSequence(arg_start, end_arg),
173 self.__language,
174 self.__escape_leading_whitespace,
175 )
176

◆ remove_selfie_once_comments()

selfie_lib.SourceFile.SourceFile.remove_selfie_once_comments (   self)

Definition at line 19 of file SourceFile.py.

19 def remove_selfie_once_comments(self):
20 # Split content into lines
21 lines = self._content_slice.__str__().split("\n")
22
23 # Create a new list of lines, excluding lines containing '# selfieonce' or '#selfieonce'
24 new_lines = []
25 for line in lines:
26 # Check for both variations of the comment
27 if "# selfieonce" in line:
28 cleaned_line = line.split("# selfieonce")[0].strip()
29 elif "#selfieonce" in line:
30 cleaned_line = line.split("#selfieonce")[0].strip()
31 else:
32 new_lines.append(line)
33 continue
34
35 # If the line has code before the comment, keep the code part
36 if cleaned_line:
37 new_lines.append(cleaned_line)
38
39 # Recombine the lines into a single string
40 new_content = "\n".join(new_lines)
41
42 # Update the content slice with new content
43 self._content_slice = Slice(new_content)
44
45 if not self.__unix_newlines:
46 self._content_slice = Slice(new_content.replace("\n", "\r\n"))
47

◆ replace_on_line()

None selfie_lib.SourceFile.SourceFile.replace_on_line (   self,
int  line_one_indexed,
str  find,
str  replace 
)

Definition at line 122 of file SourceFile.py.

122 def replace_on_line(self, line_one_indexed: int, find: str, replace: str) -> None:
123 assert "\n" not in find
124 assert "\n" not in replace
125
126 found = self.find_on_line(find, line_one_indexed)
127 self._content_slice = Slice(found.replaceSelfWith(replace))
128

Member Data Documentation

◆ _content_slice

selfie_lib.SourceFile.SourceFile._content_slice
protected

Definition at line 43 of file SourceFile.py.

◆ TRIPLE_QUOTE [1/2]

str selfie_lib.SourceFile.SourceFile.TRIPLE_QUOTE = '"""'
static

Definition at line 9 of file SourceFile.py.

◆ TRIPLE_QUOTE [2/2]

selfie_lib.SourceFile.SourceFile.TRIPLE_QUOTE

Definition at line 227 of file SourceFile.py.


The documentation for this class was generated from the following file: