jaclang 0.8.7__py3-none-any.whl → 0.8.9__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 (99) hide show
  1. jaclang/cli/cli.py +77 -29
  2. jaclang/cli/cmdreg.py +44 -0
  3. jaclang/compiler/constant.py +6 -2
  4. jaclang/compiler/jac.lark +37 -47
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +356 -61
  7. jaclang/compiler/passes/main/__init__.py +2 -4
  8. jaclang/compiler/passes/main/def_use_pass.py +1 -4
  9. jaclang/compiler/passes/main/predynamo_pass.py +221 -0
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +221 -135
  11. jaclang/compiler/passes/main/pyast_load_pass.py +54 -20
  12. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  13. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
  14. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
  22. jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
  23. jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
  24. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
  25. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
  26. jaclang/compiler/passes/main/tests/test_checker_pass.py +190 -0
  27. jaclang/compiler/passes/main/tests/test_predynamo_pass.py +56 -0
  28. jaclang/compiler/passes/main/type_checker_pass.py +29 -73
  29. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +302 -58
  30. jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
  31. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  32. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
  33. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
  34. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +276 -10
  35. jaclang/compiler/passes/transform.py +12 -8
  36. jaclang/compiler/program.py +19 -7
  37. jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
  38. jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
  39. jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
  40. jaclang/compiler/tests/fixtures/python_module.py +1 -0
  41. jaclang/compiler/tests/test_importer.py +39 -0
  42. jaclang/compiler/tests/test_parser.py +49 -0
  43. jaclang/compiler/type_system/type_evaluator.jac +959 -0
  44. jaclang/compiler/type_system/type_utils.py +246 -0
  45. jaclang/compiler/type_system/types.py +58 -2
  46. jaclang/compiler/unitree.py +102 -107
  47. jaclang/langserve/engine.jac +138 -159
  48. jaclang/langserve/server.jac +25 -1
  49. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  50. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  51. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  52. jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
  53. jaclang/langserve/tests/server_test/circle_template.jac +80 -0
  54. jaclang/langserve/tests/server_test/glob_template.jac +4 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
  56. jaclang/langserve/tests/server_test/utils.py +153 -116
  57. jaclang/langserve/tests/test_server.py +21 -84
  58. jaclang/langserve/utils.jac +12 -15
  59. jaclang/lib.py +17 -0
  60. jaclang/runtimelib/archetype.py +25 -25
  61. jaclang/runtimelib/constructs.py +2 -2
  62. jaclang/runtimelib/machine.py +63 -46
  63. jaclang/runtimelib/meta_importer.py +27 -1
  64. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  65. jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
  66. jaclang/settings.py +19 -16
  67. jaclang/tests/fixtures/abc_check.jac +3 -3
  68. jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
  69. jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
  70. jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
  71. jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
  72. jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
  73. jaclang/tests/fixtures/funccall_genexpr.py +5 -0
  74. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  75. jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
  76. jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
  77. jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
  78. jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
  79. jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
  80. jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
  81. jaclang/tests/fixtures/py2jac_params.py +8 -0
  82. jaclang/tests/fixtures/run_test.jac +4 -4
  83. jaclang/tests/test_cli.py +159 -7
  84. jaclang/tests/test_language.py +213 -38
  85. jaclang/tests/test_reference.py +3 -1
  86. jaclang/utils/helpers.py +67 -6
  87. jaclang/utils/module_resolver.py +10 -0
  88. jaclang/utils/test.py +8 -0
  89. jaclang/utils/tests/test_lang_tools.py +4 -15
  90. jaclang/utils/treeprinter.py +0 -18
  91. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/METADATA +1 -2
  92. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/RECORD +95 -65
  93. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/WHEEL +1 -1
  94. jaclang/compiler/passes/main/inheritance_pass.py +0 -131
  95. jaclang/compiler/type_system/type_evaluator.py +0 -560
  96. jaclang/langserve/dev_engine.jac +0 -645
  97. jaclang/langserve/dev_server.jac +0 -201
  98. /jaclang/{langserve/tests/server_test/code_test.py → tests/fixtures/py2jac_empty.py} +0 -0
  99. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/entry_points.txt +0 -0
