Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Commit

Permalink
main merge
Browse files Browse the repository at this point in the history
  • Loading branch information
AshishMahendra committed Aug 28, 2024
2 parents 2011c25 + 39cc924 commit ba31cee
Show file tree
Hide file tree
Showing 20 changed files with 476 additions and 361 deletions.
8 changes: 4 additions & 4 deletions jaclang/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from jaclang.plugin.builtin import dotgen
from jaclang.plugin.feature import JacCmd as Cmd
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.runtimelib.constructs import Architype
from jaclang.runtimelib.constructs import Anchor, Architype
from jaclang.runtimelib.machine import JacProgram
from jaclang.utils.helpers import debugger as db
from jaclang.utils.lang_tools import AstTool
Expand Down Expand Up @@ -124,8 +124,8 @@ def run(
if not node or node == "root":
entrypoint: Architype = Jac.get_root()
else:
obj = Jac.context().get_obj(UUID(node))
if obj is None or obj.architype is None:
obj = Jac.context().mem.find_by_id(UUID(node))
if not isinstance(obj, Anchor) or obj.architype is None:
print(f"Entrypoint {node} not found.")
return
entrypoint = obj.architype
Expand Down Expand Up @@ -154,7 +154,7 @@ def get_object(id: str, session: str = "") -> dict:
else:
id_uuid = UUID(id)

obj = Jac.context().get_obj(id_uuid)
obj = Jac.context().mem.find_by_id(id_uuid)
if obj is None:
print(f"Object with id {id} not found.")
Jac.reset_context()
Expand Down
31 changes: 31 additions & 0 deletions jaclang/langserve/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,37 @@ def get_references(
return list_of_references
return []

def rename_symbol(
self, file_path: str, position: lspt.Position, new_name: str
) -> Optional[lspt.WorkspaceEdit]:
"""Rename a symbol in a file."""
if file_path not in self.modules:
return None
index1 = find_index(
self.modules[file_path].sem_manager.sem_tokens,
position.line,
position.character,
)
if index1 is None:
return None
node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
if node_selected and node_selected.sym:
changes: dict[str, list[lspt.TextEdit]] = {}
for node in [*node_selected.sym.uses, node_selected.sym.defn[0]]:
key = uris.from_fs_path(node.loc.mod_path)
value = [
lspt.TextEdit(
range=create_range(node.loc),
new_text=new_name,
)
]
if key in changes:
changes[key].extend(value)
else:
changes[key] = value
return lspt.WorkspaceEdit(changes=changes)
return None

def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
"""Return semantic tokens for a file."""
if file_path not in self.modules:
Expand Down
17 changes: 16 additions & 1 deletion jaclang/langserve/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@


@server.feature(lspt.TEXT_DOCUMENT_DID_OPEN)
@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
"""Check syntax on change."""
ls.deep_check(params.text_document.uri)
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)


@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
async def did_save(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
"""Check syntax on change."""
await ls.launch_deep_check(params.text_document.uri)
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
Expand Down Expand Up @@ -132,6 +138,15 @@ def references(ls: JacLangServer, params: lspt.ReferenceParams) -> list[lspt.Loc
return ls.get_references(params.text_document.uri, params.position)


@server.feature(lspt.TEXT_DOCUMENT_RENAME)
def rename(
ls: JacLangServer, params: lspt.RenameParams
) -> Optional[lspt.WorkspaceEdit]:
"""Rename symbol."""
ls.log_warning("Auto Rename is Experimental, Please use with caution.")
return ls.rename_symbol(params.text_document.uri, params.position, params.new_name)


@server.feature(
lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
lspt.SemanticTokensLegend(
Expand Down
104 changes: 104 additions & 0 deletions jaclang/langserve/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,107 @@ def test_go_to_reference(self) -> None:
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
for expected in expected_refs:
self.assertIn(expected, references)

def test_py_type__definition(self) -> None:
"""Test that the go to definition is correct for pythoon imports."""
lsp = JacLangServer()
workspace_path = self.fixture_abs_path("")
workspace = Workspace(workspace_path, lsp)
lsp.lsp._workspace = workspace
import_file = uris.from_fs_path(
self.fixture_abs_path(
"../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
)
)
lsp.deep_check(import_file)
positions = [
(13, 29, "pygame_mock/color.py:0:0-2:4"),
(3, 17, "/pygame_mock/__init__.py:0:0-0:0"),
(14, 45, "pygame_mock/color.py:0:0-2:4"),
(13, 77, "mock/constants.py:4:3-4:15"),
(17, 28, "mock/display.py:0:0-1:7"),
(15, 22, "/argparse.pyi:124:0-249:13"),
(13, 74, "pygame_mock/constants.py:4:3-4:15"),
(18, 17, "/stdlib/os/__init__.pyi:50:0-50:3"),
]

for line, char, expected in positions:
with self.subTest(line=line, char=char):
self.assertIn(
expected,
str(lsp.get_definition(import_file, lspt.Position(line, char))),
)

def test_py_type__references(self) -> None:
"""Test that the go to definition is correct for pythoon imports."""
lsp = JacLangServer()
workspace_path = self.fixture_abs_path("")
workspace = Workspace(workspace_path, lsp)
lsp.lsp._workspace = workspace

circle_file = uris.from_fs_path(
self.fixture_abs_path(
"../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
)
)
lsp.deep_check(circle_file)
test_cases = [
(
12,
15,
[
":12:13-12:18",
"12:27-12:32",
"13:26-13:31",
"13:40-13:45",
"14:26-14:31",
"14:40-14:45",
],
),
(13, 63, ["6:33-6:42", "7:23-7:32", "12:45-12:54", "13:58-13:67"]),
(
15,
53,
[
"15:42-15:56",
"15:16-15:30",
"argparse.pyi:334:21-334:35",
"argparse.pyi:163:29-163:43",
"argparse.pyi:32:52-32:66",
],
),
]
for line, char, expected_refs in test_cases:
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
for expected in expected_refs:
self.assertIn(expected, references)

def test_rename_symbol(self) -> None:
"""Test that the rename is correct."""
lsp = JacLangServer()
workspace_path = self.fixture_abs_path("")
workspace = Workspace(workspace_path, lsp)
lsp.lsp._workspace = workspace

circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
lsp.deep_check(circle_file)
test_cases = [
(
20,
14,
"ShapeKind",
"27:20-27:29,",
"36:19-36:28",
"75:26-75:35",
"20:5-20:14",
),
(12, 34, "circleRadius", "12:21-12:27", "12:30-12:36", "11:19-11:25"),
(62, 14, "target_area", "65:43-65:56", "70:32-70:45", "62:5-62:18"),
]
for tup in test_cases:
line, char, new_name, *expected_refs = tup
references = str(
lsp.rename_symbol(circle_file, lspt.Position(line, char), new_name)
)
for expected in expected_refs:
self.assertIn(expected, references)
35 changes: 15 additions & 20 deletions jaclang/plugin/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def edge_ref(
def connect(
left: NodeArchitype | list[NodeArchitype],
right: NodeArchitype | list[NodeArchitype],
edge_spec: Callable[[], EdgeArchitype],
edge_spec: Callable[[NodeAnchor, NodeAnchor], EdgeArchitype],
edges_only: bool,
) -> list[NodeArchitype] | list[EdgeArchitype]:
"""Jac's connect operator feature.
Expand All @@ -475,13 +475,7 @@ def connect(
edges = []
for i in left:
for j in right:
conn_edge = edge_spec()
edges.append(conn_edge)
i.__jac__.connect_node(j.__jac__, conn_edge.__jac__)
if i.__jac__.persistent or j.__jac__.persistent:
conn_edge.__jac__.save()
j.__jac__.save()
i.__jac__.save()
edges.append(edge_spec(i.__jac__, j.__jac__))
return right if not edges_only else edges

@staticmethod
Expand All @@ -500,26 +494,23 @@ def disconnect(
node = i.__jac__
for anchor in set(node.edges):
if (
(architype := anchor.architype)
and (source := anchor.source)
(source := anchor.source)
and (target := anchor.target)
and (not filter_func or filter_func([architype]))
and (src_arch := source.architype)
and (trg_arch := target.architype)
and (not filter_func or filter_func([anchor.architype]))
):
if (
dir in [EdgeDir.OUT, EdgeDir.ANY]
and node == source
and trg_arch in right
and target.architype in right
):
anchor.detach()
anchor.destroy()
disconnect_occurred = True
if (
dir in [EdgeDir.IN, EdgeDir.ANY]
and node == target
and src_arch in right
and source.architype in right
):
anchor.detach()
anchor.destroy()
disconnect_occurred = True

return disconnect_occurred
Expand Down Expand Up @@ -554,19 +545,23 @@ def build_edge(
is_undirected: bool,
conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
conn_assign: Optional[tuple[tuple, tuple]],
) -> Callable[[], EdgeArchitype]:
) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]:
"""Jac's root getter."""
conn_type = conn_type if conn_type else GenericEdge

def builder() -> EdgeArchitype:
def builder(source: NodeAnchor, target: NodeAnchor) -> EdgeArchitype:
edge = conn_type() if isinstance(conn_type, type) else conn_type
edge.__jac__.is_undirected = is_undirected
edge.__attach__(source, target, is_undirected)
if conn_assign:
for fld, val in zip(conn_assign[0], conn_assign[1]):
if hasattr(edge, fld):
setattr(edge, fld, val)
else:
raise ValueError(f"Invalid attribute: {fld}")
if source.persistent or target.persistent:
edge.__jac__.save()
target.save()
source.save()
return edge

return builder
Expand Down
5 changes: 3 additions & 2 deletions jaclang/plugin/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Architype,
EdgeArchitype,
Memory,
NodeAnchor,
NodeArchitype,
Root,
WalkerArchitype,
Expand Down Expand Up @@ -226,7 +227,7 @@ def edge_ref(
def connect(
left: NodeArchitype | list[NodeArchitype],
right: NodeArchitype | list[NodeArchitype],
edge_spec: Callable[[], EdgeArchitype],
edge_spec: Callable[[NodeAnchor, NodeAnchor], EdgeArchitype],
edges_only: bool = False,
) -> list[NodeArchitype] | list[EdgeArchitype]:
"""Jac's connect operator feature.
Expand Down Expand Up @@ -274,7 +275,7 @@ def build_edge(
is_undirected: bool,
conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
conn_assign: Optional[tuple[tuple, tuple]],
) -> Callable[[], EdgeArchitype]:
) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]:
"""Jac's root getter."""
return pm.hook.build_edge(
is_undirected=is_undirected, conn_type=conn_type, conn_assign=conn_assign
Expand Down
6 changes: 3 additions & 3 deletions jaclang/plugin/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass

if TYPE_CHECKING:
from jaclang.runtimelib.constructs import EdgeArchitype, NodeArchitype
from jaclang.runtimelib.constructs import EdgeArchitype, NodeAnchor, NodeArchitype
from jaclang.plugin.default import (
Architype,
EdgeDir,
Expand Down Expand Up @@ -224,7 +224,7 @@ def edge_ref(
def connect(
left: NodeArchitype | list[NodeArchitype],
right: NodeArchitype | list[NodeArchitype],
edge_spec: Callable[[], EdgeArchitype],
edge_spec: Callable[[NodeAnchor, NodeAnchor], EdgeArchitype],
edges_only: bool,
) -> list[NodeArchitype] | list[EdgeArchitype]:
"""Jac's connect operator feature.
Expand Down Expand Up @@ -270,7 +270,7 @@ def build_edge(
is_undirected: bool,
conn_type: Optional[Type[EdgeArchitype] | EdgeArchitype],
conn_assign: Optional[tuple[tuple, tuple]],
) -> Callable[[], EdgeArchitype]:
) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]:
"""Jac's root getter."""
raise NotImplementedError

Expand Down
12 changes: 5 additions & 7 deletions jaclang/plugin/tests/test_jaseci.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ def test_entrypoint_non_root(self) -> None:
walker="create",
)
obj = cli.get_object(session=session, id="root")
edge_obj = cli.get_object(session=session, id=str(obj["edge_ids"][0]))
a_obj = cli.get_object(session=session, id=str(edge_obj["target_id"]))
edge_obj = cli.get_object(session=session, id=obj["edges"][0].id.hex)
a_obj = cli.get_object(session=session, id=str(edge_obj["target"].id.hex))
self._output2buffer()
cli.run(
filename=self.fixture_abs_path("simple_persistent.jac"),
Expand All @@ -104,11 +104,9 @@ def test_get_edge(self) -> None:
session=session,
)
obj = cli.get_object(session=session, id="root")
self.assertEqual(len(obj["edge_ids"]), 2)
edge_objs = [
cli.get_object(session=session, id=str(e_id)) for e_id in obj["edge_ids"]
]
node_ids = [obj["target_id"] for obj in edge_objs]
self.assertEqual(len(obj["edges"]), 2)
edge_objs = [cli.get_object(session=session, id=e.id.hex) for e in obj["edges"]]
node_ids = [obj["target"].id.hex for obj in edge_objs]
node_objs = [cli.get_object(session=session, id=str(n_id)) for n_id in node_ids]
self.assertEqual(len(node_objs), 2)
self.assertEqual(
Expand Down
Loading

0 comments on commit ba31cee

Please sign in to comment.