jaclang 0.7.9__py3-none-any.whl → 0.7.13__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 (35) hide show
  1. jaclang/cli/cli.py +13 -3
  2. jaclang/compiler/absyntree.py +10 -2
  3. jaclang/compiler/parser.py +2 -1
  4. jaclang/compiler/passes/ir_pass.py +9 -0
  5. jaclang/compiler/passes/main/import_pass.py +15 -2
  6. jaclang/compiler/passes/main/pyast_gen_pass.py +238 -32
  7. jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
  8. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -0
  9. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -2
  10. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
  11. jaclang/compiler/passes/main/type_check_pass.py +0 -17
  12. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
  13. jaclang/compiler/tests/test_importer.py +1 -1
  14. jaclang/core/importer.py +233 -62
  15. jaclang/langserve/engine.py +182 -136
  16. jaclang/langserve/server.py +29 -7
  17. jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -2
  18. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  19. jaclang/langserve/tests/test_server.py +73 -66
  20. jaclang/langserve/utils.py +266 -0
  21. jaclang/plugin/default.py +7 -4
  22. jaclang/plugin/feature.py +3 -3
  23. jaclang/plugin/spec.py +3 -3
  24. jaclang/settings.py +1 -0
  25. jaclang/tests/fixtures/deep/one_lev.jac +6 -4
  26. jaclang/tests/fixtures/needs_import.jac +1 -1
  27. jaclang/tests/test_cli.py +7 -9
  28. jaclang/tests/test_language.py +9 -13
  29. jaclang/tests/test_man_code.py +8 -10
  30. jaclang/utils/helpers.py +3 -3
  31. jaclang/utils/test.py +8 -0
  32. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/METADATA +2 -2
  33. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/RECORD +35 -35
  34. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/WHEEL +0 -0
  35. {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/entry_points.txt +0 -0
@@ -5,23 +5,27 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  import logging
7
7
  from concurrent.futures import ThreadPoolExecutor
8
- from enum import IntEnum
9
- from typing import Optional
8
+ from typing import Callable, Optional
10
9
 
11
10
 
12
11
  import jaclang.compiler.absyntree as ast
13
- from jaclang.compiler.compile import jac_ir_to_pass, jac_str_to_pass
12
+ from jaclang.compiler.compile import jac_str_to_pass
14
13
  from jaclang.compiler.parser import JacParser
15
14
  from jaclang.compiler.passes import Pass
16
- from jaclang.compiler.passes.main.schedules import type_checker_sched
15
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
17
16
  from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
18
17
  from jaclang.compiler.passes.transform import Alert
19
18
  from jaclang.langserve.utils import (
19
+ collect_all_symbols_in_scope,
20
20
  collect_symbols,
21
21
  create_range,
22
22
  find_deepest_symbol_node_at_pos,
23
+ gen_diagnostics,
23
24
  get_item_path,
24
25
  get_mod_path,
26
+ locate_affected_token,
27
+ parse_symbol_path,
28
+ resolve_completion_symbol_table,
25
29
  )
26
30
  from jaclang.vendor.pygls import uris
27
31
  from jaclang.vendor.pygls.server import LanguageServer
@@ -29,14 +33,6 @@ from jaclang.vendor.pygls.server import LanguageServer
29
33
  import lsprotocol.types as lspt
30
34
 
31
35
 
32
- class ALev(IntEnum):
33
- """Analysis Level successfully completed."""
34
-
35
- QUICK = 1
36
- DEEP = 2
37
- TYPE = 3
38
-
39
-
40
36
  class ModuleInfo:
41
37
  """Module IR and Stats."""
42
38
 
@@ -45,16 +41,11 @@ class ModuleInfo:
45
41
  ir: ast.Module,
46
42
  errors: list[Alert],
47
43
  warnings: list[Alert],
48
- alev: ALev,
49
44
  parent: Optional[ModuleInfo] = None,
50
45
  ) -> None:
51
46
  """Initialize module info."""
52
47
  self.ir = ir
53
- self.errors = errors
54
- self.warnings = warnings
55
- self.alev = alev
56
48
  self.parent: Optional[ModuleInfo] = parent
57
- self.diagnostics = self.gen_diagnostics()
58
49
  self.sem_tokens: list[int] = self.gen_sem_tokens()
59
50
 
60
51
  @property
@@ -62,43 +53,6 @@ class ModuleInfo:
62
53
  """Return uri."""
63
54
  return uris.from_fs_path(self.ir.loc.mod_path)
64
55
 
65
- @property
66
- def has_syntax_error(self) -> bool:
67
- """Return if there are syntax errors."""
68
- return len(self.errors) > 0 and self.alev == ALev.QUICK
69
-
70
- def update_with(self, new_info: ModuleInfo, refresh: bool = False) -> None:
71
- """Update module info."""
72
- self.ir = new_info.ir
73
- if refresh:
74
- self.errors = new_info.errors
75
- self.warnings = new_info.warnings
76
- else:
77
- self.errors += [i for i in new_info.errors if i not in self.errors]
78
- self.warnings += [i for i in new_info.warnings if i not in self.warnings]
79
- self.alev = new_info.alev
80
- self.diagnostics = self.gen_diagnostics()
81
- if self.alev == ALev.TYPE:
82
- self.sem_tokens = self.gen_sem_tokens()
83
-
84
- def gen_diagnostics(self) -> list[lspt.Diagnostic]:
85
- """Return diagnostics."""
86
- return [
87
- lspt.Diagnostic(
88
- range=create_range(error.loc),
89
- message=error.msg,
90
- severity=lspt.DiagnosticSeverity.Error,
91
- )
92
- for error in self.errors
93
- ] + [
94
- lspt.Diagnostic(
95
- range=create_range(warning.loc),
96
- message=warning.msg,
97
- severity=lspt.DiagnosticSeverity.Warning,
98
- )
99
- for warning in self.warnings
100
- ]
101
-
102
56
  def gen_sem_tokens(self) -> list[int]:
103
57
  """Return semantic tokens."""
104
58
  tokens = []
@@ -120,6 +74,76 @@ class ModuleInfo:
120
74
  prev_line, prev_col = line, col_start
121
75
  return tokens
122
76
 
77
+ def update_sem_tokens(
78
+ self, content_changes: lspt.DidChangeTextDocumentParams
79
+ ) -> list[int]:
80
+ """Update semantic tokens on change."""
81
+ for change in [
82
+ x
83
+ for x in content_changes.content_changes
84
+ if isinstance(x, lspt.TextDocumentContentChangeEvent_Type1)
85
+ ]:
86
+ change_start_line = change.range.start.line
87
+ change_start_char = change.range.start.character
88
+ change_end_line = change.range.end.line
89
+ change_end_char = change.range.end.character
90
+
91
+ line_delta = change.text.count("\n") - (change_end_line - change_start_line)
92
+ if line_delta == 0:
93
+ char_delta = len(change.text) - (change_end_char - change_start_char)
94
+ else:
95
+ last_newline_index = change.text.rfind("\n")
96
+ char_delta = (
97
+ len(change.text)
98
+ - last_newline_index
99
+ - 1
100
+ - change_end_char
101
+ + change_start_char
102
+ )
103
+
104
+ changed_token_index = locate_affected_token(
105
+ self.sem_tokens,
106
+ change_start_line,
107
+ change_start_char,
108
+ change_end_line,
109
+ change_end_char,
110
+ )
111
+ if changed_token_index:
112
+ self.sem_tokens[changed_token_index + 2] = max(
113
+ 1, self.sem_tokens[changed_token_index + 2] + char_delta
114
+ )
115
+ if (
116
+ len(self.sem_tokens) > changed_token_index + 5
117
+ and self.sem_tokens[changed_token_index + 5] == 0
118
+ ):
119
+ next_token_index = changed_token_index + 5
120
+ self.sem_tokens[next_token_index + 1] = max(
121
+ 0, self.sem_tokens[next_token_index + 1] + char_delta
122
+ )
123
+ return self.sem_tokens
124
+
125
+ current_token_index = 0
126
+ line_offset = 0
127
+ while current_token_index < len(self.sem_tokens):
128
+ token_line_number = self.sem_tokens[current_token_index] + line_offset
129
+ token_start_pos = self.sem_tokens[current_token_index + 1]
130
+
131
+ if token_line_number > change_start_line or (
132
+ token_line_number == change_start_line
133
+ and token_start_pos >= change_start_char
134
+ ):
135
+ self.sem_tokens[current_token_index] += line_delta
136
+ if token_line_number == change_start_line:
137
+ self.sem_tokens[current_token_index + 1] += char_delta
138
+ if token_line_number > change_end_line or (
139
+ token_line_number == change_end_line
140
+ and token_start_pos >= change_end_char
141
+ ):
142
+ break
143
+ line_offset += self.sem_tokens[current_token_index]
144
+ current_token_index += 5
145
+ return self.sem_tokens
146
+
123
147
 
