diff --git a/README.md b/README.md index d56e1a6..2a1d036 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ AI-assisted development tools to understand and execute these tasks. ## Features - Parse `CEDARScript` Abstract Syntax Tree (`AST`) that was generated by Tree-Sitter into a list of commands -- Support for various code manipulation andn analysis commands (CREATE, UPDATE, RM, MV, SELECT) +- Support for various code manipulation and analysis commands (CREATE, UPDATE, RM, MV, SELECT) - Return results in `XML` format for easier parsing and processing by LLM systems ## Installation diff --git a/src/cedarscript_ast_parser/__init__.py b/src/cedarscript_ast_parser/__init__.py index 58d14bc..017182b 100644 --- a/src/cedarscript_ast_parser/__init__.py +++ b/src/cedarscript_ast_parser/__init__.py @@ -1,17 +1,19 @@ -__version__ = "0.2.0" +__version__ = "0.2.1" from .cedarscript_ast_parser import ( CEDARScriptASTParser, ParseError, Command, CreateCommand, RmFileCommand, MvFileCommand, UpdateCommand, - SelectCommand, IdentifierFromFile, SingleFileClause, Segment, Marker, BodyOrWhole, MarkerType, RelativeMarker, RelativePositionType, - MoveClause, DeleteClause, InsertClause, ReplaceClause, EditingAction, Region, BodyOrWhole, WhereClause, RegionClause + SelectCommand, IdentifierFromFile, SingleFileClause, Segment, Marker, BodyOrWhole, MarkerType, RelativeMarker, + RelativePositionType, MoveClause, DeleteClause, InsertClause, ReplaceClause, EditingAction, Region, BodyOrWhole, + WhereClause, RegionClause ) __all__ = ( CEDARScriptASTParser, ParseError, Command, CreateCommand, RmFileCommand, MvFileCommand, UpdateCommand, - SelectCommand, IdentifierFromFile, SingleFileClause, Segment, Marker, BodyOrWhole, MarkerType, RelativeMarker, RelativePositionType, - MoveClause, DeleteClause, InsertClause, ReplaceClause, EditingAction, Region, BodyOrWhole, WhereClause, RegionClause + SelectCommand, IdentifierFromFile, SingleFileClause, Segment, Marker, BodyOrWhole, MarkerType, RelativeMarker, + RelativePositionType, MoveClause, DeleteClause, InsertClause, ReplaceClause, EditingAction, Region, BodyOrWhole, + WhereClause, RegionClause ) diff --git a/src/cedarscript_ast_parser/cedarscript_ast_parser.py b/src/cedarscript_ast_parser/cedarscript_ast_parser.py index a78a3b5..36bcba2 100644 --- a/src/cedarscript_ast_parser/cedarscript_ast_parser.py +++ b/src/cedarscript_ast_parser/cedarscript_ast_parser.py @@ -6,6 +6,7 @@ import cedarscript_grammar from dataclasses import dataclass + class ParseError(NamedTuple): command_ordinal: int message: str @@ -14,10 +15,13 @@ class ParseError(NamedTuple): suggestion: str def __str__(self): + line_msg = f'; LINE #{self.line}' if self.line else '' + col_msg = f'; COLUMN #{self.column}' if self.column else '' + suggestion_msg = f'{self.suggestion} ' if self.suggestion else '' return ( - f"COMMAND #{self.command_ordinal}{f'; LINE #{self.line}' if self.line else ''}{f'; COLUMN #{self.column}' if self.column else ''}" + f"COMMAND #{self.command_ordinal}{line_msg}{col_msg}" f"PARSING (no commands were applied at all){self.message}" - f"{f"{self.suggestion} " if self.suggestion else ""}" + f"{suggestion_msg}" "(NEVER apologize; just take a deep breath, re-read grammar rules (enclosed by tags) " "and fix you CEDARScript syntax)" ) @@ -39,6 +43,7 @@ class MarkerCompatible: def as_marker(self) -> 'Marker': pass + @dataclass class Marker(MarkerCompatible): type: MarkerType @@ -69,7 +74,7 @@ def __str__(self): case RelativePositionType.AT: pass case _: - result = f'{result} ({self.qualifier.replace('_', ' ')})' + result = f'{result} ({str(self.qualifier).replace('_', ' ')})' return result @@ -112,7 +117,7 @@ def as_marker(self) -> Marker: return Marker(self.identifier_type, self.where_clause.value, self.offset) def __str__(self): - result = f"{self.identifier_type.lower()} ({self.where_clause})" + result = f"{str(self.identifier_type).lower()} ({self.where_clause})" if self.offset is not None: result += f" at offset {self.offset}" return f"{result} from file {self.file_path}" @@ -188,6 +193,7 @@ def files_to_change(self) -> tuple[str, ...]: class CreateCommand(FileCommand): content: str + @dataclass class RmFileCommand(FileCommand): pass @@ -423,8 +429,10 @@ def parse_where_clause(self, node): return WhereClause(field=field, operator=operator, value=value) def parse_update_action(self, node): - child_types = ['update_delete_region_clause', 'update_delete_mos_clause', 'update_move_region_clause', 'update_move_mos_clause', - 'insert_clause', 'replace_mos_clause', 'replace_region_clause'] + child_types = [ + 'update_delete_region_clause', 'update_delete_mos_clause', 'update_move_region_clause', + 'update_move_mos_clause', 'insert_clause', 'replace_mos_clause', 'replace_region_clause' + ] action_node = self.find_first_by_type(node.named_children, child_types) if action_node is None: raise ValueError("No valid action found in update command") @@ -525,7 +533,7 @@ def parse_offset_clause(self, node): return None return int(self.find_first_by_type(node.children, 'number').text) - def parse_relative_indentation(self, node) -> int: + def parse_relative_indentation(self, node) -> int | None: node = self.find_first_by_type(node.named_children, 'relative_indentation') if node is None: return None @@ -537,13 +545,12 @@ def parse_content(self, node) -> str | tuple[Region, int | None]: return None match content.type: case 'content_clause': - return self.parse_content_clause(content) # str + return self.parse_content_clause(content) # str case 'content_from_segment': - return self.parse_content_from_segment_clause(content) # tuple[Region, int] + return self.parse_content_from_segment_clause(content) # tuple[Region, int] case _: raise ValueError(f"Invalid content type: {content.type}") - def parse_singlefile_clause(self, node): if node is None or node.type != 'singlefile_clause': raise ValueError("Expected singlefile_clause node") @@ -581,7 +588,8 @@ def parse_to_value_clause(self, node): raise ValueError("No value found in to_value_clause") return self.parse_string(value_node) - def parse_string(self, node): + @staticmethod + def parse_string(node): match node.type.casefold(): case 'string': node = node.named_children[0] @@ -596,7 +604,8 @@ def parse_string(self, node): return text - def parse_multiline_string(self, node): + @staticmethod + def parse_multiline_string(node): return node.text.decode('utf8').strip("'''").strip('"""') def parse_relative_indent_block(self, node) -> str: @@ -610,7 +619,8 @@ def parse_relative_indent_block(self, node) -> str: lines.append(f"{' ' * (4 * indent)}{content.text}") return '\n'.join(lines) - def find_first_by_type(self, nodes: Sequence[any], child_type): + @staticmethod + def find_first_by_type(nodes: Sequence[any], child_type): if isinstance(child_type, list): for child in nodes: if child.type in child_type: @@ -621,7 +631,8 @@ def find_first_by_type(self, nodes: Sequence[any], child_type): return child return None - def find_first_by_field_name(self, node: any, field_names): + @staticmethod + def find_first_by_field_name(node: any, field_names): if not isinstance(field_names, list): return node.child_by_field_name(field_names) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy