initial commit

This commit is contained in:
2023-10-16 21:59:05 +02:00
commit c05fc0e1ba
11 changed files with 394 additions and 0 deletions
View File
+32
View File
@@ -0,0 +1,32 @@
from dataclasses import dataclass
from enum import Enum, auto
from typing import ClassVar, DefaultDict
from .location import Range
from .tokenize import BaseToken
class ContextType(Enum):
Use = auto()
Assign = auto()
Declare = auto()
Unbind = auto()
@dataclass(frozen=True)
class Context:
lookup: ClassVar[dict[ContextType, list["Context"]]] = {}
typ: ContextType
token: list[BaseToken]
def __post_init__(self):
type(self).lookup.setdefault(self.typ, [])
type(self).lookup[self.typ].append(self)
@property
def range(self) -> Range:
new_range = self.token[0].range
for token in self.token[1:]:
new_range += token.range
return new_range
+71
View File
@@ -0,0 +1,71 @@
from dataclasses import dataclass
from functools import cached_property
from typing import overload
from lsprotocol.types import Position, Range
from parsimonious.nodes import Node
# @total_ordering
# class Position(NamedTuple):
# line: int
# char: int
#
# def __lt__(self, other: Self) -> bool:
# return (self.line < other.line) or (
# (self.line == other.line) and (self.char < other.char)
# )
#
# def __eq__(self, other: Self) -> bool:
# return (self.line == other.line) and (self.char == other.char)
#
#
# class Range(NamedTuple):
# start: Position
# end: Position
#
# def __add__(self, other: Self) -> Self:
# start = min(self.start, other.start)
# end = max(self.end, other.end)
# return Range(start, end)
#
# def contained_by(self, possibly_contained_by: Self) -> bool:
# return (self.start >= possibly_contained_by.start) and (
# self.end <= possibly_contained_by.end
# )
#
# def contains(self, possibly_contains: Self) -> bool:
# return (self.start <= possibly_contains.start) and (
# self.end >= possibly_contains.end
# )
@dataclass(frozen=True)
class Locator:
raw: str
@cached_property
def newlines(self) -> tuple[int, ...]:
t = tuple(i for i, char in enumerate(self.raw) if char == "\n")
return t
def _locate_pos(self, index: int) -> Position:
line = next(i for i, char in enumerate(self.newlines) if char >= index)
return Position(line - 1, index - (self.newlines[line - 1] if line > 0 else 0))
@overload
def locate(self, index: int) -> Position:
...
@overload
def locate(self, index: Node) -> Range:
...
def locate(self, index: int | Node) -> Position | Range:
if isinstance(index, int):
return self._locate_pos(index)
start = self._locate_pos(index.start)
end = self._locate_pos(index.end)
return Range(start, end)
+111
View File
@@ -0,0 +1,111 @@
from typing import Any, Sequence
from lsprotocol.types import Range
from parsimonious import ParseError
from dataclasses import dataclass
from parsimonious.nodes import Node, NodeVisitor
from .location import Locator
@dataclass(frozen=True)
class BaseToken:
range: Range
@dataclass(frozen=True)
class Literal(BaseToken):
value: str | float | bool
@dataclass(frozen=True)
class Token(BaseToken):
value: str
@dataclass(frozen=True)
class List(BaseToken):
value: list[BaseToken]
@dataclass
class SkillVisitor(NodeVisitor):
locator: Locator
def visit_skill(self, _: Node, visited_children: Sequence[Any]) -> list[BaseToken]:
children = []
for childlist in visited_children:
for child in childlist:
if isinstance(child, BaseToken):
children.append(child)
return children
def visit_TOKEN(self, node: Node, _: Any) -> Token:
return Token(self.locator.locate(node), node.text)
def visit_LITERAL(self, node: Node, visited_children: list[None | Node]) -> Literal:
value, *_ = visited_children
if value:
match value.expr_name:
case "L_t":
return Literal(self.locator.locate(node), True)
case "L_nil":
return Literal(self.locator.locate(node), False)
case "L_num":
return Literal(self.locator.locate(node), float(value.text))
case "L_string":
return Literal(self.locator.locate(node), value.text)
case _:
pass
raise ParseError("something went wrong during literal parsing")
def visit_listraw(
self, node: Node, visited_children: list[list[list[Any]]]
) -> List:
rest = visited_children[2]
children = []
for child in rest:
for part in child:
if isinstance(part, BaseToken):
children.append(part)
return List(self.locator.locate(node), children)
def visit_listc(self, node: Node, visited_children: list[list[list[Any]]]) -> List:
rest = ([[visited_children[0]]], visited_children[2])
children = []
for child_list in rest:
for child in child_list:
for part in child:
if isinstance(part, BaseToken):
children.append(part)
return List(self.locator.locate(node), children)
def visit_listskill(
self, node: Node, visited_children: list[list[list[Any]]]
) -> List:
rest = visited_children[1]
children = []
for child in rest:
for part in child:
if isinstance(part, BaseToken):
children.append(part)
return List(self.locator.locate(node), children)
def visit_inline_assign(self, node: Node, visited_children: Sequence[Any]):
print(node)
def generic_visit(
self, node: Node, visited_children: Sequence[Any]
) -> Node | Sequence[None | Node]:
return visited_children or node