124
148
  class JacLangServer(LanguageServer):
125
149
  """Class for managing workspace."""
@@ -129,36 +153,16 @@ class JacLangServer(LanguageServer):
129
153
  super().__init__("jac-lsp", "v0.1")
130
154
  self.modules: dict[str, ModuleInfo] = {}
131
155
  self.executor = ThreadPoolExecutor()
132
-
133
- async def push_diagnostics(self, file_path: str) -> None:
134
- """Push diagnostics for a file."""
135
- if file_path in self.modules:
136
- self.publish_diagnostics(
137
- file_path,
138
- self.modules[file_path].diagnostics,
139
- )
140
-
141
- def unwind_to_parent(self, file_path: str) -> str:
142
- """Unwind to parent."""
143
- orig_file_path = file_path
144
- if file_path in self.modules:
145
- while cur := self.modules[file_path].parent:
146
- file_path = cur.uri
147
- if file_path == orig_file_path and (
148
- discover := self.modules[file_path].ir.annexable_by
149
- ):
150
- file_path = uris.from_fs_path(discover)
151
- self.quick_check(file_path)
152
- return file_path
156
+ self.tasks: dict[str, asyncio.Task] = {}
153
157
 
154
158
  def update_modules(
155
- self, file_path: str, build: Pass, alev: ALev, refresh: bool = False
159
+ self, file_path: str, build: Pass, refresh: bool = False
156
160
  ) -> None:
157
161
  """Update modules."""
158
162
  if not isinstance(build.ir, ast.Module):
159
163
  self.log_error("Error with module build.")
160
164
  return
