jaclang 0.8.0__py3-none-any.whl → 0.8.2__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.

Files changed (124) hide show
  1. jaclang/__init__.py +6 -0
  2. jaclang/cli/cli.py +23 -50
  3. jaclang/compiler/codeinfo.py +0 -1
  4. jaclang/compiler/jac.lark +14 -22
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +378 -531
  7. jaclang/compiler/passes/main/__init__.py +0 -14
  8. jaclang/compiler/passes/main/annex_pass.py +2 -8
  9. jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
  11. jaclang/compiler/passes/main/def_use_pass.py +4 -7
  12. jaclang/compiler/passes/main/import_pass.py +6 -14
  13. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  14. jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
  15. jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
  16. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
  18. jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
  19. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
  20. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
  21. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
  22. jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
  23. jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
  24. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
  25. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
  26. jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
  27. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
  28. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
  29. jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
  30. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
  31. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
  32. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
  33. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
  34. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
  35. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
  36. jaclang/compiler/program.py +22 -66
  37. jaclang/compiler/tests/fixtures/fam.jac +2 -2
  38. jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
  39. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
  40. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
  41. jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
  42. jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
  43. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
  44. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
  45. jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
  46. jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
  47. jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
  48. jaclang/compiler/tests/test_importer.py +30 -13
  49. jaclang/compiler/tests/test_parser.py +1 -0
  50. jaclang/compiler/unitree.py +488 -320
  51. jaclang/langserve/__init__.jac +1 -0
  52. jaclang/langserve/engine.jac +503 -0
  53. jaclang/langserve/sem_manager.jac +309 -0
  54. jaclang/langserve/server.jac +201 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
  56. jaclang/langserve/tests/server_test/utils.py +35 -6
  57. jaclang/langserve/tests/session.jac +294 -0
  58. jaclang/langserve/tests/test_sem_tokens.py +2 -2
  59. jaclang/langserve/tests/test_server.py +8 -7
  60. jaclang/langserve/utils.jac +51 -30
  61. jaclang/runtimelib/archetype.py +128 -6
  62. jaclang/runtimelib/builtin.py +17 -14
  63. jaclang/runtimelib/importer.py +51 -76
  64. jaclang/runtimelib/machine.py +469 -305
  65. jaclang/runtimelib/meta_importer.py +86 -0
  66. jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
  67. jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
  68. jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
  69. jaclang/runtimelib/tests/test_jaseci.py +3 -1
  70. jaclang/runtimelib/utils.py +3 -3
  71. jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
  72. jaclang/tests/fixtures/async_ability.jac +43 -10
  73. jaclang/tests/fixtures/async_function.jac +18 -0
  74. jaclang/tests/fixtures/async_walker.jac +17 -12
  75. jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
  76. jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
  77. jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
  78. jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
  79. jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
  80. jaclang/tests/fixtures/concurrency.jac +1 -1
  81. jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
  82. jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
  83. jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
  84. jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
  85. jaclang/tests/fixtures/deep/one_lev.jac +2 -2
  86. jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
  87. jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
  88. jaclang/tests/fixtures/edge_ability.jac +49 -0
  89. jaclang/tests/fixtures/foo.jac +14 -22
  90. jaclang/tests/fixtures/guess_game.jac +1 -1
  91. jaclang/tests/fixtures/here_usage_error.jac +21 -0
  92. jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
  93. jaclang/tests/fixtures/jac_from_py.py +1 -1
  94. jaclang/tests/fixtures/jp_importer.jac +6 -6
  95. jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
  96. jaclang/tests/fixtures/node_del.jac +30 -36
  97. jaclang/tests/fixtures/unicode_strings.jac +24 -0
  98. jaclang/tests/fixtures/visit_traversal.jac +47 -0
  99. jaclang/tests/fixtures/walker_update.jac +5 -7
  100. jaclang/tests/test_cli.py +12 -7
  101. jaclang/tests/test_language.py +218 -145
  102. jaclang/tests/test_reference.py +9 -4
  103. jaclang/tests/test_typecheck.py +13 -26
  104. jaclang/utils/helpers.py +14 -6
  105. jaclang/utils/lang_tools.py +9 -8
  106. jaclang/utils/module_resolver.py +23 -0
  107. jaclang/utils/tests/test_lang_tools.py +2 -1
  108. jaclang/utils/treeprinter.py +3 -4
  109. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
  110. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
  111. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
  112. jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
  113. jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
  114. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
  115. jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
  116. jaclang/langserve/__init__.py +0 -1
  117. jaclang/langserve/engine.py +0 -553
  118. jaclang/langserve/sem_manager.py +0 -383
  119. jaclang/langserve/server.py +0 -167
  120. jaclang/langserve/tests/session.py +0 -255
  121. jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
  122. jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
  123. jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
  124. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  """Test for Jac language server[VSCE] features"""
