jaclang 0.8.7__py3-none-any.whl → 0.8.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/cli/cli.py +13 -27
- jaclang/cli/cmdreg.py +44 -0
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +3 -6
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +213 -34
- jaclang/compiler/passes/main/__init__.py +2 -4
- jaclang/compiler/passes/main/def_use_pass.py +0 -4
- jaclang/compiler/passes/main/predynamo_pass.py +221 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +70 -52
- jaclang/compiler/passes/main/pyast_load_pass.py +52 -20
- jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
- jaclang/compiler/passes/main/tests/test_checker_pass.py +191 -0
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
- jaclang/compiler/passes/main/type_checker_pass.py +29 -73
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
- jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
- jaclang/compiler/passes/transform.py +12 -8
- jaclang/compiler/program.py +14 -6
- jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
- jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
- jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
- jaclang/compiler/tests/fixtures/python_module.py +1 -0
- jaclang/compiler/tests/test_importer.py +39 -0
- jaclang/compiler/tests/test_parser.py +49 -0
- jaclang/compiler/type_system/type_evaluator.py +351 -67
- jaclang/compiler/type_system/type_utils.py +246 -0
- jaclang/compiler/type_system/types.py +58 -2
- jaclang/compiler/unitree.py +79 -94
- jaclang/langserve/engine.jac +138 -159
- jaclang/langserve/server.jac +25 -1
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
- jaclang/langserve/tests/server_test/circle_template.jac +80 -0
- jaclang/langserve/tests/server_test/glob_template.jac +4 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
- jaclang/langserve/tests/server_test/utils.py +153 -116
- jaclang/langserve/tests/test_server.py +21 -84
- jaclang/langserve/utils.jac +12 -15
- jaclang/runtimelib/machine.py +7 -0
- jaclang/runtimelib/meta_importer.py +27 -1
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
- jaclang/settings.py +18 -14
- jaclang/tests/fixtures/abc_check.jac +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
- jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
- jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
- jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
- jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
- jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
- jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
- jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
- jaclang/tests/fixtures/py2jac_params.py +8 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/test_cli.py +37 -1
- jaclang/tests/test_language.py +74 -16
- jaclang/utils/helpers.py +47 -2
- jaclang/utils/module_resolver.py +10 -0
- jaclang/utils/test.py +8 -0
- jaclang/utils/treeprinter.py +0 -18
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/METADATA +1 -2
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/RECORD +85 -60
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/inheritance_pass.py +0 -131
- jaclang/langserve/dev_engine.jac +0 -645
- jaclang/langserve/dev_server.jac +0 -201
- jaclang/langserve/tests/server_test/code_test.py +0 -0
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
|
@@ -2,21 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import tempfile
|
|
5
|
-
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from lsprotocol.types import (
|
|
9
|
+
DidOpenTextDocumentParams,
|
|
10
|
+
TextDocumentItem,
|
|
11
|
+
DidSaveTextDocumentParams,
|
|
12
|
+
DidChangeTextDocumentParams,
|
|
13
|
+
VersionedTextDocumentIdentifier,
|
|
14
|
+
)
|
|
6
15
|
from jaclang.vendor.pygls.uris import from_fs_path
|
|
7
16
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
8
17
|
|
|
9
|
-
from textwrap import dedent
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def get_jac_file_path():
|
|
13
|
-
"""Return the absolute path to the sample Jac file used for testing."""
|
|
14
|
-
return os.path.abspath(
|
|
15
|
-
os.path.join(
|
|
16
|
-
os.path.dirname(__file__), "../../../../examples/manual_code/circle.jac"
|
|
17
|
-
)
|
|
18
|
-
)
|
|
19
|
-
|
|
20
18
|
|
|
21
19
|
def create_temp_jac_file(initial_content: str = "") -> str:
|
|
22
20
|
"""Create a temporary Jac file with optional initial content and return its path."""
|
|
@@ -28,110 +26,11 @@ def create_temp_jac_file(initial_content: str = "") -> str:
|
|
|
28
26
|
return temp.name
|
|
29
27
|
|
|
30
28
|
|
|
31
|
-
def
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
f
|
|
35
|
-
""
|
|
36
|
-
This module demonstrates a simple circle class and a function to calculate
|
|
37
|
-
the area of a circle in all of Jac's glory.
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
import math;
|
|
41
|
-
|
|
42
|
-
# Module-level global variable
|
|
43
|
-
glob RAD = 5;
|
|
44
|
-
|
|
45
|
-
"""Function to calculate the area of a circle."""
|
|
46
|
-
def calculate_area(radius: float) -> float {{
|
|
47
|
-
return math.pi * radius * radius;
|
|
48
|
-
}}
|
|
49
|
-
|
|
50
|
-
#* (This is a multiline comment in Jac)
|
|
51
|
-
Above we have the demonstration of a function to calculate the area of a circle.
|
|
52
|
-
Below we have the demonstration of a class to calculate the area of a circle.
|
|
53
|
-
*#
|
|
54
|
-
|
|
55
|
-
"""Enum for shape types"""
|
|
56
|
-
enum ShapeType {{
|
|
57
|
-
CIRCLE = "Circle",
|
|
58
|
-
UNKNOWN = "Unknown"
|
|
59
|
-
}}
|
|
60
|
-
|
|
61
|
-
"""Base class for a shape."""
|
|
62
|
-
obj Shape {{
|
|
63
|
-
has shape_type: ShapeType;
|
|
64
|
-
|
|
65
|
-
"""Abstract method to calculate the area of a shape."""
|
|
66
|
-
def area -> float abs;
|
|
67
|
-
}}
|
|
68
|
-
|
|
69
|
-
"""Circle class inherits from Shape."""
|
|
70
|
-
obj Circle(Shape) {{
|
|
71
|
-
def init(radius: float) {{
|
|
72
|
-
super.init(ShapeType.CIRCLE);
|
|
73
|
-
self.radius = radius;
|
|
74
|
-
}}
|
|
75
|
-
|
|
76
|
-
"""Overridden method to calculate the area of the circle."""
|
|
77
|
-
override def area -> float {{
|
|
78
|
-
return math.pi * self.radius * self.radius;
|
|
79
|
-
}}
|
|
80
|
-
}}
|
|
81
|
-
|
|
82
|
-
with entry {{
|
|
83
|
-
c = Circle(RAD);
|
|
84
|
-
}}
|
|
85
|
-
|
|
86
|
-
# Global also works here
|
|
87
|
-
|
|
88
|
-
with entry:__main__ {{
|
|
89
|
-
# To run the program functionality
|
|
90
|
-
print(
|
|
91
|
-
f"Area of a circle with radius {{RAD}} using function: {{calculate_area(RAD)}}"
|
|
92
|
-
);
|
|
93
|
-
print(
|
|
94
|
-
f"Area of a {{c.shape_type.value}} with radius {{RAD}} using class: {{c.area()}}"
|
|
95
|
-
);
|
|
96
|
-
}}
|
|
97
|
-
|
|
98
|
-
# Unit Tests!
|
|
99
|
-
glob expected_area = 78.53981633974483;
|
|
100
|
-
{code}
|
|
101
|
-
|
|
102
|
-
test calc_area {{
|
|
103
|
-
check almostEqual(calculate_area(RAD), expected_area);
|
|
104
|
-
}}
|
|
105
|
-
|
|
106
|
-
test circle_area {{
|
|
107
|
-
c = Circle(RAD);
|
|
108
|
-
check almostEqual(c.area(), expected_area);
|
|
109
|
-
}}
|
|
110
|
-
|
|
111
|
-
test circle_type {{
|
|
112
|
-
c = Circle(RAD);
|
|
113
|
-
check c.shape_type == ShapeType.CIRCLE;
|
|
114
|
-
}}
|
|
115
|
-
'''
|
|
116
|
-
)
|
|
117
|
-
return jac_code
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def get_simple_code(code: str) -> str:
|
|
121
|
-
"""Generate a sample Jac code snippet with optional test code injected."""
|
|
122
|
-
jac_code = dedent(
|
|
123
|
-
f"""
|
|
124
|
-
|
|
125
|
-
# Unit Tests!
|
|
126
|
-
glob expected_area0 = 78.53981633974483;
|
|
127
|
-
glob expected_area1 = 78.53981633974483;
|
|
128
|
-
{code}
|
|
129
|
-
glob expected_area2 = 78.53981633974483;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
"""
|
|
133
|
-
)
|
|
134
|
-
return jac_code
|
|
29
|
+
def load_jac_template(template_file: str, code: str = "") -> str:
|
|
30
|
+
"""Load a Jac template file and inject code into placeholder."""
|
|
31
|
+
with open(template_file, "r") as f:
|
|
32
|
+
jac_template = f.read()
|
|
33
|
+
return jac_template.replace("#{{INJECT_CODE}}", code)
|
|
135
34
|
|
|
136
35
|
|
|
137
36
|
def create_ls_with_workspace(file_path: str):
|
|
@@ -142,3 +41,141 @@ def create_ls_with_workspace(file_path: str):
|
|
|
142
41
|
uri = from_fs_path(file_path)
|
|
143
42
|
ls.lsp._workspace = Workspace(os.path.dirname(file_path), ls)
|
|
144
43
|
return uri, ls
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class TestFile:
|
|
48
|
+
"""Encapsulates test file information and operations."""
|
|
49
|
+
|
|
50
|
+
path: str
|
|
51
|
+
uri: str
|
|
52
|
+
code: str
|
|
53
|
+
version: int = 1
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def from_template(cls, template_name: str, content: str = "") -> "TestFile":
|
|
57
|
+
"""Create a test file from a template."""
|
|
58
|
+
code = load_jac_template(cls._get_template_path(template_name), content)
|
|
59
|
+
temp_path = create_temp_jac_file(code)
|
|
60
|
+
uri = from_fs_path(temp_path)
|
|
61
|
+
return cls(
|
|
62
|
+
path=temp_path,
|
|
63
|
+
uri=uri or "",
|
|
64
|
+
code=code,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def _get_template_path(file_name: str) -> str:
|
|
69
|
+
"""Get absolute path to test template file."""
|
|
70
|
+
return os.path.abspath(
|
|
71
|
+
os.path.join(os.path.dirname(__file__), file_name)
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def cleanup(self):
|
|
75
|
+
"""Remove temporary test file."""
|
|
76
|
+
if os.path.exists(self.path):
|
|
77
|
+
os.remove(self.path)
|
|
78
|
+
|
|
79
|
+
def increment_version(self) -> int:
|
|
80
|
+
"""Increment and return the version number."""
|
|
81
|
+
self.version += 1
|
|
82
|
+
return self.version
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class LanguageServerTestHelper:
|
|
86
|
+
"""Helper class for language server testing operations."""
|
|
87
|
+
|
|
88
|
+
def __init__(self, ls, test_file: TestFile):
|
|
89
|
+
self.ls = ls
|
|
90
|
+
self.test_file = test_file
|
|
91
|
+
|
|
92
|
+
async def open_document(self) -> None:
|
|
93
|
+
"""Open a document in the language server."""
|
|
94
|
+
from jaclang.langserve.server import did_open
|
|
95
|
+
|
|
96
|
+
params = DidOpenTextDocumentParams(
|
|
97
|
+
text_document=TextDocumentItem(
|
|
98
|
+
uri=self.test_file.uri,
|
|
99
|
+
language_id="jac",
|
|
100
|
+
version=self.test_file.version,
|
|
101
|
+
text=self.test_file.code,
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
await did_open(self.ls, params)
|
|
105
|
+
|
|
106
|
+
async def save_document(self, code: Optional[str] = None) -> None:
|
|
107
|
+
"""Save a document in the language server."""
|
|
108
|
+
from jaclang.langserve.server import did_save
|
|
109
|
+
|
|
110
|
+
content = code if code is not None else self.test_file.code
|
|
111
|
+
version = self.test_file.increment_version()
|
|
112
|
+
|
|
113
|
+
if code:
|
|
114
|
+
self._update_workspace(code, version)
|
|
115
|
+
|
|
116
|
+
from lsprotocol.types import TextDocumentIdentifier
|
|
117
|
+
|
|
118
|
+
params = DidSaveTextDocumentParams(
|
|
119
|
+
text_document=TextDocumentIdentifier(uri=self.test_file.uri),
|
|
120
|
+
text=content
|
|
121
|
+
)
|
|
122
|
+
await did_save(self.ls, params)
|
|
123
|
+
|
|
124
|
+
async def change_document(self, code: str) -> None:
|
|
125
|
+
"""Change document content in the language server."""
|
|
126
|
+
from jaclang.langserve.server import did_change
|
|
127
|
+
|
|
128
|
+
version = self.test_file.increment_version()
|
|
129
|
+
self._update_workspace(code, version)
|
|
130
|
+
|
|
131
|
+
params = DidChangeTextDocumentParams(
|
|
132
|
+
text_document=VersionedTextDocumentIdentifier(
|
|
133
|
+
uri=self.test_file.uri,
|
|
134
|
+
version=version
|
|
135
|
+
),
|
|
136
|
+
content_changes=[{"text": code}], # type: ignore
|
|
137
|
+
)
|
|
138
|
+
await did_change(self.ls, params)
|
|
139
|
+
|
|
140
|
+
def _update_workspace(self, code: str, version: int) -> None:
|
|
141
|
+
"""Update workspace with new document content."""
|
|
142
|
+
self.ls.workspace.put_text_document(
|
|
143
|
+
TextDocumentItem(
|
|
144
|
+
uri=self.test_file.uri,
|
|
145
|
+
language_id="jac",
|
|
146
|
+
version=version,
|
|
147
|
+
text=code,
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def get_diagnostics(self) -> list:
|
|
152
|
+
"""Get diagnostics for the current document."""
|
|
153
|
+
return self.ls.diagnostics.get(self.test_file.uri, [])
|
|
154
|
+
|
|
155
|
+
def get_semantic_tokens(self):
|
|
156
|
+
"""Get semantic tokens for the current document."""
|
|
157
|
+
return self.ls.get_semantic_tokens(self.test_file.uri)
|
|
158
|
+
|
|
159
|
+
def assert_no_diagnostics(self) -> None:
|
|
160
|
+
"""Assert that there are no diagnostics."""
|
|
161
|
+
diagnostics = self.get_diagnostics()
|
|
162
|
+
assert isinstance(diagnostics, list)
|
|
163
|
+
assert len(diagnostics) == 0, f"Expected no diagnostics, found {len(diagnostics)}"
|
|
164
|
+
|
|
165
|
+
def assert_has_diagnostics(self, count: int = 1, message_contains: Optional[str] = None) -> None:
|
|
166
|
+
"""Assert that diagnostics exist with optional message validation."""
|
|
167
|
+
diagnostics = self.get_diagnostics()
|
|
168
|
+
assert isinstance(diagnostics, list)
|
|
169
|
+
assert len(diagnostics) == count, f"Expected {count} diagnostic(s), found {len(diagnostics)}"
|
|
170
|
+
|
|
171
|
+
if message_contains:
|
|
172
|
+
assert message_contains in diagnostics[0].message, \
|
|
173
|
+
f"Expected '{message_contains}' in diagnostic message"
|
|
174
|
+
|
|
175
|
+
def assert_semantic_tokens_count(self, expected_count: int) -> None:
|
|
176
|
+
"""Assert semantic tokens data has expected count."""
|
|
177
|
+
tokens = self.get_semantic_tokens()
|
|
178
|
+
assert hasattr(tokens, "data")
|
|
179
|
+
assert isinstance(tokens.data, list)
|
|
180
|
+
assert len(tokens.data) == expected_count, \
|
|
181
|
+
f"Expected {expected_count} tokens, found {len(tokens.data)}"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
1
2
|
from jaclang.utils.test import TestCase
|
|
2
3
|
from jaclang.vendor.pygls import uris
|
|
3
4
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
@@ -310,7 +311,6 @@ class TestJacLangServer(TestCase):
|
|
|
310
311
|
for token_type, expected_count in expected_counts:
|
|
311
312
|
self.assertEqual(str(sem_list).count(token_type), expected_count)
|
|
312
313
|
|
|
313
|
-
@pytest.mark.xfail(reason="TODO: Fix when we have the type checker")
|
|
314
314
|
def test_completion(self) -> None:
|
|
315
315
|
"""Test that the completions are correct."""
|
|
316
316
|
lsp = JacLangServer()
|
|
@@ -318,95 +318,28 @@ class TestJacLangServer(TestCase):
|
|
|
318
318
|
workspace = Workspace(workspace_path, lsp)
|
|
319
319
|
lsp.lsp._workspace = workspace
|
|
320
320
|
base_module_file = uris.from_fs_path(
|
|
321
|
-
self.fixture_abs_path("
|
|
321
|
+
self.fixture_abs_path("completion_test_err.jac")
|
|
322
322
|
)
|
|
323
323
|
lsp.deep_check(base_module_file)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
(
|
|
333
|
-
lspt.Position(
|
|
334
|
-
["
|
|
335
|
-
3,
|
|
336
|
-
),
|
|
337
|
-
(
|
|
338
|
-
lspt.Position(65, 13),
|
|
339
|
-
[
|
|
340
|
-
"get_color1",
|
|
341
|
-
"color1",
|
|
342
|
-
"point1",
|
|
343
|
-
"base_colorred",
|
|
344
|
-
"pointred",
|
|
345
|
-
"inner_red",
|
|
346
|
-
"doubleinner",
|
|
347
|
-
"apply_red",
|
|
348
|
-
],
|
|
349
|
-
11,
|
|
350
|
-
),
|
|
351
|
-
(
|
|
352
|
-
lspt.Position(65, 23),
|
|
353
|
-
["color22", "doublepoint22", "point22", "apply_inner_red", "enum_red"],
|
|
354
|
-
5,
|
|
355
|
-
),
|
|
356
|
-
(
|
|
357
|
-
lspt.Position(65, 31),
|
|
358
|
-
["RED22", "GREEN22", "BLUE22"],
|
|
359
|
-
3,
|
|
360
|
-
),
|
|
361
|
-
(
|
|
362
|
-
lspt.Position(35, 28),
|
|
363
|
-
[],
|
|
364
|
-
0,
|
|
365
|
-
),
|
|
366
|
-
(
|
|
367
|
-
lspt.Position(72, 12),
|
|
368
|
-
[
|
|
369
|
-
"get_color1",
|
|
370
|
-
"color1",
|
|
371
|
-
"point1",
|
|
372
|
-
"base_colorred",
|
|
373
|
-
"pointred",
|
|
374
|
-
"inner_red",
|
|
375
|
-
"doubleinner",
|
|
376
|
-
"apply_red",
|
|
377
|
-
],
|
|
378
|
-
11,
|
|
379
|
-
),
|
|
380
|
-
(
|
|
381
|
-
lspt.Position(73, 22),
|
|
382
|
-
["color22", "doublepoint22", "apply_inner_red", "point22", "enum_red"],
|
|
383
|
-
5,
|
|
384
|
-
),
|
|
385
|
-
(
|
|
386
|
-
lspt.Position(37, 12),
|
|
387
|
-
["self", "add", "subtract", "x", "Colorenum", "Colour1", "red", "r"],
|
|
388
|
-
153,
|
|
389
|
-
None,
|
|
324
|
+
|
|
325
|
+
@dataclass
|
|
326
|
+
class Case:
|
|
327
|
+
pos: lspt.Position
|
|
328
|
+
expected: list[str]
|
|
329
|
+
trigger: str = "."
|
|
330
|
+
|
|
331
|
+
test_cases: list[Case] = [
|
|
332
|
+
Case(
|
|
333
|
+
lspt.Position(8, 8),
|
|
334
|
+
["bar", "baz"],
|
|
390
335
|
),
|
|
391
336
|
]
|
|
392
|
-
default_trigger = "."
|
|
393
337
|
for case in test_cases:
|
|
394
|
-
position, expected_completions, expected_length = case[:3]
|
|
395
|
-
completion_trigger = case[3] if len(case) > 3 else default_trigger
|
|
396
338
|
completions = lsp.get_completion(
|
|
397
|
-
base_module_file,
|
|
339
|
+
base_module_file, case.pos, completion_trigger=case.trigger
|
|
398
340
|
).items
|
|
399
|
-
for completion in
|
|
341
|
+
for completion in case.expected:
|
|
400
342
|
self.assertIn(completion, str(completions))
|
|
401
|
-
self.assertEqual(expected_length, len(completions))
|
|
402
|
-
|
|
403
|
-
if position == lspt.Position(73, 12):
|
|
404
|
-
self.assertEqual(
|
|
405
|
-
2, str(completions).count("kind=<CompletionItemKind.Function: 3>")
|
|
406
|
-
)
|
|
407
|
-
self.assertEqual(
|
|
408
|
-
4, str(completions).count("kind=<CompletionItemKind.Field: 5>")
|
|
409
|
-
)
|
|
410
343
|
|
|
411
344
|
def test_go_to_reference(self) -> None:
|
|
412
345
|
"""Test that the go to reference is correct."""
|
|
@@ -419,8 +352,8 @@ class TestJacLangServer(TestCase):
|
|
|
419
352
|
lsp.deep_check(circle_file)
|
|
420
353
|
test_cases = [
|
|
421
354
|
(47, 12, ["circle.jac:47:8-47:14", "69:8-69:14", "74:8-74:14"]),
|
|
422
|
-
(54, 66, ["54:62-54:76", "65:
|
|
423
|
-
(62, 14, ["65:
|
|
355
|
+
(54, 66, ["54:62-54:76", "65:23-65:37"]),
|
|
356
|
+
(62, 14, ["65:44-65:57", "70:33-70:46"]),
|
|
424
357
|
]
|
|
425
358
|
for line, char, expected_refs in test_cases:
|
|
426
359
|
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
|
|
@@ -608,3 +541,7 @@ class TestJacLangServer(TestCase):
|
|
|
608
541
|
"/tests/fixtures/M1.jac:0:0-0:0",
|
|
609
542
|
str(lsp.get_definition(guess_game_file, lspt.Position(29, 9))),
|
|
610
543
|
)
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
TestJacLangServer().test_completion()
|
jaclang/langserve/utils.jac
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Utility functions for the language server."""
|
|
2
2
|
|
|
3
|
+
|
|
3
4
|
import asyncio;
|
|
4
5
|
import builtins;
|
|
5
6
|
import re;
|
|
@@ -112,25 +113,21 @@ def find_deepest_symbol_node_at_pos(
|
|
|
112
113
|
|
|
113
114
|
|
|
114
115
|
"""Check if the position falls within the node's location."""
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
# All lines and columns are 1-Based
|
|
117
|
+
def position_within_node(n: uni.UniNode, line: int, character: int) -> bool {
|
|
118
|
+
if n.loc.first_line < line < n.loc.last_line {
|
|
117
119
|
return True;
|
|
118
120
|
}
|
|
119
|
-
if
|
|
120
|
-
|
|
121
|
-
and <>node.loc.last_line == (line + 1)
|
|
122
|
-
and <>node.loc.col_end >= (character + 1)
|
|
123
|
-
|
|
124
|
-
or <>node.loc.last_line > (line + 1)
|
|
125
|
-
{
|
|
126
|
-
return True;
|
|
121
|
+
if line < n.loc.first_line or line > n.loc.last_line {
|
|
122
|
+
return False;
|
|
127
123
|
}
|
|
128
|
-
if
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
if line == n.loc.first_line and character < n.loc.col_start {
|
|
125
|
+
return False;
|
|
126
|
+
}
|
|
127
|
+
if line == n.loc.last_line and character >= n.loc.col_end {
|
|
128
|
+
return False;
|
|
132
129
|
}
|
|
133
|
-
return
|
|
130
|
+
return True;
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
|
jaclang/runtimelib/machine.py
CHANGED
|
@@ -1132,6 +1132,13 @@ class JacBasics:
|
|
|
1132
1132
|
return JacMachineInterface.get_edges(origin, path.destinations[-1])
|
|
1133
1133
|
return origin
|
|
1134
1134
|
|
|
1135
|
+
@staticmethod
|
|
1136
|
+
async def arefs(
|
|
1137
|
+
path: DataSpatialPath | NodeArchetype | list[NodeArchetype],
|
|
1138
|
+
) -> None:
|
|
1139
|
+
"""Jac's apply_dir stmt feature."""
|
|
1140
|
+
pass
|
|
1141
|
+
|
|
1135
1142
|
@staticmethod
|
|
1136
1143
|
def filter(
|
|
1137
1144
|
items: list[Archetype],
|
|
@@ -9,7 +9,8 @@ from typing import Optional, Sequence
|
|
|
9
9
|
|
|
10
10
|
from jaclang.runtimelib.machine import JacMachine as Jac
|
|
11
11
|
from jaclang.runtimelib.machine import JacMachineInterface
|
|
12
|
-
from jaclang.
|
|
12
|
+
from jaclang.settings import settings
|
|
13
|
+
from jaclang.utils.module_resolver import get_jac_search_paths, get_py_search_paths
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class JacMetaImporter(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
@@ -48,6 +49,30 @@ class JacMetaImporter(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
|
48
49
|
return importlib.util.spec_from_file_location(
|
|
49
50
|
fullname, candidate_path + ".jac", loader=self
|
|
50
51
|
)
|
|
52
|
+
|
|
53
|
+
# TODO: We can remove it once python modules are fully supported in jac
|
|
54
|
+
if path is None and settings.pyfile_raise:
|
|
55
|
+
if settings.pyfile_raise_full:
|
|
56
|
+
paths_to_search = get_jac_search_paths()
|
|
57
|
+
else:
|
|
58
|
+
paths_to_search = get_py_search_paths()
|
|
59
|
+
for search_path in paths_to_search:
|
|
60
|
+
candidate_path = os.path.join(search_path, *module_path_parts)
|
|
61
|
+
# Check for directory package
|
|
62
|
+
if os.path.isdir(candidate_path):
|
|
63
|
+
init_file = os.path.join(candidate_path, "__init__.py")
|
|
64
|
+
if os.path.isfile(init_file):
|
|
65
|
+
return importlib.util.spec_from_file_location(
|
|
66
|
+
fullname,
|
|
67
|
+
init_file,
|
|
68
|
+
loader=self,
|
|
69
|
+
submodule_search_locations=[candidate_path],
|
|
70
|
+
)
|
|
71
|
+
# Check for .py file
|
|
72
|
+
if os.path.isfile(candidate_path + ".py"):
|
|
73
|
+
return importlib.util.spec_from_file_location(
|
|
74
|
+
fullname, candidate_path + ".py", loader=self
|
|
75
|
+
)
|
|
51
76
|
return None
|
|
52
77
|
|
|
53
78
|
def create_module(
|
|
@@ -78,6 +103,7 @@ class JacMetaImporter(importlib.abc.MetaPathFinder, importlib.abc.Loader):
|
|
|
78
103
|
target=target,
|
|
79
104
|
base_path=base_path,
|
|
80
105
|
override_name=module.__name__,
|
|
106
|
+
lng="py" if file_path.endswith(".py") else "jac",
|
|
81
107
|
)
|
|
82
108
|
if ret:
|
|
83
109
|
loaded_module = ret[0]
|
|
@@ -44,7 +44,7 @@ walker create_custom_object {
|
|
|
44
44
|
|
|
45
45
|
can exit1 with `root exit {
|
|
46
46
|
# get directly from shelf
|
|
47
|
-
o =
|
|
47
|
+
o = _jl.get_context().mem.__shelf__.get(str(self.obj.__jac__.id)).archetype;
|
|
48
48
|
print(jid(o));
|
|
49
49
|
print(o);
|
|
50
50
|
}
|
|
@@ -87,6 +87,6 @@ walker delete_custom_object {
|
|
|
87
87
|
has object_id: str;
|
|
88
88
|
|
|
89
89
|
can enter1 with `root entry {
|
|
90
|
-
|
|
90
|
+
_jl.destroy([&(self.object_id)]);
|
|
91
91
|
}
|
|
92
92
|
}
|
jaclang/settings.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import configparser
|
|
4
4
|
import os
|
|
5
|
+
from argparse import Namespace
|
|
5
6
|
from dataclasses import dataclass, fields
|
|
6
7
|
|
|
7
8
|
|
|
@@ -19,11 +20,16 @@ class Settings:
|
|
|
19
20
|
# Compiler configuration
|
|
20
21
|
disable_mtllm: bool = False
|
|
21
22
|
ignore_test_annex: bool = False
|
|
22
|
-
pyout_jaclib_alias: str = "
|
|
23
|
+
pyout_jaclib_alias: str = "_jl"
|
|
24
|
+
pyfile_raise: bool = False
|
|
25
|
+
pyfile_raise_full: bool = False
|
|
23
26
|
|
|
24
27
|
# Formatter configuration
|
|
25
28
|
max_line_length: int = 88
|
|
26
29
|
|
|
30
|
+
# pytorch configuration
|
|
31
|
+
predynamo_pass: bool = False
|
|
32
|
+
|
|
27
33
|
# LSP configuration
|
|
28
34
|
lsp_debug: bool = False
|
|
29
35
|
|
|
@@ -42,6 +48,8 @@ class Settings:
|
|
|
42
48
|
"""Load settings from all available sources."""
|
|
43
49
|
self.load_config_file()
|
|
44
50
|
self.load_env_vars()
|
|
51
|
+
# CLI arguments are applied by the CLI after parsing, via
|
|
52
|
+
# `settings.load_command_line_arguments(args)` in start_cli.
|
|
45
53
|
|
|
46
54
|
def load_config_file(self) -> None:
|
|
47
55
|
"""Load settings from a configuration file."""
|
|
@@ -64,19 +72,15 @@ class Settings:
|
|
|
64
72
|
if env_value is not None:
|
|
65
73
|
setattr(self, key, self.convert_type(env_value))
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# )
|
|
77
|
-
# parser.add_argument("--port", type=int, default=self.config["port"])
|
|
78
|
-
# parser.add_argument("--host", default=self.config["host"])
|
|
79
|
-
# args = parser.parse_args()
|
|
75
|
+
def load_command_line_arguments(self, args: Namespace) -> None:
|
|
76
|
+
"""Override settings from command-line arguments if provided."""
|
|
77
|
+
args_dict = vars(args) if not isinstance(args, dict) else args
|
|
78
|
+
for key in [f.name for f in fields(self)]:
|
|
79
|
+
if key in args_dict and args_dict[key] is not None:
|
|
80
|
+
val = args_dict[key]
|
|
81
|
+
if isinstance(val, str):
|
|
82
|
+
val = self.convert_type(val)
|
|
83
|
+
setattr(self, key, val)
|
|
80
84
|
|
|
81
85
|
def str_to_bool(self, value: str) -> bool:
|
|
82
86
|
"""Convert string to boolean."""
|
|
@@ -63,15 +63,15 @@ with entry:__main__ {
|
|
|
63
63
|
glob expected_area = 78.53981633974483;
|
|
64
64
|
|
|
65
65
|
test calc_area {
|
|
66
|
-
|
|
66
|
+
assert almostEqual(calculate_area(RAD), expected_area);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
test circle_area {
|
|
70
70
|
c = Circle(RAD);
|
|
71
|
-
|
|
71
|
+
assert almostEqual(c.area(), expected_area);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
test circle_type {
|
|
75
75
|
c = Circle(RAD);
|
|
76
|
-
|
|
76
|
+
assert c.shape_type == ShapeType.CIRCLE;
|
|
77
77
|
}
|
|
@@ -3,20 +3,20 @@ import from jaclang.runtimelib.machine { JacMachine }
|
|
|
3
3
|
|
|
4
4
|
glob dynamic_module_source =
|
|
5
5
|
"""
|
|
6
|
-
|
|
6
|
+
import from arch_create_util {UtilityNode}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
walker DynamicWalker {
|
|
9
|
+
can start with entry {
|
|
10
|
+
print("DynamicWalker Started");
|
|
11
|
+
here ++> UtilityNode(data=42);
|
|
12
|
+
visit [-->](`?UtilityNode);
|
|
13
|
+
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
def UtilityNode {
|
|
16
|
+
here.display_data();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
""";
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
with entry {
|