@@ -1,350 +1,195 @@
1
- """Test for Jac language server[VSCE] features"""
1
+ """Test suite for Jac language server features."""
2
2
 
3
- import os
4
3
  import pytest
5
4
 
6
5
  from lsprotocol.types import (
7
- DidOpenTextDocumentParams,
8
- TextDocumentItem,
9
- DidSaveTextDocumentParams,
10
- DidChangeTextDocumentParams,
11
6
  DocumentFormattingParams,
12
7
  TextEdit,
13
- VersionedTextDocumentIdentifier,
14
8
  TextDocumentIdentifier,
15
9
  )
16
10
  from jaclang.langserve.tests.server_test.utils import (
17
- create_temp_jac_file,
18
- get_code,
19
- get_simple_code,
20
- create_ls_with_workspace, # new helper
11
+ TestFile,
12
+ LanguageServerTestHelper,
13
+ create_ls_with_workspace,
14
+ load_jac_template,
21
15
  )
22
16
  from jaclang.vendor.pygls.uris import from_fs_path
23
- from jaclang.vendor.pygls.workspace import Workspace
24
- from jaclang import JacMachineInterface as _
25
- from jaclang.langserve.engine import JacLangServer
26
- from jaclang.langserve.server import did_open, did_save, did_change, formatting
17
+ from jaclang.langserve.server import formatting
27
18
 
28
19
 
29
20
  class TestLangServe:
30
- """Test class for Jac language server features."""
31
-
21
+ """Test suite for Jac language server features."""
22
+
23
+ CIRCLE_TEMPLATE = "circle_template.jac"
24
+ GLOB_TEMPLATE = "glob_template.jac"
25
+ EXPECTED_CIRCLE_TOKEN_COUNT = 340
26
+ EXPECTED_GLOB_TOKEN_COUNT = 15
27
+
32
28
  @pytest.mark.asyncio
33
29
  async def test_open_valid_file_no_diagnostics(self):
34
- """Test opening a Jac file with a syntax error."""
35
- ls = JacLangServer()
36
-
37
- code = get_code("")
38
- temp_file_path = create_temp_jac_file(code)
39
- uri = from_fs_path(temp_file_path)
40
- ls.lsp._workspace = Workspace(os.path.dirname(temp_file_path), ls)
41
-
42
- params = DidOpenTextDocumentParams(
43
- text_document=TextDocumentItem(
44
- uri=uri,
45
- language_id="jac",
46
- version=1,
47
- text=code,
48
- )
49
- )
50
- await did_open(ls, params)
51
-
52
- diagnostics = ls.diagnostics.get(uri, [])
30
+ """Test opening a valid Jac file produces no diagnostics."""
31
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE)
32
+ uri, ls = create_ls_with_workspace(test_file.path)
33
+ test_file.uri = uri
34
+ helper = LanguageServerTestHelper(ls, test_file)
35
+
36
+ await helper.open_document()
37
+ helper.assert_no_diagnostics()
38
+
53
39
  ls.shutdown()
54
- assert len(diagnostics) == 0
55
-
56
- os.remove(temp_file_path)
57
-
40
+ test_file.cleanup()
41
+
58
42
  @pytest.mark.asyncio
59
43
  async def test_open_with_syntax_error(self):
