6
6
import cedarscript_grammar
7
7
from dataclasses import dataclass
8
8
9
+
9
10
class ParseError (NamedTuple ):
10
11
command_ordinal : int
11
12
message : str
@@ -14,10 +15,13 @@ class ParseError(NamedTuple):
14
15
suggestion : str
15
16
16
17
def __str__ (self ):
18
+ line_msg = f'; LINE #{ self .line } ' if self .line else ''
19
+ col_msg = f'; COLUMN #{ self .column } ' if self .column else ''
20
+ suggestion_msg = f'{ self .suggestion } ' if self .suggestion else ''
17
21
return (
18
- f"<error-details><error-location>COMMAND #{ self .command_ordinal } { f'; LINE # { self . line } ' if self . line else '' } { f'; COLUMN # { self . column } ' if self . column else '' } </error-location>"
22
+ f"<error-details><error-location>COMMAND #{ self .command_ordinal } { line_msg } { col_msg } </error-location>"
19
23
f"<type>PARSING (no commands were applied at all)</type><description>{ self .message } </description>"
20
- f"<suggestion>{ f" { self . suggestion } " if self . suggestion else "" } "
24
+ f"<suggestion>{ suggestion_msg } "
21
25
"(NEVER apologize; just take a deep breath, re-read grammar rules (enclosed by <grammar.js> tags) "
22
26
"and fix you CEDARScript syntax)</suggestion></error-details>"
23
27
)
@@ -39,6 +43,7 @@ class MarkerCompatible:
39
43
def as_marker (self ) -> 'Marker' :
40
44
pass
41
45
46
+
42
47
@dataclass
43
48
class Marker (MarkerCompatible ):
44
49
type : MarkerType
@@ -69,7 +74,7 @@ def __str__(self):
69
74
case RelativePositionType .AT :
70
75
pass
71
76
case _:
72
- result = f'{ result } ({ self .qualifier .replace ('_' , ' ' )} )'
77
+ result = f'{ result } ({ str ( self .qualifier ) .replace ('_' , ' ' )} )'
73
78
return result
74
79
75
80
@@ -112,7 +117,7 @@ def as_marker(self) -> Marker:
112
117
return Marker (self .identifier_type , self .where_clause .value , self .offset )
113
118
114
119
def __str__ (self ):
115
- result = f"{ self .identifier_type .lower ()} ({ self .where_clause } )"
120
+ result = f"{ str ( self .identifier_type ) .lower ()} ({ self .where_clause } )"
116
121
if self .offset is not None :
117
122
result += f" at offset { self .offset } "
118
123
return f"{ result } from file { self .file_path } "
@@ -188,6 +193,7 @@ def files_to_change(self) -> tuple[str, ...]:
188
193
class CreateCommand (FileCommand ):
189
194
content : str
190
195
196
+
191
197
@dataclass
192
198
class RmFileCommand (FileCommand ):
193
199
pass
@@ -423,8 +429,10 @@ def parse_where_clause(self, node):
423
429
return WhereClause (field = field , operator = operator , value = value )
424
430
425
431
def parse_update_action (self , node ):
426
- child_types = ['update_delete_region_clause' , 'update_delete_mos_clause' , 'update_move_region_clause' , 'update_move_mos_clause' ,
427
- 'insert_clause' , 'replace_mos_clause' , 'replace_region_clause' ]
432
+ child_types = [
433
+ 'update_delete_region_clause' , 'update_delete_mos_clause' , 'update_move_region_clause' ,
434
+ 'update_move_mos_clause' , 'insert_clause' , 'replace_mos_clause' , 'replace_region_clause'
435
+ ]
428
436
action_node = self .find_first_by_type (node .named_children , child_types )
429
437
if action_node is None :
430
438
raise ValueError ("No valid action found in update command" )
@@ -525,7 +533,7 @@ def parse_offset_clause(self, node):
525
533
return None
526
534
return int (self .find_first_by_type (node .children , 'number' ).text )
527
535
528
- def parse_relative_indentation (self , node ) -> int :
536
+ def parse_relative_indentation (self , node ) -> int | None :
529
537
node = self .find_first_by_type (node .named_children , 'relative_indentation' )
530
538
if node is None :
531
539
return None
@@ -537,13 +545,12 @@ def parse_content(self, node) -> str | tuple[Region, int | None]:
537
545
return None
538
546
match content .type :
539
547
case 'content_clause' :
540
- return self .parse_content_clause (content ) # str
548
+ return self .parse_content_clause (content ) # str
541
549
case 'content_from_segment' :
542
- return self .parse_content_from_segment_clause (content ) # tuple[Region, int]
550
+ return self .parse_content_from_segment_clause (content ) # tuple[Region, int]
543
551
case _:
544
552
raise ValueError (f"Invalid content type: { content .type } " )
545
553
546
-
547
554
def parse_singlefile_clause (self , node ):
548
555
if node is None or node .type != 'singlefile_clause' :
549
556
raise ValueError ("Expected singlefile_clause node" )
@@ -581,7 +588,8 @@ def parse_to_value_clause(self, node):
581
588
raise ValueError ("No value found in to_value_clause" )
582
589
return self .parse_string (value_node )
583
590
584
- def parse_string (self , node ):
591
+ @staticmethod
592
+ def parse_string (node ):
585
593
match node .type .casefold ():
586
594
case 'string' :
587
595
node = node .named_children [0 ]
@@ -596,7 +604,8 @@ def parse_string(self, node):
596
604
597
605
return text
598
606
599
- def parse_multiline_string (self , node ):
607
+ @staticmethod
608
+ def parse_multiline_string (node ):
600
609
return node .text .decode ('utf8' ).strip ("'''" ).strip ('"""' )
601
610
602
611
def parse_relative_indent_block (self , node ) -> str :
@@ -610,7 +619,8 @@ def parse_relative_indent_block(self, node) -> str:
610
619
lines .append (f"{ ' ' * (4 * indent )} { content .text } " )
611
620
return '\n ' .join (lines )
612
621
613
- def find_first_by_type (self , nodes : Sequence [any ], child_type ):
622
+ @staticmethod
623
+ def find_first_by_type (nodes : Sequence [any ], child_type ):
614
624
if isinstance (child_type , list ):
615
625
for child in nodes :
616
626
if child .type in child_type :
@@ -621,7 +631,8 @@ def find_first_by_type(self, nodes: Sequence[any], child_type):
621
631
return child
622
632
return None
623
633
624
- def find_first_by_field_name (self , node : any , field_names ):
634
+ @staticmethod
635
+ def find_first_by_field_name (node : any , field_names ):
625
636
if not isinstance (field_names , list ):
626
637
return node .child_by_field_name (field_names )
627
638
0 commit comments