2
+
2
3
  import os
3
4
  import pytest
4
5
 
@@ -12,24 +13,22 @@ from lsprotocol.types import (
12
13
  VersionedTextDocumentIdentifier,
13
14
  TextDocumentIdentifier,
14
15
  )
15
- from jaclang.langserve.engine import JacLangServer
16
- from jaclang.langserve.server import (
17
- did_open,
18
- did_save,
19
- did_change,
20
- formatting,
21
- )
22
16
  from jaclang.langserve.tests.server_test.utils import (
23
17
  create_temp_jac_file,
24
18
  get_code,
25
19
  get_jac_file_path,
20
+ get_simple_code,
26
21
  create_ls_with_workspace, # new helper
27
22
  )
28
23
  from jaclang.vendor.pygls.uris import from_fs_path
29
24
  from jaclang.vendor.pygls.workspace import Workspace
25
+ from jaclang import JacMachineInterface as _
26
+ from jaclang.langserve.engine import JacLangServer
27
+ from jaclang.langserve.server import did_open, did_save, did_change, formatting
30
28
 
31
29
  JAC_FILE = get_jac_file_path()
32
30
 
31
+
33
32
  class TestLangServe:
34
33
  """Test class for Jac language server features."""
35
34
 
@@ -96,7 +95,7 @@ class TestLangServe:
96
95
  temp_file_path = create_temp_jac_file(code)
97
96
  uri = from_fs_path(temp_file_path)
98
97
  ls.lsp._workspace = Workspace(os.path.dirname(temp_file_path), ls)
