Compare commits

..

No commits in common. "main" and "9e5d32a42095427200c5260dd155a250fb739872" have entirely different histories.

24 changed files with 1022 additions and 1010 deletions

7
.gitignore vendored
View File

@ -1,5 +1,2 @@
.venv/* zig-cache
.idea/* zig-out
*.egg-info/*
**/__pycache__/*
*.log

20
.vscode/launch.json vendored
View File

@ -1,20 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "main",
"type": "python",
"request": "launch",
"program": "/home/patrick/git/skill-ls/.venv/bin/skillls",
"python": "/home/patrick/git/skill-ls/.venv/bin/python"
},
{
"name": "main",
"type": "python",
"request": "launch",
"module": "skillls.parsing.iterative",
"python": "/home/patrick/git/skill-ls/.venv/bin/python"
}
]
}

91
build.zig Normal file
View File

@ -0,0 +1,91 @@
const std = @import("std");
// Although this function looks imperative, note that its job is to
// declaratively construct a build graph that will be executed by an external
// runner.
pub fn build(b: *std.Build) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{});
const lib = b.addStaticLibrary(.{
.name = "skill-ls",
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
// This declares intent for the library to be installed into the standard
// location when the user invokes the "install" step (the default step when
// running `zig build`).
b.installArtifact(lib);
const exe = b.addExecutable(.{
.name = "skill-ls",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// This declares intent for the executable to be installed into the
// standard location when the user invokes the "install" step (the default
// step when running `zig build`).
b.installArtifact(exe);
// This *creates* a Run step in the build graph, to be executed when another
// step is evaluated that depends on it. The next line below will establish
// such a dependency.
const run_cmd = b.addRunArtifact(exe);
// By making the run step depend on the install step, it will be run from the
// installation directory rather than directly from within the cache directory.
// This is not necessary, however, if the application depends on other installed
// files, this ensures they will be present and in the expected location.
run_cmd.step.dependOn(b.getInstallStep());
// This allows the user to pass arguments to the application in the build
// command itself, like this: `zig build run -- arg1 arg2 etc`
if (b.args) |args| {
run_cmd.addArgs(args);
}
// This creates a build step. It will be visible in the `zig build --help` menu,
// and can be selected like this: `zig build run`
// This will evaluate the `run` step rather than the default, which is "install".
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// Creates a step for unit testing. This only builds the test executable
// but does not run it.
const lib_unit_tests = b.addTest(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
const exe_unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
// Similar to creating the run step earlier, this exposes a `test` step to
// the `zig build --help` menu, providing a way for the user to request
// running the unit tests.
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_lib_unit_tests.step);
test_step.dependOn(&run_exe_unit_tests.step);
}

70
build.zig.zon Normal file
View File

@ -0,0 +1,70 @@
.{
.name = "skill-ls",
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0",
// This field is optional.
// This is currently advisory only; Zig does not yet do anything
// with this value.
//.minimum_zig_version = "0.11.0",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{
.lsfw = .{
.path = "lib/lsfw",
}
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
//.example = .{
// // When updating this field to a new URL, be sure to delete the corresponding
// // `hash`, otherwise you are communicating that you expect to find the old hash at
// // the new URL.
// .url = "https://example.com/foo.tar.gz",
//
// // This is computed from the file contents of the directory of files that is
// // obtained after fetching `url` and applying the inclusion rules given by
// // `paths`.
// //
// // This field is the source of truth; packages do not come from a `url`; they
// // come from a `hash`. `url` is just one of many possible mirrors for how to
// // obtain a package matching this `hash`.
// //
// // Uses the [multihash](https://multiformats.io/multihash/) format.
// .hash = "...",
//
// // When this is provided, the package is found in a directory relative to the
// // build root. In this case the package's hash is irrelevant and therefore not
// // computed. This field and `url` are mutually exclusive.
// .path = "foo",
// // When this is set to `true`, a package is declared to be lazily
// // fetched. This makes the dependency only get fetched if it is
// // actually used.
// .lazy = false,
//},
},
// Specifies the set of files and directories that are included in this package.
// Only files and directories listed here are included in the `hash` that
// is computed for this package.
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{
// This makes *all* files, recursively, included in this package. It is generally
// better to explicitly list the files and directories instead, to insure that
// fetching from tarballs, file system paths, and version control all result
// in the same contents hash.
"",
// For example...
//"build.zig",
//"build.zig.zon",
//"src",
//"LICENSE",
//"README.md",
},
}

19
data/example.il Normal file
View File

@ -0,0 +1,19 @@
;;; this is some example module docstring
; random comment
a=1+2.0*3e2-4/ 5
b_var->a
(list 1 2 34)
'(1 2 3 4)
(procedure func_name(param1 param2 @keys (a nil))
; some struff to do
)
"srting"
"wqdwd\"qwesfwf"

View File

@ -1,42 +0,0 @@
example = nil
example2 = example
(call qdwdq)
;; func2(g_arg1 g_arg2 ?g_args1 1 ?g_argw 2) => nil
(procedure Func2(arg1 arg2 @keys (args "ss") (argw 2) "ggng")
(let ()
; some stuff to do
a = some_obj->field1
some_obj->field2 = 2
db_obj->help()
args = 2
args
(foreach inner arg2
;hi
)
(procedure Wqrqw(a1 a2 @keys (a "12") "sqd")
)
)
)
(let (some vars (default "sd"))
; ... some wall of text
"))\""
wqdqwf = '(doqwf)
'wq
var = 1.3
vars = 231
qqvwv
if(expr then expr else expr)
cfunc()
)
let( (inner inner2)
; block
)
somefunccall("somecalcfunc()")

View File

@ -1,43 +0,0 @@
[project]
name = "skillls"
version = "0.1.0"
dependencies = [
"parsimonious~=0.10.0",
"pygls~=2.0",
"rich",
"tree-sitter>=0.24.0",
"tree-sitter-skill>=0.1.5",
]
requires-python = ">= 3.11"
[project.optional-dependencies]
dev = [
"black",
"mypy",
"ruff",
"pytest",
"types-parsimonious",
]
[build-system]
build-backend = 'setuptools.build_meta'
requires = [
'setuptools',
]
[project.scripts]
skillls = "skillls.main:main"
[tools.black]
line-length = 100
target-version = "py311"
include = "skillls"
[tools.ruff]
line-length = 100
include = ['ALL']
[tool.uv.sources]
tree-sitter-skill = { git = "ssh://git@git.acereca.net/acereca/tree-sitter-skill.git" }

View File

View File

@ -1,75 +0,0 @@
from dataclasses import dataclass
from enum import Enum, auto
from lsprotocol.types import Location, Position, Range
from skillls.types import URI
class SyntaxError(Exception):
pass
class ParenMismatchErrorKind(Enum):
TooManyClosed = "Found too many closing parens"
TooManyOpened = "Found too many open parens"
@dataclass
class ParenMismatchError(SyntaxError):
kind: ParenMismatchErrorKind
loc: Range
def _check_for_matching_parens(content: str) -> list[Exception]:
excs: list[Exception] = []
opened = 0
line = 0
col = 0
last_open: Position = Position(0, 0)
last_close: Position = Position(0, 0)
for char in content:
match char:
case "(":
opened += 1
last_open = Position(line, col)
case ")":
opened -= 1
if opened < 0:
excs.append(
ParenMismatchError(
ParenMismatchErrorKind.TooManyClosed,
Range(Position(line, col), Position(line, col + 1)),
)
)
opened = 0
last_close = Position(line, col)
case "\n":
line += 1
col = -1
case _:
pass
col += 1
if opened > 0:
excs.append(
ParenMismatchError(
ParenMismatchErrorKind.TooManyOpened,
Range(last_open, Position(last_open.line, last_open.character + 1)),
)
)
return excs
def check_content_for_errors(clean_content: str) -> None:
excs: list[Exception] = []
excs.extend(_check_for_matching_parens(clean_content))
if excs:
raise ExceptionGroup("", excs)

View File

@ -1,192 +0,0 @@
from copy import copy
from dataclasses import dataclass
from logging import getLogger
from pathlib import Path
from pprint import pformat
from lsprotocol.types import DocumentSymbol, Position, Range, SymbolKind
from re import MULTILINE, compile as recompile, finditer
from pygls.workspace import TextDocument
from skillls.checker import check_content_for_errors
from skillls.types import URI, Node, NodeKind
logger = getLogger(__name__)
@dataclass
class ParserCleanerState:
in_comment: bool = False
in_string: bool = False
NODE_KIND_OPTIONS = "|".join(k.value for k in NodeKind)
NAMESPACE_STARTERS = recompile(
(rf"(\(\s*(?P<typ>{NODE_KIND_OPTIONS})\b|\b(?P<ctyp>{NODE_KIND_OPTIONS})\()"),
MULTILINE,
)
def clean_content(content: str) -> str:
content_cleaned = ""
state = ParserCleanerState()
for cix, char in enumerate(content):
match (content[cix], state):
case ";", ParserCleanerState(in_comment=False, in_string=False):
state.in_comment = True
case '"', ParserCleanerState(in_comment=False):
if content[cix - 1] != "\\":
state.in_string = not state.in_string
content_cleaned += char
case "\n", ParserCleanerState(in_comment=True):
state.in_comment = False
content_cleaned += char
case _, ParserCleanerState(in_comment=False, in_string=False):
content_cleaned += char
case _, ParserCleanerState(in_comment=False, in_string=True):
content_cleaned += " "
case _:
pass
return content_cleaned
def build_node_hierarchy(nodes: list[Node]) -> list[Node]:
to_be_sorted = copy(nodes)
sorted: list[Node] = []
while to_be_sorted:
node_to_sort = to_be_sorted.pop(0)
for sorted_node in sorted:
if sorted_node.should_contain(node_to_sort):
sorted_node.add_child(node_to_sort)
break
else:
sorted.append(node_to_sort)
return sorted
def find_scopes(content_cleaned: str, scope_prefix: str = "") -> list[Node]:
ret: list[Node] = []
for found in NAMESPACE_STARTERS.finditer(content_cleaned):
partial = content_cleaned[found.end() :]
open_brackets = 1
offset = 0
for offset, char in enumerate(partial):
match char:
case "(":
open_brackets += 1
case ")":
open_brackets -= 1
if open_brackets == 0:
break
case _:
pass
pre_lines = content_cleaned[: found.start()].splitlines()
start_line = len(pre_lines) - (
1 if pre_lines[-1] != "" and pre_lines[-1].strip() == "" else 0
)
start_char = len(pre_lines[-1])
inner_lines = content_cleaned[
found.start() : found.end() + offset + 1
].splitlines()
end_line = start_line + len(inner_lines) - 1
end_char = len(inner_lines[-1])
kind = NodeKind(found.group("typ") or found.group("ctyp"))
loc = Range(Position(start_line, start_char), Position(end_line, end_char))
node = Node(
node=f"{scope_prefix}.{kind.value}_{len([n for n in ret if n.kind == kind])}",
kind=kind,
location=loc,
)
ret.append(node)
next = found.end()
# allowed scoped locals syntax
# function(pos1 pos2)
# function(pos1 (pos2 default))
# function(pos1 @rest args)
# function(pos1 @key (kwarg1 default1) (kwarg2 default2))
while content_cleaned[next] != "(":
if content_cleaned[next] == "\n":
start_line += 1
start_char = 0
next += 1
start_char += 1
next += 1
last = 0
for positional in finditer(
r"(?P<leading>\s*)(?P<local>\w+|\(\w+\b[^)]*\))(?P<trailing>\s*)",
content_cleaned[next:],
):
if positional.start() != last:
logger.debug(
f"found ({positional}), but last ({last}) != ({positional.start()})"
)
break
last = positional.end()
leading_nls = positional.group("leading").count("\n")
inner_nls = positional.group("local").count("\n")
trailing_nls = positional.group("trailing").count("\n")
local_name = positional.group("local").split()[0]
local = DocumentSymbol(
name=local_name,
kind=SymbolKind.Variable,
range=Range(
Position(
start_line + leading_nls,
len(positional.group("leading")) + start_char,
),
Position(
start_line + leading_nls,
len(positional.group("leading")) + start_char + len(local_name),
),
),
selection_range=Range(
Position(
start_line + leading_nls,
len(positional.group("leading")) + start_char,
),
Position(
start_line + leading_nls,
len(positional.group("leading")) + start_char + len(local_name),
),
),
)
node.symbols[local_name] = local
start_line += leading_nls + inner_nls + trailing_nls
start_char += len(positional.group(0))
# other cases
logger.debug(pformat(node))
return build_node_hierarchy(ret)
def parse_file(file: TextDocument) -> list[Node]:
content = file.source
content_cleaned = clean_content(content)
check_content_for_errors(content_cleaned)
return find_scopes(content_cleaned, scope_prefix=Path(file.path).stem)

View File

@ -1,167 +0,0 @@
from logging import DEBUG, basicConfig, getLogger
from pathlib import Path
from typing import Any
from lsprotocol.types import (
TEXT_DOCUMENT_DID_CHANGE,
TEXT_DOCUMENT_DID_CLOSE,
TEXT_DOCUMENT_DID_OPEN,
INITIALIZE,
TEXT_DOCUMENT_DID_SAVE,
TEXT_DOCUMENT_DOCUMENT_SYMBOL,
TEXT_DOCUMENT_INLAY_HINT,
Diagnostic,
DiagnosticSeverity,
DidChangeTextDocumentParams,
DidCloseTextDocumentParams,
DidOpenTextDocumentParams,
DocumentSymbol,
DocumentSymbolParams,
InitializeParams,
InlayHint,
InlayHintKind,
InlayHintParams,
NotebookDocumentSyncOptions,
PublishDiagnosticsParams,
TextDocumentSyncKind,
)
from pygls.lsp.server import LanguageServer
from skillls.checker import ParenMismatchError
from skillls.helpers import parse_file
from skillls.types import URI, Node
basicConfig(
filename="skillls.log",
filemode="w",
level=DEBUG,
format="%(asctime)s [%(levelname)s]: %(message)s",
)
logger = getLogger(__name__)
class SkillLanguageServer(LanguageServer):
ws_files: set[URI]
opened_files: set[URI]
scopes: dict[URI, list[Node]]
errs: dict[URI, ExceptionGroup]
def __init__(
self,
name: str,
version: str,
text_document_sync_kind: TextDocumentSyncKind = TextDocumentSyncKind.Incremental,
notebook_document_sync: NotebookDocumentSyncOptions | None = None,
):
super().__init__(name, version, text_document_sync_kind, notebook_document_sync)
self.ws_files = set()
self.opened_files = set()
self.scopes = {}
self.errs = {}
def update_diagnostics(self) -> None:
for uri in self.opened_files:
diags: list[Diagnostic] = []
if eg := self.errs.get(uri):
for exc in eg.exceptions:
match exc:
case ParenMismatchError():
diags.append(
Diagnostic(
message=f"[skill_ls] {Path.from_uri(uri).name}:{exc.loc.start.line} {exc.kind.value}",
severity=DiagnosticSeverity.Error,
range=exc.loc,
)
)
# if diags:
self.text_document_publish_diagnostics(
PublishDiagnosticsParams(
uri=uri,
version=self.workspace.get_text_document(uri).version,
diagnostics=diags,
)
)
server = SkillLanguageServer("SkillLS", "0.2.0")
@server.feature(INITIALIZE)
def lsp_initialize(server: SkillLanguageServer, params: InitializeParams) -> None:
init_options: dict[str, Any] = params.initialization_options or {}
logger.info("done init")
logger.debug(init_options)
ws_dir = server.workspace.root_path
logger.debug(ws_dir)
if ws_dir:
root_dir = Path(ws_dir)
for file in (*root_dir.rglob("*.il"), *root_dir.rglob("*.ocn")):
uri = file.as_uri()
logger.debug(uri)
server.ws_files.add(uri)
try:
server.scopes[uri] = parse_file(server.workspace.get_text_document(uri))
if server.errs.get(uri):
del server.errs[uri]
except ExceptionGroup as eg:
server.errs[uri] = eg
@server.feature(TEXT_DOCUMENT_DID_OPEN)
def on_open(server: SkillLanguageServer, params: DidOpenTextDocumentParams) -> None:
server.opened_files.add(params.text_document.uri)
server.update_diagnostics()
@server.feature(TEXT_DOCUMENT_DID_CLOSE)
def on_close(server: SkillLanguageServer, params: DidCloseTextDocumentParams) -> None:
server.opened_files.remove(params.text_document.uri)
@server.feature(TEXT_DOCUMENT_DID_CHANGE)
@server.feature(TEXT_DOCUMENT_DID_SAVE)
def on_change(server: SkillLanguageServer, params: DidChangeTextDocumentParams) -> None:
try:
server.scopes[params.text_document.uri] = parse_file(
server.workspace.get_text_document(params.text_document.uri)
)
if server.errs.get(params.text_document.uri):
del server.errs[params.text_document.uri]
except ExceptionGroup as eg:
server.errs[params.text_document.uri] = eg
server.update_diagnostics()
@server.feature(TEXT_DOCUMENT_INLAY_HINT)
def on_inlay(server: SkillLanguageServer, params: InlayHintParams) -> list[InlayHint]:
hints: list[InlayHint] = []
uri = params.text_document.uri
for node in server.scopes.get(uri, []):
hints.append(
InlayHint(
label=node.node,
kind=InlayHintKind.Type,
padding_left=True,
position=node.location.end,
)
)
return hints
@server.feature(TEXT_DOCUMENT_DOCUMENT_SYMBOL)
def on_symbols(
server: SkillLanguageServer, params: DocumentSymbolParams
) -> list[DocumentSymbol] | None:
return [node.as_doc_symbol() for node in server.scopes[params.text_document.uri]]
def main():
server.start_io()

View File

@ -1,66 +0,0 @@
from dataclasses import dataclass, field
from enum import Enum, auto
from lsprotocol.types import DocumentSymbol, Range, SymbolKind
URI = str
class NodeKind(Enum):
LET = "let"
PROCEDURE = "procedure"
PROC = "proc"
FOREACH = "foreach"
@dataclass
class Node:
node: str
kind: NodeKind
location: Range
children: list["Node"] = field(default_factory=list)
symbols: dict[str, DocumentSymbol] = field(default_factory=dict)
@property
def all_symbols(self) -> list[DocumentSymbol]:
return [
*self.symbols.values(),
*(sym for child in self.children for sym in child.all_symbols),
]
def should_contain(self, other: "Node") -> bool:
"""range based overlap check"""
start_after = (other.location.start.line > self.location.start.line) or (
(other.location.start.line == self.location.start.line)
and (other.location.start.character > self.location.start.character)
)
ends_before = (other.location.end.line < self.location.end.line) or (
(other.location.end.line == self.location.end.line)
and (other.location.end.character < self.location.start.character)
)
return start_after and ends_before
def add_child(self, new_child: "Node") -> None:
for existing_child in self.children:
if existing_child.should_contain(new_child):
existing_child.add_child(new_child)
break
else:
self.children.append(new_child)
def as_doc_symbol(self) -> DocumentSymbol:
return DocumentSymbol(
name=self.node,
kind=SymbolKind.Namespace,
range=self.location,
selection_range=self.location,
children=list(self.symbols.values())
+ [child.as_doc_symbol() for child in self.children],
)
@dataclass
class DocumentSymbols:
uri: str
tree: Node

91
src/classifier.zig Normal file
View File

@ -0,0 +1,91 @@
const tkz = @import("tokenize.zig");
const hlp = @import("helpers.zig");
const std = @import("std");
pub const TokenClass = enum {
symbol,
string,
comment,
docstring,
number,
nil,
t,
list_start,
list_lazy_start,
list_end,
operator,
};
pub const ClassifiedToken = struct {
tok: tkz.Token,
cls: TokenClass,
};
const operators = std.ComptimeStringMap(void, .{
.{"->"},
.{"~>"},
.{"/="},
.{"*="},
.{"-="},
.{"+="},
.{"||"},
.{"&&"},
.{"="},
.{"+"},
.{"-"},
.{"*"},
.{"/"},
.{"~"},
.{"%"},
.{"@keys"},
.{"@rest"},
});
const numbers = std.ComptimeStringMap(void, .{
.{"0"},
.{"1"},
.{"2"},
.{"3"},
.{"4"},
.{"5"},
.{"6"},
.{"7"},
.{"8"},
.{"9"},
});
fn classify(tok: tkz.Token) ClassifiedToken {
return ClassifiedToken{
.tok = tok,
.cls = if (operators.has(tok.value))
TokenClass.operator
else if (std.mem.eql(u8, "'(", tok.value))
TokenClass.list_lazy_start
else if (std.mem.eql(u8, "(", tok.value))
TokenClass.list_start
else if (std.mem.eql(u8, ")", tok.value))
TokenClass.list_end
else if (std.mem.eql(u8, "\"", tok.value[0..1]))
TokenClass.string
else if (std.mem.eql(u8, "nil", tok.value))
TokenClass.nil
else if (std.mem.eql(u8, "t", tok.value))
TokenClass.t
else if (numbers.has(tok.value[0..1]))
TokenClass.number
else if (std.mem.eql(u8, ";", tok.value[0..1]))
if (tok.value.len >= 3 and std.mem.eql(u8, ";;;", tok.value[0..3])) TokenClass.docstring else TokenClass.comment
else
TokenClass.symbol,
};
}
pub fn classifyTokens(toks: []const tkz.Token, allocator: std.mem.Allocator) !std.ArrayList(ClassifiedToken) {
var ctoks = std.ArrayList(ClassifiedToken).init(allocator);
for (toks) |tok| {
try ctoks.append(classify(tok));
}
return ctoks;
}

9
src/helpers.zig Normal file
View File

@ -0,0 +1,9 @@
const std = @import("std");
pub fn isPartOf(comptime T: type, haystack: [][]const T, needle: []const T) bool {
for (haystack) |straw| {
if (std.mem.eql(u8, straw, needle[0..straw.len])) {
return true;
}
}
return false;
}

1
src/lsfw Submodule

@ -0,0 +1 @@
Subproject commit 5077a6cc6d6e0cf8ed95db234146aa14c42767f0

90
src/lsp.zig Normal file
View File

@ -0,0 +1,90 @@
const std = @import("std");
const lsp_types = @import("lsfw/src/types.zig");
const lsp = @import("lsfw/src/lsp.zig");
const lsp_doc = @import("lsfw/src/document.zig");
const lsp_log = @import("lsfw/src/logger.zig");
const tkz = @import("tokenize.zig");
const cls = @import("classifier.zig");
const State = struct { symbols: std.ArrayList(cls.ClassifiedToken) };
const Lsp = lsp.Lsp(State);
const Scope = enum { hi };
fn handleHover(allocator: std.mem.Allocator, ctx: *Lsp.Context, pos: lsp_types.Position) ?[]const u8 {
if (null == ctx.state) {
lsp_log.notify(.info, "could not find token under cursor (at {})", .{pos});
return null;
} else if (0 == ctx.state.?.symbols.items.len) {
handleDocOpen(allocator, ctx);
}
lsp_log.notify(.err, "{}", .{ctx.state.?.symbols});
// for (ctx.state.?.symbols.items) |tok| {
// if (tok.tok.line == pos.line and tok.tok.char <= pos.character and (tok.tok.char + tok.tok.value.len) >= pos.character) {
// lsp_log.notify(.info, "{}", .{tok});
// break;
// }
// }
return null;
}
fn handleCompletion(allocator: std.mem.Allocator, context: *Lsp.Context, position: lsp_types.Position) ?lsp_types.CompletionList {
_ = context;
_ = position;
var completions = std.ArrayList(lsp_types.CompletionItem).init(allocator);
if (std.mem.Allocator.Error.OutOfMemory == completions.append(.{
.label = "(procedure)",
.insertText = "(procedure ${1:func_name}($2)\n\n)",
.insertTextFormat = .Snippet,
.kind = .Function,
})) {
return null;
}
return .{ .items = completions.items };
}
fn handleDocOpen(allocator: std.mem.Allocator, context: *Lsp.Context) void {
lsp_log.notify(.err, "opened doc {s}", .{context.document.uri});
const content = context.document.text;
const toks = tkz.tokenizeContent(content, allocator) catch unreachable;
// const toks = std.ArrayList(tkz.Token).init(allocator);
lsp_log.notify(.err, "toks {}", .{toks});
// defer toks.deinit();
const ctoks = cls.classifyTokens(toks.items, allocator) catch unreachable;
lsp_log.notify(.err, "ctoks {}", .{ctoks});
// defer ctoks.deinit();
// const ast = try stx.generateSyntaxTree(ctoks);
lsp_log.notify(.info, "opened {s}, found {d} tokens", .{ context.document.uri, ctoks.items.len });
if (context.state != null) {
context.state.?.symbols.deinit();
}
context.state = .{
.symbols = std.ArrayList(cls.ClassifiedToken).init(allocator),
};
}
fn handleDocChanged(allocator: std.mem.Allocator, context: *Lsp.Context, _: []lsp_types.ChangeEvent) void {
handleDocOpen(allocator, context);
}
fn handleDocClose(_: std.mem.Allocator, _: *Lsp.Context) void {}
pub fn start() !u8 {
const descr = lsp_types.ServerData{
.serverInfo = .{
.name = "skill lsp",
.version = "0.1.0",
},
};
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
var server = Lsp.init(gpa.allocator(), descr);
server.registerHoverCallback(handleHover);
server.registerCompletionCallback(handleCompletion);
server.registerDocOpenCallback(handleDocOpen);
server.registerDocChangeCallback(handleDocChanged);
server.registerDocCloseCallback(handleDocClose);
return server.start();
}

35
src/main.zig Normal file
View File

@ -0,0 +1,35 @@
const std = @import("std");
const tkz = @import("tokenizer.zig");
// const cls = @import("classifier.zig");
// const stx = @import("syntax.zig");
const lsp = @import("lsp.zig");
pub fn main() !void {
// var file = try std.fs.cwd().openFile("data/example.il", .{});
// defer file.close();
//
// const content = try file.readToEndAlloc(std.heap.page_allocator, 4096 * ((1 << 10) << 10));
//
// const toks = try tkz.tokenizeContent(content);
// // for (toks.items) |tok| {
// // std.debug.print("{}:{} `{s}`\n", .{
// // tok.line,
// // tok.char,
// // tok.value,
// // });
// // }
//
// const ctoks = try cls.classifyTokens(toks);
// // for (ctoks.items) |ctok| {
// // std.debug.print("{}:{}\t`{s:<40}`({})\n", .{
// // ctok.tok.line,
// // ctok.tok.char,
// // ctok.tok.value,
// // ctok.cls,
// // });
// // }
// const ast = try stx.generateSyntaxTree(ctoks);
// std.debug.print("{}\n", .{ast});
//
_ = try lsp.start();
}

178
src/parser.zig Normal file
View File

@ -0,0 +1,178 @@
const std = @import("std");
const toks = @import("tokenizer.zig");
pub const ParseError = error{ no_fn_name, no_fn_params };
pub const Tag = enum {
///expression
///`<rhs...>`
///
///lhs ignored
expr,
///variable assignment
///`<lhs> = <rhs...>`
///
///lhs is overwritten to be variable
var_assign,
///lazy evaluated list
///`'(<rhs...>)`
///
///lhs ignored
llist,
///list (evaluated)
///`(<lhs> <rhs...>)`
///
///lhs needs to be a callable
list_eval,
///fn_def (procedure)
///`;;; <lhs>
///(procedure <main_token>(<lhs>) <rhs...>)`
fn_def,
};
pub const Node = struct {
tag: Tag,
main_token: Index,
data: Data,
pub const Data = struct {
lhs: Index,
rhs: Index,
};
pub const Index = u32;
};
pub const AstError = error{};
pub const Parser = struct {
gpa: std.mem.Allocator,
source: [:0]const u8,
token_tags: []const toks.Token.Tag,
token_locs: []const toks.Token.Loc,
tok_i: Node.Index,
errs: std.ArrayList(AstError),
nodes: std.MultiArrayList(Node),
extra_data: std.ArrayList(Node.Index),
scratch: std.ArrayList(Node.Index),
pub fn init(buffer: [:0]const u8, mal: std.MultiArrayList(toks.Token), allocator: std.mem.Allocator) !Parser {
return .{
.gpa = allocator,
.source = buffer,
.token_tags = mal.items(.tag),
.token_locs = mal.items(.loc),
.tok_i = 0,
.errs = std.ArrayList(AstError).init(allocator),
.nodes = std.MultiArrayList(Node){},
.extra_data = std.ArrayList(Node.Index).init(allocator),
.scratch = std.ArrayList(Node.Index).init(allocator),
};
}
fn hasToken(self: *Parser, expected: toks.Token.Tag, offset: isize) ?toks.Token {
if (self.token_tags[@intCast(self.tok_i + offset)] == expected) {
return .{ .loc = self.token_locs[@intCast(self.tok_i + offset)], .tag = self.token_tags[@intCast(self.tok_i + offset)] };
}
return null;
}
fn eatToken(self: *Parser, expected: toks.Token.Tag) ?Node.Index {
const tok = self.hasToken(expected, 0);
if (tok != null) {
self.tok_i += 1;
return self.tok_i - 1;
}
return null;
}
fn parse_fn_proc(self: *Parser) ?Node {
_ = self.eatToken(.sym);
if (self.hasToken(.list_l, -2) != null) {
// lisp style
} else if (self.eatToken(.list_l) != null) {
// c style
} else {
// not a procedure call or invalid syntax?
}
const name = self.eatToken(.sym) orelse return null;
std.debug.print("found procedure def for `{s}`", .{self.source[self.token_locs[name].start..self.token_locs[name].end]});
_ = self.eatToken(.list_l) orelse return null;
var open_lists: usize = 0;
while (true) : (self.tok_i += 1) {
switch (self.token_tags[self.tok_i]) {
.list_l, .list_lz => {
open_lists += 1;
},
.list_r => {
if (open_lists > 0) {
open_lists -= 1;
} else {
break;
}
},
else => {},
}
}
while (true) : (self.tok_i += 1) {
switch (self.token_tags[self.tok_i]) {
.list_l, .list_lz => {
open_lists += 1;
},
.list_r => {
if (open_lists > 0) {
open_lists -= 1;
} else {
break;
}
},
else => {},
}
}
self.tok_i += 1;
return Node{ .tag = .fn_def, .main_token = name, .data = .{ .lhs = 0, .rhs = 0 } };
}
pub fn next(self: *Parser) ?Node {
while (self.tok_i < self.token_tags.len) : (self.tok_i += 1) {
switch (self.token_tags[self.tok_i]) {
toks.Token.Tag.sym => {
if (std.mem.eql(u8, "procedure", self.source[self.token_locs[self.tok_i].start..self.token_locs[self.tok_i].end])) {
return self.parse_fn_proc();
}
},
else => {},
}
}
return null;
}
};
test "parsing of simple example" {
const example =
\\t
\\nil
\\a = b
\\"some string w/ escaped\""
\\(procedure a() )
;
var tokz = toks.Tokenizer.init(example);
var tokens = std.MultiArrayList(toks.Token){};
defer tokens.deinit(std.testing.allocator);
while (tokz.next()) |tok| {
try tokens.append(std.testing.allocator, tok);
std.debug.print("{}\n", .{tok});
}
var parse = try Parser.init(example, tokens, std.testing.allocator);
while (parse.next()) |ast_node| {
std.debug.print("{}\n", .{ast_node});
}
}

10
src/root.zig Normal file
View File

@ -0,0 +1,10 @@
const std = @import("std");
const testing = std.testing;
export fn add(a: i32, b: i32) i32 {
return a + b;
}
test "basic add functionality" {
try testing.expect(add(3, 7) == 10);
}

55
src/syntax.zig Normal file
View File

@ -0,0 +1,55 @@
const std = @import("std");
const cls = @import("classifier.zig");
pub const SyntaxNode = struct {
ctok: cls.ClassifiedToken,
nodes: ?std.ArrayList(SyntaxNode),
};
pub fn generateSyntaxTree(ctoks: std.ArrayList(cls.ClassifiedToken)) !std.ArrayList(SyntaxNode) {
var nodes = std.ArrayList(SyntaxNode).init(std.heap.page_allocator);
var actives = std.ArrayList(SyntaxNode).init(std.heap.page_allocator);
for (ctoks.items) |ctok| {
switch (ctok.cls) {
cls.TokenClass.comment, cls.TokenClass.docstring => {
try nodes.append(.{
.ctok = ctok,
.nodes = null,
});
},
cls.TokenClass.list_start, cls.TokenClass.list_lazy_start => {
try actives.append(.{
.ctok = ctok,
.nodes = std.ArrayList(SyntaxNode).init(std.heap.page_allocator),
});
},
cls.TokenClass.list_end => {
if (actives.items.len > 0) {
try nodes.append(actives.pop());
} else {
std.debug.print("{}\n", .{actives});
}
},
else => {
const active_top = actives.popOrNull();
if (active_top != null) {
var active = active_top.?;
var actives_nodes: std.ArrayList(SyntaxNode) = undefined;
if (active.nodes != null) {
actives_nodes = active.nodes.?;
} else {
active.nodes = std.ArrayList(SyntaxNode).init(std.heap.page_allocator);
actives_nodes = active.nodes.?;
}
try actives_nodes.append(.{
.ctok = ctok,
.nodes = null,
});
} else {}
},
}
}
return nodes;
}

99
src/tokenize.zig Normal file
View File

@ -0,0 +1,99 @@
const std = @import("std");
const lsp = @import("lsfw/src/lsp.zig");
pub const Token = struct {
/// 0-based index of token start in whole file
start: usize,
/// 1-based line numbert token starts at
line: usize,
/// 1-based char numbert token starts at in line
char: usize,
value: []const u8,
};
const TokenizationError = error{InvalidKeyword};
pub fn tokenizeContent(content: []u8, allocator: std.mem.Allocator) !std.ArrayList(Token) {
var toks = std.ArrayList(Token).init(allocator);
var lines = std.ArrayList(usize).init(allocator);
defer lines.deinit();
var index: usize = 0;
while (index < content.len) {
var l: usize = 1;
const char = content[index];
_ = switch (char) {
'\n' => {
try lines.append(index);
index += l;
continue;
},
';' => {
while (switch (content[index + l]) {
'\n' => false,
else => true,
}) : (l += 1) {}
},
'"' => {
while (switch (content[index + l]) {
'"' => (content[index + l - 1] == '\\'),
else => true,
}) : (l += 1) {}
l += 1;
},
'a'...'z', 'A'...'Z', '_' => {
while (switch (content[index + l]) {
'a'...'z', 'A'...'Z', '0'...'9', '_' => true,
else => false,
}) : (l += 1) {}
},
'0'...'9' => {
while (switch (content[index + l]) {
'0'...'9', '.', 'e' => true,
else => false,
}) : (l += 1) {}
},
'+', '-', '~', '*', '/', '%', '<', '>', '=', '?', '|', '&', '(', ')', '\'' => {
for ([_]*const [2]u8{ "->", "~>", "||", "&&", "/=", "*=", "+=", "-=", "'(" }) |op| {
if (std.mem.eql(u8, op, content[index .. index + 2])) {
l = 2;
break;
}
}
},
'@' => {
while (switch (content[index + l]) {
'a'...'z', 'A'...'Z', '_', '0'...'9' => true,
else => false,
}) : (l += 1) {}
if (std.mem.eql(u8, "@keys", content[index .. index + l])) {} else if (std.mem.eql(u8, "@rest", content[index .. index + l])) {} else {
std.debug.print("line={d}, char={d}\n", .{
.line = lines.items.len,
.char = switch (lines.items.len) {
0 => index,
else => index - lines.items[lines.items.len - 1],
},
});
}
},
else => {
index += l;
continue;
},
};
try toks.append(.{
.start = index,
.value = try allocator.dupe(u8, content[index .. index + l]),
.line = lines.items.len,
.char = switch (lines.items.len) {
0 => index,
else => index - lines.items[lines.items.len - 1],
},
});
index += l;
}
lsp.logger.notify(.err, "done with initial tokenization, generated {d} tokens", .{toks.items.len});
return toks;
}

272
src/tokenizer.zig Normal file
View File

@ -0,0 +1,272 @@
const std = @import("std");
pub const Token = struct {
tag: Tag,
loc: Loc,
pub const Loc = struct {
start: usize,
end: usize,
};
pub const Tag = enum {
sym,
num,
str,
/// t
t,
/// nil
nil,
/// =
assign,
/// -=
assign_sub,
/// /=
assign_div,
/// *=
assign_mul,
/// +=
assign_add,
/// ==
op_eq,
/// >
op_gt,
/// >=
op_geq,
/// <
op_lt,
/// <=
op_leq,
/// /
op_div,
/// *
op_mul,
/// +
op_add,
/// -
op_sub,
/// ->
op_acc,
/// ~>
op_derefacc,
/// %
op_mod,
/// !
op_not,
/// !=
op_neq,
/// ||
op_or,
/// &&
op_and,
/// (
list_l,
/// '(
list_lz,
/// )
list_r,
/// @keys
kw_keys,
/// @rest
kw_rest,
};
pub fn format(self: *const Token, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.print("{d}:{d} .{s}", .{ self.loc.start, self.loc.end, @tagName(self.tag) });
}
};
pub const Tokenizer = struct {
buffer: [:0]const u8,
index: usize,
start: usize,
const State = enum {
start,
alphanum_identifier,
number_or_float,
decimals,
signed_exponent,
unsigned_exponent,
string,
op_plus,
op_minus,
op_star,
op_fslash,
op_pipe,
op_amp,
op_excl,
op_deref,
op_eq,
list_l,
list_lz,
list_r,
};
pub fn init(buf: [:0]const u8) Tokenizer {
return .{
.buffer = buf,
.index = 0,
.start = 0,
};
}
pub fn next(self: *Tokenizer) ?Token {
var state: State = .start;
while (self.index < self.buffer.len) : (self.index += 1) {
const c = self.buffer[self.index];
const loc = Token.Loc{ .start = self.start, .end = self.index };
state = switch (state) {
.start => blk: {
self.start = self.index;
break :blk switch (c) {
'a'...'z', 'A'...'Z', '_' => .alphanum_identifier,
'0'...'9' => .number_or_float,
'.' => .decimals,
'"' => .string,
'+' => .op_plus,
'-' => .op_minus,
'*' => .op_star,
'/' => .op_fslash,
'|' => .op_pipe,
'&' => .op_amp,
'!' => .op_excl,
'~' => .op_deref,
'=' => .op_eq,
'(' => .list_l,
')' => .list_r,
'\'' => .list_lz,
else => .start,
};
},
.alphanum_identifier => switch (c) {
'a'...'z', 'A'...'Z', '0'...'9', '_' => .alphanum_identifier,
else => {
inline for (.{ Token.Tag.t, Token.Tag.nil }) |alphanum_tag| {
if (std.mem.eql(u8, self.buffer[self.start..self.index], @tagName(alphanum_tag))) {
return Token{ .tag = alphanum_tag, .loc = loc };
}
}
return Token{ .tag = .sym, .loc = loc };
},
},
.number_or_float => switch (c) {
'0'...'9' => .number_or_float,
'.' => .decimals,
'e' => .signed_exponent,
' ', '\n' => {
return Token{ .tag = .num, .loc = loc };
},
else => unreachable,
},
.decimals => switch (c) {
'0'...'9' => .decimals,
' ', '\n' => {
return Token{ .tag = .num, .loc = loc };
},
else => unreachable,
},
.signed_exponent => switch (c) {
'0'...'9', '+', '-' => .unsigned_exponent,
else => unreachable,
},
.unsigned_exponent => switch (c) {
'0'...'9' => .unsigned_exponent,
' ', '\n' => {
return Token{ .tag = .num, .loc = loc };
},
else => unreachable,
},
.string => switch (c) {
'"' => {
return Token{ .tag = .str, .loc = loc };
},
'\\' => blk: {
self.index += 1;
break :blk .string;
},
else => .string,
},
.op_plus, .op_minus, .op_fslash, .op_star, .op_excl, .op_eq => switch (c) {
'=' => {
return Token{ .tag = switch (state) {
.op_plus => .assign_add,
.op_minus => .assign_sub,
.op_star => .assign_mul,
.op_fslash => .assign_div,
.op_excl => .op_neq,
.op_eq => .op_eq,
else => unreachable,
}, .loc = loc };
},
' ', '\n' => {
return Token{ .tag = switch (state) {
.op_plus => .op_add,
.op_minus => .op_sub,
.op_star => .op_mul,
.op_fslash => .op_div,
.op_excl => .op_not,
.op_eq => .assign,
else => unreachable,
}, .loc = loc };
},
'>' => {
return Token{ .tag = switch (state) {
.op_minus => .op_acc,
else => unreachable,
}, .loc = loc };
},
else => unreachable,
},
.op_pipe => switch (c) {
'|' => {
return Token{ .tag = .op_or, .loc = loc };
},
else => unreachable,
},
.op_amp => switch (c) {
'&' => {
return Token{ .tag = .op_and, .loc = loc };
},
else => unreachable,
},
.op_deref => switch (c) {
'>' => {
return Token{ .tag = .op_derefacc, .loc = loc };
},
else => unreachable,
},
.list_l => {
return Token{ .tag = .list_l, .loc = loc };
},
.list_r => {
return Token{ .tag = .list_r, .loc = loc };
},
.list_lz => switch (c) {
'(' => {
return Token{ .tag = .op_derefacc, .loc = loc };
},
else => unreachable,
},
};
}
return null;
}
};
test "simple tokenization" {
const example =
\\t
\\nil
\\a = b
\\"some string w/ escaped\""
;
var tokz = Tokenizer.init(example);
try std.testing.expectEqual(Token{ .loc = .{ .start = 0, .end = 1 }, .tag = .t }, tokz.next());
try std.testing.expectEqual(Token{ .loc = .{ .start = 2, .end = 5 }, .tag = .nil }, tokz.next());
try std.testing.expectEqual(Token{ .loc = .{ .start = 6, .end = 7 }, .tag = .sym }, tokz.next());
try std.testing.expectEqual(Token{ .loc = .{ .start = 8, .end = 9 }, .tag = .assign }, tokz.next());
try std.testing.expectEqual(Token{ .loc = .{ .start = 10, .end = 11 }, .tag = .sym }, tokz.next());
try std.testing.expectEqual(Token{ .loc = .{ .start = 12, .end = 37 }, .tag = .str }, tokz.next());
}

40
todo.md
View File

@ -1,40 +0,0 @@
# TODOs
- [x] Paren pair parsing
- iterative parsing and matching of paren/bracket pairs
- [ ] tokenizer
- identify "tokens"
- everythin is a token with exception of:
- operators
- parens/brackets
- numbers
- t / nil
- comments (maybe already handled)
- [ ] namespaces / scopes
- namespaces are started with:
- let / letseq / let...
```skill
; let[T]( locals: list[tuple[symbol, Any] | symbol] | nil, *exprs: Any, last_expr: T) -> T
```
- prog
```skill
; prog( locals: list[symbol] | nil, *exprs: Any) -> Any
```
- procedure
```skill
; function_name(req_param: Any, key_param1: any = value_param2) => Any
procedure( function_name(req_param @keys (key_param1 value_param2))
...
)
function_name(<req_arg> ?key_param1 <value_param2>)
```
- [ ] token contextualization
- looks for declaration / definition of symbol

360
uv.lock
View File

@ -1,360 +0,0 @@
version = 1
revision = 2
requires-python = ">=3.13"
[[package]]
name = "attrs"
version = "24.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984, upload-time = "2024-12-16T06:59:29.899Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397, upload-time = "2024-12-16T06:59:26.977Z" },
]
[[package]]
name = "black"
version = "24.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "mypy-extensions" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "platformdirs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d8/0d/cc2fb42b8c50d80143221515dd7e4766995bd07c56c9a3ed30baf080b6dc/black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875", size = 645813, upload-time = "2024-10-07T19:20:50.361Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/a0/a993f58d4ecfba035e61fca4e9f64a2ecae838fc9f33ab798c62173ed75c/black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981", size = 1643986, upload-time = "2024-10-07T19:28:50.684Z" },
{ url = "https://files.pythonhosted.org/packages/37/d5/602d0ef5dfcace3fb4f79c436762f130abd9ee8d950fa2abdbf8bbc555e0/black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b", size = 1448085, upload-time = "2024-10-07T19:28:12.093Z" },
{ url = "https://files.pythonhosted.org/packages/47/6d/a3a239e938960df1a662b93d6230d4f3e9b4a22982d060fc38c42f45a56b/black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2", size = 1760928, upload-time = "2024-10-07T19:24:15.233Z" },
{ url = "https://files.pythonhosted.org/packages/dd/cf/af018e13b0eddfb434df4d9cd1b2b7892bab119f7a20123e93f6910982e8/black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b", size = 1436875, upload-time = "2024-10-07T19:24:42.762Z" },
{ url = "https://files.pythonhosted.org/packages/8d/a7/4b27c50537ebca8bec139b872861f9d2bf501c5ec51fcf897cb924d9e264/black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d", size = 206898, upload-time = "2024-10-07T19:20:48.317Z" },
]
[[package]]
name = "cattrs"
version = "24.1.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/64/65/af6d57da2cb32c076319b7489ae0958f746949d407109e3ccf4d115f147c/cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85", size = 426462, upload-time = "2024-09-22T14:58:36.377Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", size = 66446, upload-time = "2024-09-22T14:58:34.812Z" },
]
[[package]]
name = "click"
version = "8.1.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" },
]
[[package]]
name = "colorama"
version = "0.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
]
[[package]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" },
]
[[package]]
name = "lsprotocol"
version = "2025.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
{ name = "cattrs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e9/26/67b84e6ec1402f0e6764ef3d2a0aaf9a79522cc1d37738f4e5bb0b21521a/lsprotocol-2025.0.0.tar.gz", hash = "sha256:e879da2b9301e82cfc3e60d805630487ac2f7ab17492f4f5ba5aaba94fe56c29", size = 74896, upload-time = "2025-06-17T21:30:18.156Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7b/f0/92f2d609d6642b5f30cb50a885d2bf1483301c69d5786286500d15651ef2/lsprotocol-2025.0.0-py3-none-any.whl", hash = "sha256:f9d78f25221f2a60eaa4a96d3b4ffae011b107537facee61d3da3313880995c7", size = 76250, upload-time = "2025-06-17T21:30:19.455Z" },
]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" },
]
[[package]]
name = "mypy"
version = "1.14.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mypy-extensions" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051, upload-time = "2024-12-30T16:39:07.335Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097, upload-time = "2024-12-30T16:37:25.144Z" },
{ url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728, upload-time = "2024-12-30T16:38:08.634Z" },
{ url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965, upload-time = "2024-12-30T16:38:12.132Z" },
{ url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660, upload-time = "2024-12-30T16:38:17.342Z" },
{ url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198, upload-time = "2024-12-30T16:38:32.839Z" },
{ url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276, upload-time = "2024-12-30T16:38:20.828Z" },
{ url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905, upload-time = "2024-12-30T16:38:42.021Z" },
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433, upload-time = "2023-02-04T12:11:27.157Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695, upload-time = "2023-02-04T12:11:25.002Z" },
]
[[package]]
name = "packaging"
version = "24.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" },
]
[[package]]
name = "parsimonious"
version = "0.10.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "regex" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" },
]
[[package]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" },
]
[[package]]
name = "platformdirs"
version = "4.3.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302, upload-time = "2024-09-17T19:06:50.688Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" },
]
[[package]]
name = "pluggy"
version = "1.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" },
]
[[package]]
name = "pygls"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
{ name = "cattrs" },
{ name = "lsprotocol" },
]
sdist = { url = "https://files.pythonhosted.org/packages/87/50/2bfc32f3acbc8941042919b59c9f592291127b55d7331b72e67ce7b62f08/pygls-2.0.0.tar.gz", hash = "sha256:99accd03de1ca76fe1e7e317f0968ebccf7b9955afed6e2e3e188606a20b4f07", size = 55796, upload-time = "2025-10-17T19:22:47.925Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/09/14feafc13bebb9c85b29b374889c1549d3700cb572f2d43a1bb940d70315/pygls-2.0.0-py3-none-any.whl", hash = "sha256:b4e54bba806f76781017ded8fd07463b98670f959042c44170cd362088b200cc", size = 69533, upload-time = "2025-10-17T19:22:46.63Z" },
]
[[package]]
name = "pygments"
version = "2.19.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" },
]
[[package]]
name = "pytest"
version = "8.3.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" },
{ name = "iniconfig" },
{ name = "packaging" },
{ name = "pluggy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919, upload-time = "2024-12-01T12:54:25.98Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083, upload-time = "2024-12-01T12:54:19.735Z" },
]
[[package]]
name = "regex"
version = "2024.11.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" },
{ url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" },
{ url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" },
{ url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" },
{ url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" },
{ url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" },
{ url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" },
{ url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" },
{ url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" },
{ url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" },
{ url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" },
{ url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" },
{ url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" },
{ url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" },
{ url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" },
]
[[package]]
name = "rich"
version = "13.9.4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
{ name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149, upload-time = "2024-11-01T16:43:57.873Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424, upload-time = "2024-11-01T16:43:55.817Z" },
]
[[package]]
name = "ruff"
version = "0.9.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/80/63/77ecca9d21177600f551d1c58ab0e5a0b260940ea7312195bd2a4798f8a8/ruff-0.9.2.tar.gz", hash = "sha256:b5eceb334d55fae5f316f783437392642ae18e16dcf4f1858d55d3c2a0f8f5d0", size = 3553799, upload-time = "2025-01-16T13:22:20.512Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/af/b9/0e168e4e7fb3af851f739e8f07889b91d1a33a30fca8c29fa3149d6b03ec/ruff-0.9.2-py3-none-linux_armv6l.whl", hash = "sha256:80605a039ba1454d002b32139e4970becf84b5fee3a3c3bf1c2af6f61a784347", size = 11652408, upload-time = "2025-01-16T13:21:12.732Z" },
{ url = "https://files.pythonhosted.org/packages/2c/22/08ede5db17cf701372a461d1cb8fdde037da1d4fa622b69ac21960e6237e/ruff-0.9.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9aab82bb20afd5f596527045c01e6ae25a718ff1784cb92947bff1f83068b00", size = 11587553, upload-time = "2025-01-16T13:21:17.716Z" },
{ url = "https://files.pythonhosted.org/packages/42/05/dedfc70f0bf010230229e33dec6e7b2235b2a1b8cbb2a991c710743e343f/ruff-0.9.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbd337bac1cfa96be615f6efcd4bc4d077edbc127ef30e2b8ba2a27e18c054d4", size = 11020755, upload-time = "2025-01-16T13:21:21.746Z" },
{ url = "https://files.pythonhosted.org/packages/df/9b/65d87ad9b2e3def67342830bd1af98803af731243da1255537ddb8f22209/ruff-0.9.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b35259b0cbf8daa22a498018e300b9bb0174c2bbb7bcba593935158a78054d", size = 11826502, upload-time = "2025-01-16T13:21:26.135Z" },
{ url = "https://files.pythonhosted.org/packages/93/02/f2239f56786479e1a89c3da9bc9391120057fc6f4a8266a5b091314e72ce/ruff-0.9.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6a9701d1e371bf41dca22015c3f89769da7576884d2add7317ec1ec8cb9c3c", size = 11390562, upload-time = "2025-01-16T13:21:29.026Z" },
{ url = "https://files.pythonhosted.org/packages/c9/37/d3a854dba9931f8cb1b2a19509bfe59e00875f48ade632e95aefcb7a0aee/ruff-0.9.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc53e68b3c5ae41e8faf83a3b89f4a5d7b2cb666dff4b366bb86ed2a85b481f", size = 12548968, upload-time = "2025-01-16T13:21:34.147Z" },
{ url = "https://files.pythonhosted.org/packages/fa/c3/c7b812bb256c7a1d5553433e95980934ffa85396d332401f6b391d3c4569/ruff-0.9.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8efd9da7a1ee314b910da155ca7e8953094a7c10d0c0a39bfde3fcfd2a015684", size = 13187155, upload-time = "2025-01-16T13:21:40.494Z" },
{ url = "https://files.pythonhosted.org/packages/bd/5a/3c7f9696a7875522b66aa9bba9e326e4e5894b4366bd1dc32aa6791cb1ff/ruff-0.9.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3292c5a22ea9a5f9a185e2d131dc7f98f8534a32fb6d2ee7b9944569239c648d", size = 12704674, upload-time = "2025-01-16T13:21:45.041Z" },
{ url = "https://files.pythonhosted.org/packages/be/d6/d908762257a96ce5912187ae9ae86792e677ca4f3dc973b71e7508ff6282/ruff-0.9.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a605fdcf6e8b2d39f9436d343d1f0ff70c365a1e681546de0104bef81ce88df", size = 14529328, upload-time = "2025-01-16T13:21:49.45Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c2/049f1e6755d12d9cd8823242fa105968f34ee4c669d04cac8cea51a50407/ruff-0.9.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c547f7f256aa366834829a08375c297fa63386cbe5f1459efaf174086b564247", size = 12385955, upload-time = "2025-01-16T13:21:52.71Z" },
{ url = "https://files.pythonhosted.org/packages/91/5a/a9bdb50e39810bd9627074e42743b00e6dc4009d42ae9f9351bc3dbc28e7/ruff-0.9.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d18bba3d3353ed916e882521bc3e0af403949dbada344c20c16ea78f47af965e", size = 11810149, upload-time = "2025-01-16T13:21:57.098Z" },
{ url = "https://files.pythonhosted.org/packages/e5/fd/57df1a0543182f79a1236e82a79c68ce210efb00e97c30657d5bdb12b478/ruff-0.9.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b338edc4610142355ccf6b87bd356729b62bf1bc152a2fad5b0c7dc04af77bfe", size = 11479141, upload-time = "2025-01-16T13:22:00.585Z" },
{ url = "https://files.pythonhosted.org/packages/dc/16/bc3fd1d38974f6775fc152a0554f8c210ff80f2764b43777163c3c45d61b/ruff-0.9.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:492a5e44ad9b22a0ea98cf72e40305cbdaf27fac0d927f8bc9e1df316dcc96eb", size = 12014073, upload-time = "2025-01-16T13:22:03.956Z" },
{ url = "https://files.pythonhosted.org/packages/47/6b/e4ca048a8f2047eb652e1e8c755f384d1b7944f69ed69066a37acd4118b0/ruff-0.9.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:af1e9e9fe7b1f767264d26b1075ac4ad831c7db976911fa362d09b2d0356426a", size = 12435758, upload-time = "2025-01-16T13:22:07.73Z" },
{ url = "https://files.pythonhosted.org/packages/c2/40/4d3d6c979c67ba24cf183d29f706051a53c36d78358036a9cd21421582ab/ruff-0.9.2-py3-none-win32.whl", hash = "sha256:71cbe22e178c5da20e1514e1e01029c73dc09288a8028a5d3446e6bba87a5145", size = 9796916, upload-time = "2025-01-16T13:22:10.894Z" },
{ url = "https://files.pythonhosted.org/packages/c3/ef/7f548752bdb6867e6939489c87fe4da489ab36191525fadc5cede2a6e8e2/ruff-0.9.2-py3-none-win_amd64.whl", hash = "sha256:c5e1d6abc798419cf46eed03f54f2e0c3adb1ad4b801119dedf23fcaf69b55b5", size = 10773080, upload-time = "2025-01-16T13:22:14.155Z" },
{ url = "https://files.pythonhosted.org/packages/0e/4e/33df635528292bd2d18404e4daabcd74ca8a9853b2e1df85ed3d32d24362/ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6", size = 10001738, upload-time = "2025-01-16T13:22:18.121Z" },
]
[[package]]
name = "skillls"
version = "0.1.0"
source = { editable = "." }
dependencies = [
{ name = "parsimonious" },
{ name = "pygls" },
{ name = "rich" },
{ name = "tree-sitter" },
{ name = "tree-sitter-skill" },
]
[package.optional-dependencies]
dev = [
{ name = "black" },
{ name = "mypy" },
{ name = "pytest" },
{ name = "ruff" },
{ name = "types-parsimonious" },
]
[package.metadata]
requires-dist = [
{ name = "black", marker = "extra == 'dev'" },
{ name = "mypy", marker = "extra == 'dev'" },
{ name = "parsimonious", specifier = "~=0.10.0" },
{ name = "pygls", specifier = "~=2.0" },
{ name = "pytest", marker = "extra == 'dev'" },
{ name = "rich" },
{ name = "ruff", marker = "extra == 'dev'" },
{ name = "tree-sitter", specifier = ">=0.24.0" },
{ name = "tree-sitter-skill", git = "ssh://git@git.acereca.net/acereca/tree-sitter-skill.git" },
{ name = "types-parsimonious", marker = "extra == 'dev'" },
]
provides-extras = ["dev"]
[[package]]
name = "tree-sitter"
version = "0.24.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a7/a2/698b9d31d08ad5558f8bfbfe3a0781bd4b1f284e89bde3ad18e05101a892/tree-sitter-0.24.0.tar.gz", hash = "sha256:abd95af65ca2f4f7eca356343391ed669e764f37748b5352946f00f7fc78e734", size = 168304, upload-time = "2025-01-17T05:06:38.115Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/61/cd/2348339c85803330ce38cee1c6cbbfa78a656b34ff58606ebaf5c9e83bd0/tree_sitter-0.24.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0d4a6416ed421c4210f0ca405a4834d5ccfbb8ad6692d4d74f7773ef68f92071", size = 140781, upload-time = "2025-01-17T05:06:22.82Z" },
{ url = "https://files.pythonhosted.org/packages/8b/a3/1ea9d8b64e8dcfcc0051028a9c84a630301290995cd6e947bf88267ef7b1/tree_sitter-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0992d483677e71d5c5d37f30dfb2e3afec2f932a9c53eec4fca13869b788c6c", size = 133928, upload-time = "2025-01-17T05:06:25.146Z" },
{ url = "https://files.pythonhosted.org/packages/fe/ae/55c1055609c9428a4aedf4b164400ab9adb0b1bf1538b51f4b3748a6c983/tree_sitter-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57277a12fbcefb1c8b206186068d456c600dbfbc3fd6c76968ee22614c5cd5ad", size = 564497, upload-time = "2025-01-17T05:06:27.53Z" },
{ url = "https://files.pythonhosted.org/packages/ce/d0/f2ffcd04882c5aa28d205a787353130cbf84b2b8a977fd211bdc3b399ae3/tree_sitter-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25fa22766d63f73716c6fec1a31ee5cf904aa429484256bd5fdf5259051ed74", size = 578917, upload-time = "2025-01-17T05:06:31.057Z" },
{ url = "https://files.pythonhosted.org/packages/af/82/aebe78ea23a2b3a79324993d4915f3093ad1af43d7c2208ee90be9273273/tree_sitter-0.24.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7d5d9537507e1c8c5fa9935b34f320bfec4114d675e028f3ad94f11cf9db37b9", size = 581148, upload-time = "2025-01-17T05:06:32.409Z" },
{ url = "https://files.pythonhosted.org/packages/a1/b4/6b0291a590c2b0417cfdb64ccb8ea242f270a46ed429c641fbc2bfab77e0/tree_sitter-0.24.0-cp313-cp313-win_amd64.whl", hash = "sha256:f58bb4956917715ec4d5a28681829a8dad5c342cafd4aea269f9132a83ca9b34", size = 120207, upload-time = "2025-01-17T05:06:34.841Z" },
{ url = "https://files.pythonhosted.org/packages/a8/18/542fd844b75272630229c9939b03f7db232c71a9d82aadc59c596319ea6a/tree_sitter-0.24.0-cp313-cp313-win_arm64.whl", hash = "sha256:23641bd25dcd4bb0b6fa91b8fb3f46cc9f1c9f475efe4d536d3f1f688d1b84c8", size = 108232, upload-time = "2025-01-17T05:06:35.831Z" },
]
[[package]]
name = "tree-sitter-skill"
version = "0.1.1"
source = { git = "ssh://git@git.acereca.net/acereca/tree-sitter-skill.git#ce8634713b13f1787837fd9a7c515383ecedac07" }
dependencies = [
{ name = "tree-sitter" },
]
[[package]]
name = "types-parsimonious"
version = "0.10.0.20240331"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/11/8a/3e0f5d72ea35bc5fba64899fca45124a4398c78e28c40a3e119f15882d35/types-parsimonious-0.10.0.20240331.tar.gz", hash = "sha256:c9ca50c968b83203a285ee8fbe4a50c5aa6d8ca903d92802ee5398cb95608ceb", size = 5482, upload-time = "2024-03-31T02:17:49.591Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b5/fe/f6f9b4ec9c4cd0c567bcd581d65795bb07b0613fe3d15b249af348efa42a/types_parsimonious-0.10.0.20240331-py3-none-any.whl", hash = "sha256:6828faa2b74c03d229d2ea5b661a9de47589a837fec48424804c42b9113a28cd", size = 6308, upload-time = "2024-03-31T02:17:48.098Z" },
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" },
]