Coverage for phml\nodes\position.py: 100%
18 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-08 16:33 -0600
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-08 16:33 -0600
1from __future__ import annotations
3from typing import TYPE_CHECKING, Optional
5if TYPE_CHECKING:
6 from .point import Point
9class Position:
10 """Position represents the location of a node in a source file.
12 The `start` field of `Position` represents the place of the first character
13 of the parsed source region. The `end` field of Position represents the place
14 of the first character after the parsed source region, whether it exists or not.
15 The value of the `start` and `end` fields implement the `Point` interface.
17 The `indent` field of `Position` represents the start column at each index
18 (plus start line) in the source region, for elements that span multiple lines.
20 If the syntactic unit represented by a node is not present in the source file at
21 the time of parsing, the node is said to be `generated` and it must not have positional
22 information.
23 """
25 def __init__(self, start: Point, end: Point, indent: Optional[int] = None):
26 self.start = start
27 self.end = end
29 if indent is not None and indent < 0:
30 raise IndexError(f"Position.indent value must be >= 0 or None but was {indent}")
32 self.indent = indent
34 def __eq__(self, obj) -> bool:
35 return bool(
36 obj is not None
37 and isinstance(obj, Position)
38 and self.start == obj.start
39 and self.end == obj.end
40 )
42 def as_dict(self) -> dict:
43 """Convert the position object to a dict."""
44 return {
45 "start": {
46 "line": self.start.line,
47 "column": self.start.column,
48 "offset": self.start.offset,
49 },
50 "end": {"line": self.end.line, "column": self.end.column, "offset": self.end.offset},
51 "indent": self.indent,
52 }
54 def __repr__(self) -> str:
55 indent = f" ~ {self.indent}" if self.indent is not None else ""
56 return f"<{self.start}-{self.end}{indent}>"
58 def __str__(self) -> str:
59 return repr(self)