99
-
98
+
100
99
  params = DidOpenTextDocumentParams(
101
100
  text_document=TextDocumentItem(
102
101
  uri=uri,
@@ -131,7 +130,9 @@ class TestLangServe:
131
130
  ls.shutdown()
132
131
  assert hasattr(sem_tokens, "data")
133
132
  assert isinstance(sem_tokens.data, list)
134
- assert len(sem_tokens.data) == 0 # TODO: we should retain the sem tokens, will be fixed in next PR
133
+ assert (
134
+ len(sem_tokens.data) == 0
135
+ ) # TODO: we should retain the sem tokens, will be fixed in next PR
135
136
 
136
137
  os.remove(temp_file_path)
137
138
 
@@ -142,14 +143,17 @@ class TestLangServe:
142
143
  temp_file_path = create_temp_jac_file(code)
143
144
  uri, ls = create_ls_with_workspace(temp_file_path)
144
145
 
145
- await did_open(ls, DidOpenTextDocumentParams(
146
- text_document=TextDocumentItem(
147
- uri=uri,
148
- language_id="jac",
149
- version=1,
150
- text=code,
151
- )
152
- ))
146
+ await did_open(
147
+ ls,
148
+ DidOpenTextDocumentParams(
149
+ text_document=TextDocumentItem(
150
+ uri=uri,
151
+ language_id="jac",
152
+ version=1,
153
+ text=code,
154
+ )
155
+ ),
156
+ )
153
157
 
154
158
  params = DidSaveTextDocumentParams(
155
159
  text_document=TextDocumentItem(
@@ -167,12 +171,14 @@ class TestLangServe:
167
171
 
168
172
  # Now simulate a syntax error by updating the workspace and saving
169
173
  broken_code = get_code("error")
170
- ls.workspace.put_text_document(TextDocumentItem(
171
- uri=uri,
172
- language_id="jac",
173
- version=3,
174
- text=broken_code,
175
- ))
174
+ ls.workspace.put_text_document(
175
+ TextDocumentItem(
176
+ uri=uri,
177
+ language_id="jac",
178
+ version=3,
179
+ text=broken_code,
180
+ )
181
+ )
176
182
  params = DidSaveTextDocumentParams(
177
183
  text_document=TextDocumentItem(
178
184
  uri=uri,
@@ -182,6 +188,9 @@ class TestLangServe:
182
188
  )
183
189
  )
184
190
  await did_save(ls, params)
191
+ sem_tokens = ls.get_semantic_tokens(uri)
192
+ # semantic tokens should still be present even if there is a syntax error
193
+ assert len(sem_tokens.data) == 300
185
194
  diagnostics = ls.diagnostics.get(uri, [])
186
195
  assert isinstance(diagnostics, list)
187
196
  assert len(diagnostics) == 1
@@ -197,26 +206,31 @@ class TestLangServe:
197
206
  temp_file_path = create_temp_jac_file(code)
198
207
  uri, ls = create_ls_with_workspace(temp_file_path)
199
208
 
200
- await did_open(ls, DidOpenTextDocumentParams(
201
- text_document=TextDocumentItem(
202
- uri=uri,
203
- language_id="jac",
204
- version=1,
205
- text=code,
206
- )
207
- ))
209
+ await did_open(
210
+ ls,
211
+ DidOpenTextDocumentParams(
212
+ text_document=TextDocumentItem(
213
+ uri=uri,
214
+ language_id="jac",
215
+ version=1,
216
+ text=code,
217
+ )
218
+ ),
219
+ )
208
220
 
209
221
  # No error, should be no diagnostics
210
222
  params = DidChangeTextDocumentParams(
211
223
  text_document=VersionedTextDocumentIdentifier(uri=uri, version=2),
212
- content_changes=[{"text": "\n" + code}]
224
+ content_changes=[{"text": "\n" + code}],
225
+ )
226
+ ls.workspace.put_text_document(
227
+ TextDocumentItem(
228
+ uri=uri,
229
+ language_id="jac",
230
+ version=2,
231
+ text="\n" + code,
232
+ )
213
233
  )
214
- ls.workspace.put_text_document(TextDocumentItem(
215
- uri=uri,
216
- language_id="jac",
217
- version=2,
218
- text="\n" + code,
219
- ))
220
234
  await did_change(ls, params)
221
235
  diagnostics = ls.diagnostics.get(uri, [])
222
236
  assert isinstance(diagnostics, list)
@@ -227,15 +241,20 @@ class TestLangServe:
227
241
  error_code = "\nerror"
228
242
  params = DidChangeTextDocumentParams(
229
243
  text_document=VersionedTextDocumentIdentifier(uri=uri, version=3),
230
- content_changes=[{"text": error_code + code}]
244
+ content_changes=[{"text": error_code + code}],
245
+ )
246
+ ls.workspace.put_text_document(
247
+ TextDocumentItem(
248
+ uri=uri,
249
+ language_id="jac",
250
+ version=3,
251
+ text=error_code + code,
252
+ )
231
253
  )
232
- ls.workspace.put_text_document(TextDocumentItem(
233
- uri=uri,
234
- language_id="jac",
235
- version=3,
236
- text=error_code + code,
237
- ))
238
254
  await did_change(ls, params)
255
+ sem_tokens = ls.get_semantic_tokens(uri)
256
+ # semantic tokens should still be present even if there is a syntax error
257
+ assert len(sem_tokens.data) == 300
239
258
  diagnostics = ls.diagnostics.get(uri, [])
240
259
  assert isinstance(diagnostics, list)
241
260
  assert len(diagnostics) == 1
@@ -251,12 +270,84 @@ class TestLangServe:
251
270
  uri, ls = create_ls_with_workspace(temp_file_path)
252
271
  params = DocumentFormattingParams(
253
272
  text_document=TextDocumentIdentifier(uri=uri),
254
- options={"tabSize": 4, "insertSpaces": True}
273
+ options={"tabSize": 4, "insertSpaces": True},
255
274
  )
256
275
  edits = formatting(ls, params)
257
276
  assert isinstance(edits, list)
258
277
  assert isinstance(edits[0], TextEdit)
259
- assert len(edits[0].new_text) > 100 # it is a random number to check if the text is changed
278
+ assert (
279
+ len(edits[0].new_text) > 100
280
+ ) # it is a random number to check if the text is changed
260
281
  print(edits[0].new_text)
261
282
  ls.shutdown()
262
- os.remove(temp_file_path)
283
+ os.remove(temp_file_path)
284
+
285
+ @pytest.mark.asyncio
286
+ async def test_multifile_workspace(self):
287
+ """Test opening multiple Jac files in a workspace."""
288
+ code1 = get_simple_code("")
289
+ code2 = get_simple_code("error")
290
+ temp_file_path1 = create_temp_jac_file(code1)
291
+ temp_file_path2 = create_temp_jac_file(code2)
292
+
293
+ uri1, ls = create_ls_with_workspace(temp_file_path1)
294
+ uri2 = from_fs_path(temp_file_path2)
295
+
296
+ await did_open(
297
+ ls,
298
+ DidOpenTextDocumentParams(
299
+ text_document=TextDocumentItem(
300
+ uri=uri1,
301
+ language_id="jac",
302
+ version=1,
303
+ text=code1,
304
+ )
305
+ ),
306
+ )
307
+ await did_open(
308
+ ls,
309
+ DidOpenTextDocumentParams(
310
+ text_document=TextDocumentItem(
311
+ uri=uri2,
312
+ language_id="jac",
313
+ version=1,
314
+ text=code2,
315
+ )
316
+ ),
317
+ )
318
+
319
+ diagnostics1 = ls.diagnostics.get(uri1, [])
320
+ diagnostics2 = ls.diagnostics.get(uri2, [])
321
+ assert len(diagnostics1) == 0
322
+ assert len(diagnostics2) == 1
323
+ assert diagnostics2[0].message == "Syntax Error"
324
+
325
+ before_sem_tokens_1 = ls.get_semantic_tokens(uri1)
326
+ before_sem_tokens_2 = ls.get_semantic_tokens(uri2)
327
+ assert len(before_sem_tokens_1.data) == 15
328
+ assert len(before_sem_tokens_2.data) == 0
329
+
330
+ changed_code = get_simple_code("glob x = 90;")
331
+ ls.workspace.put_text_document(
332
+ TextDocumentItem(
333
+ uri=uri1,
334
+ language_id="jac",
335
+ version=2,
336
+ text=changed_code,
337
+ )
338
+ )
339
+ params = DidChangeTextDocumentParams(
340
+ text_document=VersionedTextDocumentIdentifier(uri=uri1, version=2),
341
+ content_changes=[{"text": changed_code}],
342
+ )
343
+ await did_change(ls, params)
344
+
345
+ after_sem_tokens_1 = ls.get_semantic_tokens(uri1)
346
+ after_sem_tokens_2 = ls.get_semantic_tokens(uri2)
347
+
348
+ assert len(after_sem_tokens_1.data) == 20
349
+ assert len(after_sem_tokens_2.data) == 0
350
+
351
+ ls.shutdown()
352
+ os.remove(temp_file_path1)
353
+ os.remove(temp_file_path2)
@@ -1,29 +1,37 @@
1
1
  """Unit test utilities for JacLangServer."""
2
+
2
3
  import os
3
4
  import tempfile
4
5
 
5
- from jaclang.langserve.engine import JacLangServer
6
6
  from jaclang.vendor.pygls.uris import from_fs_path
7
7
  from jaclang.vendor.pygls.workspace import Workspace
8
8
 
9
9
  from textwrap import dedent
10
10
 
11
+
11
12
  def get_jac_file_path():
12
13
  """Return the absolute path to the sample Jac file used for testing."""
13
14
  return os.path.abspath(
14
- os.path.join(os.path.dirname(__file__), "../../../../examples/manual_code/circle.jac")
15
+ os.path.join(
16
+ os.path.dirname(__file__), "../../../../examples/manual_code/circle.jac"
17
+ )
15
18
  )
16
19
 
20
+
17
21
  def create_temp_jac_file(initial_content: str = "") -> str:
18
22
  """Create a temporary Jac file with optional initial content and return its path."""
19
- temp = tempfile.NamedTemporaryFile(delete=False, suffix=".jac", mode="w", encoding="utf-8")
23
+ temp = tempfile.NamedTemporaryFile(
24
+ delete=False, suffix=".jac", mode="w", encoding="utf-8"
25
+ )
20
26
  temp.write(initial_content)
21
27
  temp.close()
22
28
  return temp.name
23
29
 
30
+
24
31
  def get_code(code: str) -> str:
25
32
  """Generate a sample Jac code snippet with optional test code injected."""
26
- jac_code = dedent(f'''
33
+ jac_code = dedent(
34
+ f'''
27
35
  """
28
36
  This module demonstrates a simple circle class and a function to calculate
29
37
  the area of a circle in all of Jac's glory.
@@ -104,12 +112,33 @@ def get_code(code: str) -> str:
104
112
  c = Circle(RAD);
105
113
  check c.shape_type == ShapeType.CIRCLE;
106
114
  }}
107
- ''')
115
+ '''
116
+ )
108
117
  return jac_code
109
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
135
+
136
+
110
137
  def create_ls_with_workspace(file_path: str):
111
138
  """Create JacLangServer and workspace for a given file path, return (uri, ls)."""
139
+ from jaclang.langserve.engine import JacLangServer
140
+
112
141
  ls = JacLangServer()
113
142
  uri = from_fs_path(file_path)
114
143
  ls.lsp._workspace = Workspace(os.path.dirname(file_path), ls)
115
- return uri, ls
144
+ return uri, ls
@@ -0,0 +1,294 @@
1
+ """Provides LSP session helpers for testing."""
2
+
3
+ import os;
4
+ import subprocess;
5
+ import sys;
6
+ import from concurrent.futures { Future, ThreadPoolExecutor }
7
+ import from threading { Event }
8
+
9
+ import from pylsp_jsonrpc.dispatchers { MethodDispatcher }
10
+ import from pylsp_jsonrpc.endpoint { Endpoint }
11
+ import from pylsp_jsonrpc.streams { JsonRpcStreamReader, JsonRpcStreamWriter }
12
+
13
+ import defaults;
14
+
15
+
16
+ with entry {
17
+ LSP_EXIT_TIMEOUT = 5000;
18
+ PUBLISH_DIAGNOSTICS = 'textDocument/publishDiagnostics';
19
+ WINDOW_LOG_MESSAGE = 'window/logMessage';
20
+ WINDOW_SHOW_MESSAGE = 'window/showMessage';
21
+ }
22
+
23
+
24
+ """Send and Receive messages over LSP as a test LS Client."""
25
+ class LspSession (MethodDispatcher) {
26
+ def init(self: LspSession, cwd: Any = None) {
27
+ self.cwd = cwd if cwd else os.getcwd() ;
28
+ self._thread_pool = ThreadPoolExecutor();
29
+ self._sub = None;
30
+ self._writer = None;
31
+ self._reader = None;
32
+ self._endpoint = None;
33
+ self._notification_callbacks = {};
34
+ }
35
+
36
+ """Context manager entrypoint.\n\n shell=True needed for pytest-cov to work in subprocess.\n """
37
+ def __enter__(self: LspSession) {
38
+ self._sub = subprocess.Popen(
39
+ ["jac", "run",
40
+ os.path.join(os.path.dirname(os.path.dirname(__file__)), 'server.jac')],
41
+ stdout=subprocess.PIPE,
42
+ stdin=subprocess.PIPE,
43
+ stderr=subprocess.DEVNULL,
44
+ bufsize=0,
45
+ cwd=self.cwd,
46
+ env=os.environ,
47
+ shell=('WITH_COVERAGE' in os.environ)
48
+ );
49
+ self._writer = JsonRpcStreamWriter(os.fdopen(self._sub.stdin.fileno(), 'wb'));
50
+ self._reader = JsonRpcStreamReader(os.fdopen(self._sub.stdout.fileno(), 'rb'));
51
+ dispatcher =
52
+ {PUBLISH_DIAGNOSTICS : self._publish_diagnostics , WINDOW_SHOW_MESSAGE : self._window_show_message , WINDOW_LOG_MESSAGE : self._window_log_message };
53
+ self._endpoint = Endpoint(dispatcher, self._writer.write);
54
+ self._thread_pool.submit(self._reader.listen, self._endpoint.consume);
55
+ return self;
56
+ }
57
+
58
+ def __exit__(self: LspSession, typ: Any, value: Any, _tb: Any) {
59
+ self.shutdown(True);
60
+ try {
61
+ self._sub.terminate();
62
+ } except Exception as e {
63
+
64
+ }
65
+
66
+ self._endpoint.shutdown();
67
+ self._thread_pool.shutdown();
68
+ }
69
+
70
+ """Sends the initialize request to LSP server."""
71
+ def initialize(
72
+ self: LspSession,
73
+ initialize_params: Any = None,
74
+ process_server_capabilities: Any = None
75
+ ) {
76
+ server_initialized = Event();
77
+ def _after_initialize(fut: Any) {
78
+ if process_server_capabilities {
79
+ process_server_capabilities(fut.result());
80
+ }
81
+ self.initialized();
82
+ server_initialized.set();
83
+ }
84
+ self._send_request(
85
+ 'initialize',
86
+ params=initialize_params
87
+ if (initialize_params is not None)
88
+ else defaults.VSCODE_DEFAULT_INITIALIZE
89
+ ,
90
+ handle_response=_after_initialize
91
+ );
92
+ server_initialized.wait();
93
+ }
94
+
95
+ """Sends the initialized notification to LSP server."""
96
+ def initialized(self: LspSession, initialized_params: Any = None) {
97
+ if (initialized_params is None) {
98
+ initialized_params = {};
99
+ }
100
+ self._endpoint.notify('initialized', initialized_params);
101
+ }
102
+
103
+ """Sends the shutdown request to LSP server."""
104
+ def shutdown(
105
+ self: LspSession,
106
+ should_exit: Any,
107
+ exit_timeout: Any = LSP_EXIT_TIMEOUT
108
+ ) {
109
+ def _after_shutdown(_: Any) {
110
+ if should_exit {
111
+ self.exit_lsp(exit_timeout);
112
+ }
113
+ }
114
+ self._send_request('shutdown', handle_response=_after_shutdown);
115
+ }
116
+
117
+ """Handles LSP server process exit."""
118
+ def exit_lsp(self: LspSession, exit_timeout: Any = LSP_EXIT_TIMEOUT) {
119
+ self._endpoint.notify('exit');
120
+ assert (self._sub.wait(exit_timeout) == 0) ;
121
+ }
122
+
123
+ """Sends text document completion request to LSP server."""
124
+ def text_document_completion(self: LspSession, completion_params: Any) {
125
+ fut = self._send_request('textDocument/completion', params=completion_params);
126
+ return fut.result();
127
+ }
128
+
129
+ """Sends text document rename request to LSP server."""
130
+ def text_document_rename(self: LspSession, rename_params: Any) {
131
+ fut = self._send_request('textDocument/rename', params=rename_params);
132
+ return fut.result();
133
+ }
134
+
135
+ """Sends text document code action request to LSP server."""
136
+ def text_document_code_action(self: LspSession, code_action_params: Any) {
137
+ fut = self._send_request('textDocument/codeAction', params=code_action_params);
138
+ return fut.result();
139
+ }
140
+
141
+ """Sends text document hover request to LSP server."""
142
+ def text_document_hover(self: LspSession, hover_params: Any) {
143
+ fut = self._send_request('textDocument/hover', params=hover_params);
144
+ return fut.result();
145
+ }
146
+
147
+ """Sends text document formatting request to LSP server."""
148
+ def text_document_formatting(self: LspSession, formatting_params: Any) {
149
+ fut = self._send_request('textDocument/formatting', params=formatting_params);
150
+ return fut.result();
151
+ }
152
+
153
+ """Sends text document hover request to LSP server."""
154
+ def text_document_signature_help(self: LspSession, signature_help_params: Any) {
155
+ fut = self._send_request(
156
+ 'textDocument/signatureHelp',
157
+ params=signature_help_params
158
+ );
159
+ return fut.result();
160
+ }
161
+
162
+ """Sends text document declaration request to LSP server."""
163
+ def text_document_declaration(self: LspSession, declaration_params: Any) {
164
+ fut = self._send_request('textDocument/declaration', params=declaration_params);
165
+ return fut.result();
166
+ }
167
+
168
+ """Sends text document definition request to LSP server."""
169
+ def text_document_definition(self: LspSession, definition_params: Any) {
170
+ fut = self._send_request('textDocument/definition', params=definition_params);
171
+ return fut.result();
172
+ }
173
+
174
+ """Sends text document symbol request to LSP server."""
175
+ def text_document_symbol(self: LspSession, document_symbol_params: Any) {
176
+ fut = self._send_request(
177
+ 'textDocument/documentSymbol',
178
+ params=document_symbol_params
179
+ );
180
+ return fut.result();
181
+ }
182
+
183
+ """Sends text document highlight request to LSP server."""
184
+ def text_document_highlight(self: LspSession, document_highlight_params: Any) {
185
+ fut = self._send_request(
186
+ 'textDocument/documentHighlight',
187
+ params=document_highlight_params
188
+ );
189
+ return fut.result();
190
+ }
191
+
192
+ """Sends text document references request to LSP server."""
193
+ def text_document_references(self: LspSession, references_params: Any) {
194
+ fut = self._send_request('textDocument/references', params=references_params);
195
+ return fut.result();
196
+ }
197
+
198
+ """Sends workspace symbol request to LSP server."""
199
+ def workspace_symbol(self: LspSession, workspace_symbol_params: Any) {
200
+ fut = self._send_request('workspace/symbol', params=workspace_symbol_params);
201
+ return fut.result();
202
+ }
203
+
204
+ """Sends completion item resolve request to LSP server."""
205
+ def completion_item_resolve(self: LspSession, resolve_params: Any) {
206
+ fut = self._send_request('completionItem/resolve', params=resolve_params);
207
+ return fut.result();
208
+ }
209
+
210
+ """Sends did change notification to LSP Server."""
211
+ def notify_did_change(self: LspSession, did_change_params: Any) {
212
+ self._send_notification('textDocument/didChange', params=did_change_params);
213
+ }
214
+
215
+ """Sends did save notification to LSP Server."""
216
+ def notify_did_save(self: LspSession, did_save_params: Any) {
217
+ self._send_notification('textDocument/didSave', params=did_save_params);
218
+ }
219
+
220
+ """Sends did open notification to LSP Server."""
221
+ def notify_did_open(self: LspSession, did_open_params: Any) {
222
+ self._send_notification('textDocument/didOpen', params=did_open_params);
223
+ }
224
+
225
+ """Set custom LS notification handler."""
226
+ def set_notification_callback(
227
+ self: LspSession,
228
+ notification_name: Any,
229
+ callback: Any
230
+ ) {
231
+ self._notification_callbacks[notification_name] = callback;
232
+ }
233
+
234
+ """Gets callback if set or default callback for a given LS notification."""
235
+ def get_notification_callback(self: LspSession, notification_name: Any) {
236
+ try {
237
+ return self._notification_callbacks[notification_name];
238
+ } except KeyError {
239
+ def _default_handler(_params: Any) -> None {}
240
+ return _default_handler;
241
+ }
242
+
243
+ }
244
+
245
+ """Internal handler for text document publish diagnostics."""
246
+ def _publish_diagnostics(self: LspSession, publish_diagnostics_params: Any) {
247
+ return self._handle_notification(
248
+ PUBLISH_DIAGNOSTICS,
249
+ publish_diagnostics_params
250
+ );
251
+ }
252
+
253
+ """Internal handler for window log message."""
254
+ def _window_log_message(self: LspSession, window_log_message_params: Any) {
255
+ return self._handle_notification(WINDOW_LOG_MESSAGE, window_log_message_params);
256
+ }
257
+
258
+ """Internal handler for window show message."""
259
+ def _window_show_message(self: LspSession, window_show_message_params: Any) {
260
+ return self._handle_notification(
261
+ WINDOW_SHOW_MESSAGE,
262
+ window_show_message_params
263
+ );
264
+ }
265
+
266
+ """Internal handler for notifications."""
267
+ def _handle_notification(self: LspSession, notification_name: Any, params: Any) {
268
+ fut = Future();
269
+ def _handler() {
270
+ callback = self.get_notification_callback(notification_name);
271
+ callback(params);
272
+ fut.set_result(None);
273
+ }
274
+ self._thread_pool.submit(_handler);
275
+ return fut;
276
+ }
277
+
278
+ """Sends {name} request to the LSP server."""
279
+ def _send_request(
280
+ self: LspSession,
281
+ name: Any,
282
+ params: Any = None,
283
+ handle_response: Any = lambda f: Any: f.done()
284
+ ) {
285
+ fut = self._endpoint.request(name, params);
286
+ fut.add_done_callback(handle_response);
287
+ return fut;
288
+ }
289
+
290
+ """Sends {name} notification to the LSP server."""
291
+ def _send_notification(self: LspSession, name: Any, params: Any = None) {
292
+ self._endpoint.notify(name, params);
293
+ }
294
+ }
@@ -2,9 +2,9 @@
2
2
 
3
3
  import copy
4
4
  import lsprotocol.types as lspt
5
-
6
- from jaclang.langserve.sem_manager import SemTokManager
5
+ from jaclang import JacMachineInterface as _
7
6
  from jaclang.utils.test import TestCase
7
+ from jaclang.langserve.sem_manager import SemTokManager
8
8
 
9
9
  from typing import Tuple
10
10