60
- """Test opening a Jac file with a syntax error."""
61
- ls = JacLangServer()
62
-
63
- code = get_code("error")
64
- temp_file_path = create_temp_jac_file(code)
65
- uri = from_fs_path(temp_file_path)
66
- ls.lsp._workspace = Workspace(os.path.dirname(temp_file_path), ls)
67
-
68
- params = DidOpenTextDocumentParams(
69
- text_document=TextDocumentItem(
70
- uri=uri,
71
- language_id="jac",
72
- version=1,
73
- text=code,
74
- )
75
- )
76
- await did_open(ls, params)
77
-
78
- diagnostics = ls.diagnostics.get(uri, [])
44
+ """Test opening a Jac file with syntax error produces diagnostics."""
45
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE, "error")
46
+ uri, ls = create_ls_with_workspace(test_file.path)
47
+ if uri:
48
+ test_file.uri = uri
49
+ helper = LanguageServerTestHelper(ls, test_file)
50
+
51
+ await helper.open_document()
52
+ helper.assert_has_diagnostics(count=1, message_contains="Unexpected token 'error'")
53
+
54
+ diagnostics = helper.get_diagnostics()
55
+ assert str(diagnostics[0].range) == "65:0-65:5"
56
+
79
57
  ls.shutdown()
80
- assert len(diagnostics) == 1
81
- assert diagnostics[0].message == "Syntax Error"
82
- assert str(diagnostics[0].range) == "66:0-66:1"
83
-
84
- os.remove(temp_file_path)
85
-
58
+ test_file.cleanup()
59
+
86
60
  @pytest.mark.asyncio
87
61
  async def test_did_open_and_simple_syntax_error(self):
88
- """Test diagnostics for a Jac file with a syntax error."""
89
- ls = JacLangServer()
90
-
91
- code = get_code("")
92
- temp_file_path = create_temp_jac_file(code)
93
- uri = from_fs_path(temp_file_path)
94
- ls.lsp._workspace = Workspace(os.path.dirname(temp_file_path), ls)
95
-
96
- params = DidOpenTextDocumentParams(
97
- text_document=TextDocumentItem(
98
- uri=uri,
99
- language_id="jac",
100
- version=1,
101
- text=code,
102
- )
103
- )
104
- await did_open(ls, params)
105
- diagnostics = ls.diagnostics.get(uri, [])
106
- assert isinstance(diagnostics, list)
107
- assert len(diagnostics) == 0
108
-
109
- broken_code = get_code("error")
110
- with open(temp_file_path, "w") as f:
111
- f.write(broken_code)
112
- params = DidOpenTextDocumentParams(
113
- text_document=TextDocumentItem(
114
- uri=uri,
115
- language_id="jac",
116
- version=1,
117
- text=broken_code,
118
- )
119
- )
120
- await did_open(ls, params)
121
- diagnostics = ls.diagnostics.get(uri, [])
122
- assert isinstance(diagnostics, list)
123
- assert len(diagnostics) == 1
124
-
125
- sem_tokens = ls.get_semantic_tokens(uri)
126
- print(sem_tokens)
62
+ """Test diagnostics evolution from valid to invalid code."""
63
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE)
64
+ uri, ls = create_ls_with_workspace(test_file.path)
65
+ test_file.uri = uri
66
+ helper = LanguageServerTestHelper(ls, test_file)
67
+
68
+ # Open valid file
69
+ print("Opening valid file...")
70
+ await helper.open_document()
71
+ helper.assert_no_diagnostics()
72
+
73
+ # Introduce syntax error
74
+ broken_code = load_jac_template(
75
+ test_file._get_template_path(self.CIRCLE_TEMPLATE),
76
+ "error"
77
+ )
78
+ await helper.change_document(broken_code)
79
+ helper.assert_has_diagnostics(count=1)
80
+ helper.assert_semantic_tokens_count(self.EXPECTED_CIRCLE_TOKEN_COUNT)
81
+
127
82
  ls.shutdown()
128
- assert hasattr(sem_tokens, "data")
129
- assert isinstance(sem_tokens.data, list)
130
- assert (
131
- len(sem_tokens.data) == 0
132
- ) # TODO: we should retain the sem tokens, will be fixed in next PR
133
-
134
- os.remove(temp_file_path)
135
-
83
+ test_file.cleanup()
84
+
136
85
  @pytest.mark.asyncio
