@@ -198,6 +198,7 @@ def __init__(self, filepath: Path):
198
198
self .encoding : str = result .encoding if result else "utf-8"
199
199
with open (filepath , "rb" ) as f :
200
200
self ._content : bytes = f .read ()
201
+ self ._node : Node | None = None
201
202
202
203
@property
203
204
def content (self ):
@@ -226,26 +227,38 @@ def parse(self, **kwargs: Any) -> MatlabMixin:
226
227
Raises:
227
228
ValueError: If the file could not be parsed.
228
229
"""
229
- tree = PARSER . parse ( self . _content )
230
- cursor = tree . walk ( )
231
-
232
- if cursor . node is None :
233
- raise ValueError ( f"The file { self . filepath } could not be parsed." )
234
- captures = FILE_QUERY . captures ( cursor . node )
235
-
236
- if "function" in captures :
237
- model = self ._parse_function (captures ["function" ][0 ], ** kwargs )
238
- elif "class" in captures :
239
- model = self ._parse_class (captures ["class" ][0 ], ** kwargs )
240
- else :
241
- model = Script (self .filepath .stem , filepath = self .filepath , ** kwargs )
230
+ try :
231
+ tree = PARSER . parse ( self . _content )
232
+ cursor = tree . walk ()
233
+
234
+ if cursor . node is None :
235
+ raise ValueError ( f"The file { self . filepath } could not be parsed." )
236
+ captures = FILE_QUERY . captures ( cursor . node )
237
+ if "function" in captures :
238
+ model = self ._parse_function (captures ["function" ][0 ], ** kwargs )
239
+ elif "class" in captures :
240
+ model = self ._parse_class (captures ["class" ][0 ], ** kwargs )
241
+ else :
242
+ model = Script (self .filepath .stem , filepath = self .filepath , ** kwargs )
242
243
243
- if not model .docstring :
244
- model .docstring = self ._comment_docstring (
245
- captures .get ("header" , None ), parent = model
246
- )
244
+ if not model .docstring :
245
+ model .docstring = self ._comment_docstring (
246
+ captures .get ("header" , None ), parent = model
247
+ )
247
248
248
- return model
249
+ return model
250
+ except Exception as ex :
251
+ syntax_error = SyntaxError (f"Error parsing Matlab file" )
252
+ syntax_error .filename = str (self .filepath )
253
+ if self ._node is not None :
254
+ if self ._node .text is not None :
255
+ indentation = ' ' * self ._node .start_point .column
256
+ syntax_error .text = indentation + self ._node .text .decode (self .encoding )
257
+ syntax_error .lineno = self ._node .start_point .row + 1
258
+ syntax_error .offset = self ._node .start_point .column + 1
259
+ syntax_error .end_lineno = self ._node .end_point .row + 1
260
+ syntax_error .end_offset = self ._node .end_point .column + 1
261
+ raise syntax_error from ex
249
262
250
263
def _parse_class (self , node : Node , ** kwargs : Any ) -> Class :
251
264
"""
@@ -262,6 +275,7 @@ def _parse_class(self, node: Node, **kwargs: Any) -> Class:
262
275
Returns:
263
276
Class: The parsed Class or Classfolder model.
264
277
"""
278
+ self ._node = node
265
279
saved_kwargs = {key : value for key , value in kwargs .items ()}
266
280
captures = CLASS_QUERY .captures (node )
267
281
@@ -401,6 +415,7 @@ def _parse_attribute(self, node: Node) -> tuple[str, Any]:
401
415
The value is `True` if no value is specified,
402
416
otherwise it is the parsed value which can be a boolean or a string.
403
417
"""
418
+ self ._node = node
404
419
captures = ATTRIBUTE_QUERY .captures (node )
405
420
406
421
key = self ._first_from_capture (captures , "name" )
@@ -429,6 +444,7 @@ def _parse_function(self, node: Node, method: bool = False, **kwargs: Any) -> Fu
429
444
KeyError: If required captures are missing from the node.
430
445
431
446
"""
447
+ self ._node = node
432
448
captures : dict = FUNCTION_QUERY .matches (node )[0 ][1 ]
433
449
434
450
input_names = self ._decode_from_capture (captures , "input" )
@@ -529,6 +545,7 @@ def _decode(self, node: Node) -> str:
529
545
Returns:
530
546
str: The decoded text of the node. If the node or its text is None, returns an empty string.
531
547
"""
548
+ self ._node = node
532
549
return (
533
550
node .text .decode (self .encoding )
534
551
if node is not None and node .text is not None
0 commit comments