Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/parsimonious/exceptions.py: 64%

39 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:15 +0000

1from textwrap import dedent 

2 

3from parsimonious.utils import StrAndRepr 

4 

5 

6class ParsimoniousError(Exception): 

7 """A base exception class to allow library users to catch any Parsimonious error.""" 

8 pass 

9 

10 

11class ParseError(StrAndRepr, ParsimoniousError): 

12 """A call to ``Expression.parse()`` or ``match()`` didn't match.""" 

13 

14 def __init__(self, text, pos=-1, expr=None): 

15 # It would be nice to use self.args, but I don't want to pay a penalty 

16 # to call descriptors or have the confusion of numerical indices in 

17 # Expression.match_core(). 

18 self.text = text 

19 self.pos = pos 

20 self.expr = expr 

21 

22 def __str__(self): 

23 rule_name = (("'%s'" % self.expr.name) if self.expr.name else 

24 str(self.expr)) 

25 return "Rule %s didn't match at '%s' (line %s, column %s)." % ( 

26 rule_name, 

27 self.text[self.pos:self.pos + 20], 

28 self.line(), 

29 self.column()) 

30 

31 # TODO: Add line, col, and separated-out error message so callers can build 

32 # their own presentation. 

33 

34 def line(self): 

35 """Return the 1-based line number where the expression ceased to 

36 match.""" 

37 # This is a method rather than a property in case we ever wanted to 

38 # pass in which line endings we want to use. 

39 if isinstance(self.text, list): # TokenGrammar 

40 return None 

41 else: 

42 return self.text.count('\n', 0, self.pos) + 1 

43 

44 def column(self): 

45 """Return the 1-based column where the expression ceased to match.""" 

46 # We choose 1-based because that's what Python does with SyntaxErrors. 

47 try: 

48 return self.pos - self.text.rindex('\n', 0, self.pos) 

49 except (ValueError, AttributeError): 

50 return self.pos + 1 

51 

52 

53class LeftRecursionError(ParseError): 

54 def __str__(self): 

55 rule_name = self.expr.name if self.expr.name else str(self.expr) 

56 window = self.text[self.pos:self.pos + 20] 

57 return dedent(f""" 

58 Left recursion in rule {rule_name!r} at {window!r} (line {self.line()}, column {self.column()}). 

59 

60 Parsimonious is a packrat parser, so it can't handle left recursion. 

61 See https://en.wikipedia.org/wiki/Parsing_expression_grammar#Indirect_left_recursion 

62 for how to rewrite your grammar into a rule that does not use left-recursion. 

63 """ 

64 ).strip() 

65 

66 

67class IncompleteParseError(ParseError): 

68 """A call to ``parse()`` matched a whole Expression but did not consume the 

69 entire text.""" 

70 

71 def __str__(self): 

72 return "Rule '%s' matched in its entirety, but it didn't consume all the text. The non-matching portion of the text begins with '%s' (line %s, column %s)." % ( 

73 self.expr.name, 

74 self.text[self.pos:self.pos + 20], 

75 self.line(), 

76 self.column()) 

77 

78 

79class VisitationError(ParsimoniousError): 

80 """Something went wrong while traversing a parse tree. 

81 

82 This exception exists to augment an underlying exception with information 

83 about where in the parse tree the error occurred. Otherwise, it could be 

84 tiresome to figure out what went wrong; you'd have to play back the whole 

85 tree traversal in your head. 

86 

87 """ 

88 # TODO: Make sure this is pickleable. Probably use @property pattern. Make 

89 # the original exc and node available on it if they don't cause a whole 

90 # raft of stack frames to be retained. 

91 def __init__(self, exc, exc_class, node): 

92 """Construct. 

93 

94 :arg exc: What went wrong. We wrap this and add more info. 

95 :arg node: The node at which the error occurred 

96 

97 """ 

98 self.original_class = exc_class 

99 super().__init__( 

100 '%s: %s\n\n' 

101 'Parse tree:\n' 

102 '%s' % 

103 (exc_class.__name__, 

104 exc, 

105 node.prettily(error=node))) 

106 

107 

108class BadGrammar(StrAndRepr, ParsimoniousError): 

109 """Something was wrong with the definition of a grammar. 

110 

111 Note that a ParseError might be raised instead if the error is in the 

112 grammar definition syntax. 

113 

114 """ 

115 

116 

117class UndefinedLabel(BadGrammar): 

118 """A rule referenced in a grammar was never defined. 

119 

120 Circular references and forward references are okay, but you have to define 

121 stuff at some point. 

122 

123 """ 

124 def __init__(self, label): 

125 self.label = label 

126 

127 def __str__(self): 

128 return 'The label "%s" was never defined.' % self.label