137
86
  async def test_did_save(self):
138
- """Test saving a Jac file triggers diagnostics."""
139
- code = get_code("")
140
- temp_file_path = create_temp_jac_file(code)
141
- uri, ls = create_ls_with_workspace(temp_file_path)
142
-
143
- await did_open(
144
- ls,
145
- DidOpenTextDocumentParams(
146
- text_document=TextDocumentItem(
147
- uri=uri,
148
- language_id="jac",
149
- version=1,
150
- text=code,
151
- )
152
- ),
153
- )
154
-
155
- params = DidSaveTextDocumentParams(
156
- text_document=TextDocumentItem(
157
- uri=uri,
158
- language_id="jac",
159
- version=2,
160
- text=code,
161
- )
162
- )
163
-
164
- await did_save(ls, params)
165
- diagnostics = ls.diagnostics.get(uri, [])
166
- assert isinstance(diagnostics, list)
167
- assert len(diagnostics) == 0
168
-
169
- # Now simulate a syntax error by updating the workspace and saving
170
- broken_code = get_code("error")
171
- ls.workspace.put_text_document(
172
- TextDocumentItem(
173
- uri=uri,
174
- language_id="jac",
175
- version=3,
176
- text=broken_code,
177
- )
178
- )
179
- params = DidSaveTextDocumentParams(
180
- text_document=TextDocumentItem(
181
- uri=uri,
182
- language_id="jac",
183
- version=3,
184
- text=broken_code,
185
- )
186
- )
187
- await did_save(ls, params)
188
- sem_tokens = ls.get_semantic_tokens(uri)
189
- # semantic tokens should still be present even if there is a syntax error
190
- assert len(sem_tokens.data) == 340
191
- diagnostics = ls.diagnostics.get(uri, [])
192
- assert isinstance(diagnostics, list)
193
- assert len(diagnostics) == 1
194
- assert diagnostics[0].message == "Syntax Error"
195
-
87
+ """Test saving a Jac file triggers appropriate diagnostics."""
88
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE)
89
+ uri, ls = create_ls_with_workspace(test_file.path)
90
+ if uri:
91
+ test_file.uri = uri
92
+ helper = LanguageServerTestHelper(ls, test_file)
93
+
94
+ await helper.open_document()
95
+ await helper.save_document()
96
+ helper.assert_no_diagnostics()
97
+
98
+ # Save with syntax error
99
+ broken_code = load_jac_template(
100
+ test_file._get_template_path(self.CIRCLE_TEMPLATE),
101
+ "error"
102
+ )
103
+ await helper.save_document(broken_code)
104
+ helper.assert_semantic_tokens_count(self.EXPECTED_CIRCLE_TOKEN_COUNT)
105
+ helper.assert_has_diagnostics(count=1, message_contains="Unexpected token 'error'")
106
+
196
107
  ls.shutdown()
197
- os.remove(temp_file_path)
198
-
108
+ test_file.cleanup()
109
+
199
110
  @pytest.mark.asyncio
200
111
  async def test_did_change(self):
201
112
  """Test changing a Jac file triggers diagnostics."""
