skill-ls/skillls/parsing/tokenize.py

112 lines
3.1 KiB
Python

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