161
- new_mod = ModuleInfo(
165
+ self.modules[file_path] = ModuleInfo(
162
166
  ir=build.ir,
163
167
  errors=[
164
168
  i
@@ -170,24 +174,14 @@ class JacLangServer(LanguageServer):
170
174
  for i in build.warnings_had
171
175
  if i.loc.mod_path == uris.to_fs_path(file_path)
172
176
  ],
173
- alev=alev,
174
177
  )
175
- if file_path in self.modules:
176
- self.modules[file_path].update_with(new_mod, refresh=refresh)
177
- else:
178
- self.modules[file_path] = new_mod
179
178
  for p in build.ir.mod_deps.keys():
180
179
  uri = uris.from_fs_path(p)
181
- new_mod = ModuleInfo(
180
+ self.modules[uri] = ModuleInfo(
182
181
  ir=build.ir.mod_deps[p],
183
182
  errors=[i for i in build.errors_had if i.loc.mod_path == p],
184
183
  warnings=[i for i in build.warnings_had if i.loc.mod_path == p],
185
- alev=alev,
186
184
  )
187
- if not refresh and uri in self.modules:
188
- self.modules[uri].update_with(new_mod)
189
- else:
190
- self.modules[uri] = new_mod
191
185
  self.modules[uri].parent = (
192
186
  self.modules[file_path] if file_path != uri else None
193
187
  )
@@ -199,72 +193,100 @@ class JacLangServer(LanguageServer):
199
193
  build = jac_str_to_pass(
200
194
  jac_str=document.source, file_path=document.path, schedule=[]
201
195
  )
196
+ self.publish_diagnostics(
197
+ file_path,
198
+ gen_diagnostics(file_path, build.errors_had, build.warnings_had),
199
+ )
200
+ return len(build.errors_had) == 0
202
201
  except Exception as e:
203
202
  self.log_error(f"Error during syntax check: {e}")
204
203
  return False
205
- self.update_modules(file_path, build, ALev.QUICK, refresh=True)
206
- return len(self.modules[file_path].errors) == 0
207
-
208
- def deep_check(self, file_path: str) -> bool:
209
- """Rebuild a file and its dependencies."""
210
- if file_path not in self.modules:
211
- self.quick_check(file_path)
212
- try:
213
- file_path = self.unwind_to_parent(file_path)
214
- build = jac_ir_to_pass(ir=self.modules[file_path].ir)
215
- except Exception as e:
216
- self.log_error(f"Error during syntax check: {e}")
217
- return False
218
- self.update_modules(file_path, build, ALev.DEEP)
219
- return len(self.modules[file_path].errors) == 0
220
204
 
221
- def type_check(self, file_path: str) -> bool:
205
+ def deep_check(self, file_path: str, annex_view: Optional[str] = None) -> bool:
222
206
  """Rebuild a file and its dependencies."""
223
- if file_path not in self.modules:
224
- self.deep_check(file_path)
225
207
  try:
226
- file_path = self.unwind_to_parent(file_path)
227
- build = jac_ir_to_pass(
228
- ir=self.modules[file_path].ir, schedule=type_checker_sched
208
+ document = self.workspace.get_text_document(file_path)
209
+ build = jac_str_to_pass(
210
+ jac_str=document.source,
211
+ file_path=document.path,
212
+ schedule=py_code_gen_typed,
213
+ )
214
+ self.update_modules(file_path, build)
215
+ if discover := self.modules[file_path].ir.annexable_by:
216
+ return self.deep_check(
217
+ uris.from_fs_path(discover), annex_view=file_path
218
+ )
219
+ self.publish_diagnostics(
220
+ file_path,
221
+ gen_diagnostics(
222
+ annex_view if annex_view else file_path,
223
+ build.errors_had,
224
+ build.warnings_had,
225
+ ),
229
226
  )
227
+ return len(build.errors_had) == 0
230
228
  except Exception as e:
231
- self.log_error(f"Error during type check: {e}")
229
+ self.log_error(f"Error during deep check: {e}")
232
230
  return False
233
- self.update_modules(file_path, build, ALev.TYPE)
234
- return len(self.modules[file_path].errors) == 0
235
231
 
236
- async def analyze_and_publish(self, uri: str, level: int = 2) -> None:
232
+ async def launch_quick_check(self, uri: str) -> None:
237
233
  """Analyze and publish diagnostics."""
238
- self.log_py(f"Analyzing {uri}...")
239
- success = await asyncio.get_event_loop().run_in_executor(
234
+ await asyncio.get_event_loop().run_in_executor(
240
235
  self.executor, self.quick_check, uri
241
236
  )
242
- await self.push_diagnostics(uri)
243
- if success and level > 0:
244
- success = await asyncio.get_event_loop().run_in_executor(
245
- self.executor, self.deep_check, uri
246
- )
247
- await self.push_diagnostics(uri)
248
- if level > 1:
249
- await asyncio.get_event_loop().run_in_executor(
250
- self.executor, self.type_check, uri
251
- )
252
- await self.push_diagnostics(uri)
237
+
238
+ async def launch_deep_check(self, uri: str) -> None:
239
+ """Analyze and publish diagnostics."""
240
+
241
+ async def run_in_executor(
242
+ func: Callable[[str, Optional[str]], bool],
243
+ file_path: str,
244
+ annex_view: Optional[str] = None,
245
+ ) -> None:
246
+ loop = asyncio.get_event_loop()
247
+ await loop.run_in_executor(self.executor, func, file_path, annex_view)
248
+
249
+ if uri in self.tasks and not self.tasks[uri].done():
250
+ self.log_py(f"Canceling {uri} deep check...")
251
+ self.tasks[uri].cancel()
252
+ del self.tasks[uri]
253
+ self.log_py(f"Analyzing {uri}...")
254
+ task = asyncio.create_task(run_in_executor(self.deep_check, uri))
255
+ self.tasks[uri] = task
256
+ await task
253
257
 
254
258
  def get_completion(
255
- self, file_path: str, position: lspt.Position
259
+ self, file_path: str, position: lspt.Position, completion_trigger: Optional[str]
256
260
  ) -> lspt.CompletionList:
257
261
  """Return completion for a file."""
258
- items = []
262
+ completion_items = []
259
263
  document = self.workspace.get_text_document(file_path)
260
- current_line = document.lines[position.line].strip()
261
- if current_line.endswith("hello."):
264
+ current_line = document.lines[position.line]
265
+ current_pos = position.character
266
+ current_symbol_path = parse_symbol_path(current_line, current_pos)
267
+ node_selected = find_deepest_symbol_node_at_pos(
268
+ self.modules[file_path].ir,
269
+ position.line,
270
+ position.character - 2,
271
+ )
262
272
 
263
- items = [
264
- lspt.CompletionItem(label="world"),
265
- lspt.CompletionItem(label="friend"),
266
- ]
267
- return lspt.CompletionList(is_incomplete=False, items=items)
273
+ mod_tab = (
274
+ self.modules[file_path].ir.sym_tab
275
+ if not node_selected
276
+ else node_selected.sym_tab
277
+ )
278
+ current_tab = self.modules[file_path].ir._sym_tab
279
+ current_symbol_table = mod_tab
280
+ if completion_trigger == ".":
281
+ completion_items = resolve_completion_symbol_table(
282
+ mod_tab, current_symbol_path, current_tab
283
+ )
284
+ else:
285
+ try: # noqa SIM105
286
+ completion_items = collect_all_symbols_in_scope(current_symbol_table)
287
+ except AttributeError:
288
+ pass
289
+ return lspt.CompletionList(is_incomplete=False, items=completion_items)
268
290
 
269
291
  def rename_module(self, old_path: str, new_path: str) -> None:
270
292
  """Rename module."""
@@ -311,6 +333,8 @@ class JacLangServer(LanguageServer):
311
333
  self, file_path: str, position: lspt.Position
312
334
  ) -> Optional[lspt.Hover]:
313
335
  """Return hover information for a file."""
336
+ if file_path not in self.modules:
337
+ return None
314
338
  node_selected = find_deepest_symbol_node_at_pos(
315
339
  self.modules[file_path].ir, position.line, position.character
316
340
  )
@@ -347,7 +371,9 @@ class JacLangServer(LanguageServer):
347
371
 
348
372
  def get_document_symbols(self, file_path: str) -> list[lspt.DocumentSymbol]:
349
373
  """Return document symbols for a file."""
350
- if root_node := self.modules[file_path].ir._sym_tab:
374
+ if file_path in self.modules and (
375
+ root_node := self.modules[file_path].ir._sym_tab
376
+ ):
351
377
  return collect_symbols(root_node)
352
378
  return []
353
379
 
@@ -355,6 +381,8 @@ class JacLangServer(LanguageServer):
355
381
  self, file_path: str, position: lspt.Position
356
382
  ) -> Optional[lspt.Location]:
357
383
  """Return definition location for a file."""
384
+ if file_path not in self.modules:
385
+ return None
358
386
  node_selected: Optional[ast.AstSymbolNode] = find_deepest_symbol_node_at_pos(
359
387
  self.modules[file_path].ir, position.line, position.character
360
388
  )
@@ -419,6 +447,24 @@ class JacLangServer(LanguageServer):
419
447
  else:
420
448
  return None
421
449
 
450
+ def get_references(
451
+ self, file_path: str, position: lspt.Position
452
+ ) -> list[lspt.Location]:
453
+ """Return references for a file."""
454
+ node_selected = find_deepest_symbol_node_at_pos(
455
+ self.modules[file_path].ir, position.line, position.character
456
+ )
457
+ if node_selected and node_selected.sym:
458
+ list_of_references: list[lspt.Location] = [
459
+ lspt.Location(
460
+ uri=uris.from_fs_path(node.loc.mod_path),
461
+ range=create_range(node.loc),
462
+ )
463
+ for node in node_selected.sym.uses
464
+ ]
465
+ return list_of_references
466
+ return []
467
+
422
468
  def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
423
469
  """Return semantic tokens for a file."""
424
470
  if file_path not in self.modules:
@@ -9,7 +9,6 @@ from jaclang.compiler.constant import (
9
9
  JacSemTokenType as SemTokType,
10
10
  )
11
11
  from jaclang.langserve.engine import JacLangServer
12
- from jaclang.langserve.utils import debounce
13
12
 
14
13
  import lsprotocol.types as lspt
15
14
 
@@ -20,14 +19,19 @@ server = JacLangServer()
20
19
  @server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
21
20
  async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
22
21
  """Check syntax on change."""
23
- await ls.analyze_and_publish(params.text_document.uri)
22
+ await ls.launch_deep_check(params.text_document.uri)
23
+ ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
24
24
 
25
25
 
26
26
  @server.feature(lspt.TEXT_DOCUMENT_DID_CHANGE)
27
- @debounce(0.3)
28
- async def did_change(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
27
+ async def did_change(
28
+ ls: JacLangServer, params: lspt.DidChangeTextDocumentParams
29
+ ) -> None:
29
30
  """Check syntax on change."""
30
- await ls.analyze_and_publish(params.text_document.uri, level=1)
31
+ await ls.launch_quick_check(file_path := params.text_document.uri)
32
+ if file_path in ls.modules:
33
+ ls.modules[file_path].update_sem_tokens(params)
34
+ ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
31
35
 
32
36
 
33
37
  @server.feature(lspt.TEXT_DOCUMENT_FORMATTING)
@@ -82,11 +86,15 @@ def did_delete_files(ls: JacLangServer, params: lspt.DeleteFilesParams) -> None:
82
86
 
83
87
  @server.feature(
84
88
  lspt.TEXT_DOCUMENT_COMPLETION,
85
- lspt.CompletionOptions(trigger_characters=[".", ":", ""]),
89
+ lspt.CompletionOptions(trigger_characters=[".", ":", "a-zA-Z0-9"]),
86
90
  )
87
91
  def completion(ls: JacLangServer, params: lspt.CompletionParams) -> lspt.CompletionList:
88
92
  """Provide completion."""
89
- return ls.get_completion(params.text_document.uri, params.position)
93
+ return ls.get_completion(
94
+ params.text_document.uri,
95
+ params.position,
96
+ params.context.trigger_character if params.context else None,
97
+ )
90
98
 
91
99
 
92
100
  @server.feature(lspt.TEXT_DOCUMENT_HOVER, lspt.HoverOptions(work_done_progress=True))
@@ -113,6 +121,12 @@ def definition(
113
121
  return ls.get_definition(params.text_document.uri, params.position)
114
122
 
115
123
 
124
+ @server.feature(lspt.TEXT_DOCUMENT_REFERENCES)
125
+ def references(ls: JacLangServer, params: lspt.ReferenceParams) -> list[lspt.Location]:
126
+ """Provide references."""
127
+ return ls.get_references(params.text_document.uri, params.position)
128
+
129
+
116
130
  @server.feature(
117
131
  lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
118
132
  lspt.SemanticTokensLegend(
@@ -124,6 +138,14 @@ def semantic_tokens_full(
124
138
  ls: JacLangServer, params: lspt.SemanticTokensParams
125
139
  ) -> lspt.SemanticTokens:
126
140
  """Provide semantic tokens."""
141
+ # import logging
142
+
143
+ # logging.info("\nGetting semantic tokens\n")
144
+ # # logging.info(ls.get_semantic_tokens(params.text_document.uri))
145
+ # i = 0
146
+ # while i < len(ls.get_semantic_tokens(params.text_document.uri).data):
147
+ # logging.info(ls.get_semantic_tokens(params.text_document.uri).data[i : i + 5])
148
+ # i += 5
127
149
  return ls.get_semantic_tokens(params.text_document.uri)
128
150
 
129
151
 
@@ -21,8 +21,34 @@ with entry:__main__ {
21
21
 
22
22
  glob x: int = 10;
23
23
 
24
- enum Color {
24
+ enum Colorenum {
25
25
  RED,
26
26
  GREEN,
27
27
  BLUE
28
- }
28
+ }
29
+
30
+ obj Colour1 {
31
+ has color1: Colorenum,
32
+ point1: int;
33
+
34
+ can get_color1 -> Colorenum;
35
+ }
36
+
37
+ :obj:Colour1:can:get_color1 -> Colorenum {
38
+ return self.color;
39
+ }
40
+
41
+ obj red :Colour1: {
42
+ has base_colorred: Colorenum = Color.RED,
43
+ pointred: int = 10;
44
+ obj color2 {
45
+ has color22: Color = Colorenum.BLUE,
46
+ point22: int = 20;
47
+ }
48
+ }
49
+
50
+ with entry:__main__ {
51
+ r = red(color1=Color.GREEN, point1=20);
52
+ print(r.get_color1());
53
+ print(r.color2.color22);
54
+ }
@@ -1,6 +1,6 @@
1
1
  import:py os;
2
2
  import:py from math, sqrt as square_root;
3
3
  import:py datetime as dt;
4
- import:jac from base_module_structure, add as adsd, subtract,x,Color as clr;
4
+ import:jac from base_module_structure, add_numbers as adsd, subtract,x,Colorenum as clr;
5
5
  import:jac base_module_structure as base_module_structure;
6
6
  import:py from py_import,add1 as ss, sub1 as subtract1,apple,Orange1;