202
- code = get_code("")
203
- temp_file_path = create_temp_jac_file(code)
204
- uri, ls = create_ls_with_workspace(temp_file_path)
205
-
206
- await did_open(
207
- ls,
208
- DidOpenTextDocumentParams(
209
- text_document=TextDocumentItem(
210
- uri=uri,
211
- language_id="jac",
212
- version=1,
213
- text=code,
214
- )
215
- ),
216
- )
217
-
218
- # No error, should be no diagnostics
219
- params = DidChangeTextDocumentParams(
220
- text_document=VersionedTextDocumentIdentifier(uri=uri, version=2),
221
- content_changes=[{"text": "\n" + code}],
222
- )
223
- ls.workspace.put_text_document(
224
- TextDocumentItem(
225
- uri=uri,
226
- language_id="jac",
227
- version=2,
228
- text="\n" + code,
229
- )
230
- )
231
- await did_change(ls, params)
232
- diagnostics = ls.diagnostics.get(uri, [])
233
- assert isinstance(diagnostics, list)
234
- assert len(diagnostics) == 0
235
-
236
- # Now add a syntax error and update workspace
237
- # This should trigger diagnostics with a syntax error
238
- error_code = "\nerror"
239
- params = DidChangeTextDocumentParams(
240
- text_document=VersionedTextDocumentIdentifier(uri=uri, version=3),
241
- content_changes=[{"text": error_code + code}],
242
- )
243
- ls.workspace.put_text_document(
244
- TextDocumentItem(
245
- uri=uri,
246
- language_id="jac",
247
- version=3,
248
- text=error_code + code,
249
- )
250
- )
251
- await did_change(ls, params)
252
- sem_tokens = ls.get_semantic_tokens(uri)
253
- # semantic tokens should still be present even if there is a syntax error
254
- assert len(sem_tokens.data) == 340
255
- diagnostics = ls.diagnostics.get(uri, [])
256
- assert isinstance(diagnostics, list)
257
- assert len(diagnostics) == 1
258
- assert diagnostics[0].message == "Syntax Error"
259
-
113
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE)
114
+ uri, ls = create_ls_with_workspace(test_file.path)
115
+ if uri:
116
+ test_file.uri = uri
117
+ helper = LanguageServerTestHelper(ls, test_file)
118
+
119
+ await helper.open_document()
120
+
121
+ # Change without error
122
+ await helper.change_document("\n" + test_file.code)
123
+ helper.assert_no_diagnostics()
124
+
125
+ # Change with syntax error
126
+ await helper.change_document("\nerror" + test_file.code)
127
+ helper.assert_semantic_tokens_count(self.EXPECTED_CIRCLE_TOKEN_COUNT)
128
+ helper.assert_has_diagnostics(count=1, message_contains="Unexpected token")
129
+
260
130
  ls.shutdown()
261
- os.remove(temp_file_path)
262
-
131
+ test_file.cleanup()
132
+
263
133
  def test_vsce_formatting(self):
264
- """Test formatting a Jac file returns edits."""
265
- code = get_code("")
266
- temp_file_path = create_temp_jac_file(code)
267
- uri, ls = create_ls_with_workspace(temp_file_path)
134
+ """Test formatting a Jac file returns valid edits."""
135
+ test_file = TestFile.from_template(self.CIRCLE_TEMPLATE)
136
+ uri, ls = create_ls_with_workspace(test_file.path)
137
+
138
+ from lsprotocol.types import FormattingOptions
139
+
268
140
  params = DocumentFormattingParams(
269
- text_document=TextDocumentIdentifier(uri=uri),
270
- options={"tabSize": 4, "insertSpaces": True},
141
+ text_document=TextDocumentIdentifier(uri=uri or ""),
142
+ options=FormattingOptions(tab_size=4, insert_spaces=True),
271
143
  )
272
144
  edits = formatting(ls, params)
145
+
273
146
  assert isinstance(edits, list)
147
+ assert len(edits) > 0
274
148
  assert isinstance(edits[0], TextEdit)
275
- assert (
276
- len(edits[0].new_text) > 100
277
- ) # it is a random number to check if the text is changed
278
- print(edits[0].new_text)
149
+ assert len(edits[0].new_text) > 100
150
+
279
151
  ls.shutdown()
280
- os.remove(temp_file_path)
281
-
152
+ test_file.cleanup()
153
+
282
154
  @pytest.mark.asyncio
283
155
  async def test_multifile_workspace(self):
284
156
  """Test opening multiple Jac files in a workspace."""
285
- code1 = get_simple_code("")
286
- code2 = get_simple_code("error")
287
- temp_file_path1 = create_temp_jac_file(code1)
288
- temp_file_path2 = create_temp_jac_file(code2)
289
-
290
- uri1, ls = create_ls_with_workspace(temp_file_path1)
291
- uri2 = from_fs_path(temp_file_path2)
292
-
293
- await did_open(
294
- ls,
295
- DidOpenTextDocumentParams(
296
- text_document=TextDocumentItem(
297
- uri=uri1,
298
- language_id="jac",
299
- version=1,
300
- text=code1,
301
- )
302
- ),
303
- )
304
- await did_open(
305
- ls,
306
- DidOpenTextDocumentParams(
307
- text_document=TextDocumentItem(
308
- uri=uri2,
309
- language_id="jac",
310
- version=1,
311
- text=code2,
312
- )
313
- ),
314
- )
315
-
316
- diagnostics1 = ls.diagnostics.get(uri1, [])
317
- diagnostics2 = ls.diagnostics.get(uri2, [])
318
- assert len(diagnostics1) == 0
319
- assert len(diagnostics2) == 1
320
- assert diagnostics2[0].message == "Syntax Error"
321
-
322
- before_sem_tokens_1 = ls.get_semantic_tokens(uri1)
323
- before_sem_tokens_2 = ls.get_semantic_tokens(uri2)
324
- assert len(before_sem_tokens_1.data) == 15
325
- assert len(before_sem_tokens_2.data) == 0
326
-
327
- changed_code = get_simple_code("glob x = 90;")
328
- ls.workspace.put_text_document(
329
- TextDocumentItem(
330
- uri=uri1,
331
- language_id="jac",
332
- version=2,
333
- text=changed_code,
334
- )
335
- )
336
- params = DidChangeTextDocumentParams(
337
- text_document=VersionedTextDocumentIdentifier(uri=uri1, version=2),
338
- content_changes=[{"text": changed_code}],
339
- )
340
- await did_change(ls, params)
341
-
342
- after_sem_tokens_1 = ls.get_semantic_tokens(uri1)
343
- after_sem_tokens_2 = ls.get_semantic_tokens(uri2)
344
-
345
- assert len(after_sem_tokens_1.data) == 20
346
- assert len(after_sem_tokens_2.data) == 0
347
-
157
+ file1 = TestFile.from_template(self.GLOB_TEMPLATE)
158
+ file2 = TestFile.from_template(self.GLOB_TEMPLATE, "error")
159
+
160
+ uri1, ls = create_ls_with_workspace(file1.path)
161
+ if uri1:
162
+ file1.uri = uri1
163
+ file2_uri = from_fs_path(file2.path)
164
+ if file2_uri:
165
+ file2.uri = file2_uri
166
+
167
+ helper1 = LanguageServerTestHelper(ls, file1)
168
+ helper2 = LanguageServerTestHelper(ls, file2)
169
+
170
+ # Open both files
171
+ await helper1.open_document()
172
+ await helper2.open_document()
173
+
174
+ # Verify initial state
175
+ helper1.assert_no_diagnostics()
176
+ helper2.assert_has_diagnostics(count=1, message_contains="Unexpected token")
177
+
178
+ # Check semantic tokens before change
179
+ helper1.assert_semantic_tokens_count(self.EXPECTED_GLOB_TOKEN_COUNT)
180
+ helper2.assert_semantic_tokens_count(self.EXPECTED_GLOB_TOKEN_COUNT)
181
+
182
+ # Change first file
183
+ changed_code = load_jac_template(
184
+ file1._get_template_path(self.GLOB_TEMPLATE),
185
+ "glob x = 90;"
186
+ )
187
+ await helper1.change_document(changed_code)
188
+
189
+ # Verify semantic tokens after change
190
+ helper1.assert_semantic_tokens_count(20)
191
+ helper2.assert_semantic_tokens_count(self.EXPECTED_GLOB_TOKEN_COUNT)
192
+
348
193
  ls.shutdown()
349
- os.remove(temp_file_path1)
350
- os.remove(temp_file_path2)
194
+ file1.cleanup()
195
+ file2.cleanup()