jaclang 0.7.5__py3-none-any.whl → 0.7.6__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/compiler/absyntree.py +167 -26
- jaclang/compiler/constant.py +98 -2
- jaclang/compiler/jac.lark +2 -0
- jaclang/compiler/parser.py +4 -0
- jaclang/compiler/passes/main/access_modifier_pass.py +5 -3
- jaclang/compiler/passes/main/def_impl_match_pass.py +3 -1
- jaclang/compiler/passes/main/def_use_pass.py +27 -39
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +34 -12
- jaclang/compiler/passes/main/sub_node_tab_pass.py +0 -5
- jaclang/compiler/passes/main/sym_tab_build_pass.py +31 -181
- jaclang/compiler/passes/tool/tests/fixtures/genai/essay_review.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/expert_answer.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/joke_gen.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/odd_word_out.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/personality_finder.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/text_to_type.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/translator.jac +1 -1
- jaclang/compiler/passes/tool/tests/fixtures/genai/wikipedia.jac +1 -1
- jaclang/compiler/symtable.py +118 -65
- jaclang/core/aott.py +7 -3
- jaclang/core/importer.py +1 -1
- jaclang/langserve/engine.py +100 -36
- jaclang/langserve/server.py +34 -61
- jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -0
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +15 -0
- jaclang/langserve/tests/fixtures/import_include_statements.jac +6 -0
- jaclang/langserve/tests/fixtures/py_import.py +26 -0
- jaclang/langserve/tests/test_server.py +90 -6
- jaclang/langserve/utils.py +114 -4
- jaclang/plugin/default.py +2 -2
- jaclang/plugin/feature.py +1 -1
- jaclang/plugin/spec.py +1 -1
- jaclang/tests/fixtures/aott_raise.jac +1 -1
- jaclang/tests/fixtures/edgetypeissue.jac +10 -0
- jaclang/tests/fixtures/hello.jac +1 -1
- jaclang/tests/fixtures/with_llm_function.jac +1 -1
- jaclang/tests/fixtures/with_llm_lower.jac +1 -1
- jaclang/tests/fixtures/with_llm_method.jac +1 -1
- jaclang/tests/fixtures/with_llm_type.jac +1 -1
- jaclang/tests/fixtures/with_llm_vision.jac +1 -1
- jaclang/tests/test_language.py +106 -96
- {jaclang-0.7.5.dist-info → jaclang-0.7.6.dist-info}/METADATA +1 -1
- {jaclang-0.7.5.dist-info → jaclang-0.7.6.dist-info}/RECORD +45 -50
- jaclang/core/llms/__init__.py +0 -20
- jaclang/core/llms/anthropic.py +0 -90
- jaclang/core/llms/base.py +0 -206
- jaclang/core/llms/groq.py +0 -70
- jaclang/core/llms/huggingface.py +0 -76
- jaclang/core/llms/ollama.py +0 -81
- jaclang/core/llms/openai.py +0 -65
- jaclang/core/llms/togetherai.py +0 -63
- jaclang/core/llms/utils.py +0 -9
- jaclang/tests/fixtures/edgetypetest.jac +0 -16
- {jaclang-0.7.5.dist-info → jaclang-0.7.6.dist-info}/WHEEL +0 -0
- {jaclang-0.7.5.dist-info → jaclang-0.7.6.dist-info}/entry_points.txt +0 -0
jaclang/compiler/symtable.py
CHANGED
|
@@ -2,60 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
from typing import Optional,
|
|
5
|
+
import ast as ast3
|
|
6
|
+
from typing import Optional, Sequence
|
|
7
7
|
|
|
8
|
+
import jaclang.compiler.absyntree as ast
|
|
9
|
+
from jaclang.compiler.constant import SymbolAccess, SymbolType
|
|
8
10
|
from jaclang.utils.treeprinter import dotgen_symtab_tree, print_symtab_tree
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
import jaclang.compiler.absyntree as ast
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class SymbolType(Enum):
|
|
16
|
-
"""Symbol types."""
|
|
17
|
-
|
|
18
|
-
MODULE = "module" # LSP: Module
|
|
19
|
-
MOD_VAR = "mod_var" # LSP: Variable
|
|
20
|
-
VAR = "variable" # LSP: Variable
|
|
21
|
-
IMM_VAR = "immutable" # LSP: Constant
|
|
22
|
-
ABILITY = "ability" # LSP: Function
|
|
23
|
-
OBJECT_ARCH = "object" # LSP: Class
|
|
24
|
-
NODE_ARCH = "node" # LSP: Class
|
|
25
|
-
EDGE_ARCH = "edge" # LSP: Class
|
|
26
|
-
WALKER_ARCH = "walker" # LSP: Class
|
|
27
|
-
ENUM_ARCH = "enum" # LSP: Enum
|
|
28
|
-
TEST = "test" # LSP: Function
|
|
29
|
-
TYPE = "type" # LSP: TypeParameter
|
|
30
|
-
IMPL = "impl" # LSP: Interface or Property
|
|
31
|
-
HAS_VAR = "field" # LSP: Field
|
|
32
|
-
METHOD = "method" # LSP: Method
|
|
33
|
-
CONSTRUCTOR = "constructor" # LSP: Constructor
|
|
34
|
-
ENUM_MEMBER = "enum_member" # LSP: EnumMember
|
|
35
|
-
NUMBER = "number" # LSP: Number
|
|
36
|
-
STRING = "string" # LSP: String
|
|
37
|
-
BOOL = "bool" # LSP: Boolean
|
|
38
|
-
SEQUENCE = "sequence" # LSP: Array
|
|
39
|
-
NULL = "null" # LSP: Null
|
|
40
|
-
UNKNOWN = "unknown" # LSP: Unknown
|
|
41
|
-
|
|
42
|
-
def __str__(self) -> str:
|
|
43
|
-
"""Stringify."""
|
|
44
|
-
return self.value
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class SymbolAccess(Enum):
|
|
48
|
-
"""Symbol types."""
|
|
49
|
-
|
|
50
|
-
PRIVATE = "private"
|
|
51
|
-
PUBLIC = "public"
|
|
52
|
-
PROTECTED = "protected"
|
|
53
|
-
|
|
54
|
-
def __str__(self) -> str:
|
|
55
|
-
"""Stringify."""
|
|
56
|
-
return self.value
|
|
57
|
-
|
|
58
|
-
|
|
59
13
|
# Symbols can have mulitple definitions but resolves decl to be the
|
|
60
14
|
# first such definition in a given scope.
|
|
61
15
|
class Symbol:
|
|
@@ -93,13 +47,10 @@ class Symbol:
|
|
|
93
47
|
def sym_dotted_name(self) -> str:
|
|
94
48
|
"""Return a full path of the symbol."""
|
|
95
49
|
out = [self.defn[0].sym_name]
|
|
96
|
-
current_tab = self.parent_tab
|
|
50
|
+
current_tab: SymbolTable | None = self.parent_tab
|
|
97
51
|
while current_tab is not None:
|
|
98
52
|
out.append(current_tab.name)
|
|
99
|
-
|
|
100
|
-
current_tab = current_tab.parent
|
|
101
|
-
else:
|
|
102
|
-
break
|
|
53
|
+
current_tab = current_tab.parent
|
|
103
54
|
out.reverse()
|
|
104
55
|
return ".".join(out)
|
|
105
56
|
|
|
@@ -127,19 +78,13 @@ class SymbolTable:
|
|
|
127
78
|
"""Initialize."""
|
|
128
79
|
self.name = name
|
|
129
80
|
self.owner = owner
|
|
130
|
-
self.parent = parent
|
|
81
|
+
self.parent = parent
|
|
131
82
|
self.kid: list[SymbolTable] = []
|
|
132
83
|
self.tab: dict[str, Symbol] = {}
|
|
133
84
|
self.inherit: list[SymbolTable] = []
|
|
134
85
|
|
|
135
|
-
def
|
|
136
|
-
"""Check if has parent."""
|
|
137
|
-
return self.parent != self
|
|
138
|
-
|
|
139
|
-
def get_parent(self) -> SymbolTable:
|
|
86
|
+
def get_parent(self) -> Optional[SymbolTable]:
|
|
140
87
|
"""Get parent."""
|
|
141
|
-
if self.parent == self:
|
|
142
|
-
raise Exception("No parent")
|
|
143
88
|
return self.parent
|
|
144
89
|
|
|
145
90
|
def lookup(self, name: str, deep: bool = True) -> Optional[Symbol]:
|
|
@@ -150,8 +95,8 @@ class SymbolTable:
|
|
|
150
95
|
found = i.lookup(name, deep=False)
|
|
151
96
|
if found:
|
|
152
97
|
return found
|
|
153
|
-
if deep and self.
|
|
154
|
-
return self.
|
|
98
|
+
if deep and self.parent:
|
|
99
|
+
return self.parent.lookup(name, deep)
|
|
155
100
|
return None
|
|
156
101
|
|
|
157
102
|
def insert(
|
|
@@ -197,6 +142,114 @@ class SymbolTable:
|
|
|
197
142
|
self.kid.append(SymbolTable(name, key_node, self))
|
|
198
143
|
return self.kid[-1]
|
|
199
144
|
|
|
145
|
+
def inherit_sym_tab(self, target_sym_tab: SymbolTable) -> None:
|
|
146
|
+
"""Inherit symbol table."""
|
|
147
|
+
for i in target_sym_tab.tab.values():
|
|
148
|
+
self.def_insert(i.decl, access_spec=i.access)
|
|
149
|
+
|
|
150
|
+
def def_insert(
|
|
151
|
+
self,
|
|
152
|
+
node: ast.AstSymbolNode,
|
|
153
|
+
access_spec: Optional[ast.AstAccessNode] | SymbolAccess = None,
|
|
154
|
+
single_decl: Optional[str] = None,
|
|
155
|
+
) -> Optional[Symbol]:
|
|
156
|
+
"""Insert into symbol table."""
|
|
157
|
+
if node.sym and self == node.sym.parent_tab:
|
|
158
|
+
return node.sym
|
|
159
|
+
self.insert(node=node, single=single_decl is not None, access_spec=access_spec)
|
|
160
|
+
self.update_py_ctx_for_def(node)
|
|
161
|
+
return node.sym
|
|
162
|
+
|
|
163
|
+
def chain_def_insert(self, node_list: list[ast.AstSymbolNode]) -> None:
|
|
164
|
+
"""Link chain of containing names to symbol."""
|
|
165
|
+
if not node_list:
|
|
166
|
+
return
|
|
167
|
+
cur_sym_tab: SymbolTable | None = node_list[0].sym_tab
|
|
168
|
+
node_list[-1].name_spec.py_ctx_func = ast3.Store
|
|
169
|
+
if isinstance(node_list[-1].name_spec, ast.AstSymbolNode):
|
|
170
|
+
node_list[-1].name_spec.py_ctx_func = ast3.Store
|
|
171
|
+
|
|
172
|
+
node_list = node_list[:-1] # Just performs lookup mappings of pre assign chain
|
|
173
|
+
for i in node_list:
|
|
174
|
+
cur_sym_tab = (
|
|
175
|
+
lookup.decl.sym_tab
|
|
176
|
+
if (
|
|
177
|
+
lookup := self.use_lookup(
|
|
178
|
+
i,
|
|
179
|
+
sym_table=cur_sym_tab,
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
else None
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def use_lookup(
|
|
186
|
+
self,
|
|
187
|
+
node: ast.AstSymbolNode,
|
|
188
|
+
sym_table: Optional[SymbolTable] = None,
|
|
189
|
+
) -> Optional[Symbol]:
|
|
190
|
+
"""Link to symbol."""
|
|
191
|
+
if node.sym:
|
|
192
|
+
return node.sym
|
|
193
|
+
if not sym_table:
|
|
194
|
+
sym_table = node.sym_tab
|
|
195
|
+
if sym_table:
|
|
196
|
+
lookup = sym_table.lookup(name=node.sym_name, deep=True)
|
|
197
|
+
lookup.add_use(node.name_spec) if lookup else None
|
|
198
|
+
return node.sym
|
|
199
|
+
|
|
200
|
+
def chain_use_lookup(self, node_list: Sequence[ast.AstSymbolNode]) -> None:
|
|
201
|
+
"""Link chain of containing names to symbol."""
|
|
202
|
+
if not node_list:
|
|
203
|
+
return
|
|
204
|
+
cur_sym_tab: SymbolTable | None = node_list[0].sym_tab
|
|
205
|
+
for i in node_list:
|
|
206
|
+
if cur_sym_tab is None:
|
|
207
|
+
break
|
|
208
|
+
cur_sym_tab = (
|
|
209
|
+
lookup.decl.sym_tab
|
|
210
|
+
if (
|
|
211
|
+
lookup := self.use_lookup(
|
|
212
|
+
i,
|
|
213
|
+
sym_table=cur_sym_tab,
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
else None
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def update_py_ctx_for_def(self, node: ast.AstSymbolNode) -> None:
|
|
220
|
+
"""Update python context for definition."""
|
|
221
|
+
node.name_spec.py_ctx_func = ast3.Store
|
|
222
|
+
if isinstance(node, (ast.TupleVal, ast.ListVal)) and node.values:
|
|
223
|
+
# Handling of UnaryExpr case for item is only necessary for
|
|
224
|
+
# the generation of Starred nodes in the AST for examples
|
|
225
|
+
# like `(a, *b) = (1, 2, 3, 4)`.
|
|
226
|
+
def fix(item: ast.TupleVal | ast.ListVal | ast.UnaryExpr) -> None:
|
|
227
|
+
if isinstance(item, ast.UnaryExpr):
|
|
228
|
+
if isinstance(item.operand, ast.AstSymbolNode):
|
|
229
|
+
item.operand.name_spec.py_ctx_func = ast3.Store
|
|
230
|
+
elif isinstance(item, (ast.TupleVal, ast.ListVal)):
|
|
231
|
+
for i in item.values.items if item.values else []:
|
|
232
|
+
if isinstance(i, ast.AstSymbolNode):
|
|
233
|
+
i.name_spec.py_ctx_func = ast3.Store
|
|
234
|
+
elif isinstance(i, ast.AtomTrailer):
|
|
235
|
+
self.chain_def_insert(i.as_attr_list)
|
|
236
|
+
if isinstance(i, (ast.TupleVal, ast.ListVal, ast.UnaryExpr)):
|
|
237
|
+
fix(i)
|
|
238
|
+
|
|
239
|
+
fix(node)
|
|
240
|
+
|
|
241
|
+
def inherit_baseclasses_sym(self, node: ast.Architype | ast.Enum) -> None:
|
|
242
|
+
"""Inherit base classes symbol tables."""
|
|
243
|
+
if node.base_classes:
|
|
244
|
+
for base_cls in node.base_classes.items:
|
|
245
|
+
if (
|
|
246
|
+
isinstance(base_cls, ast.AstSymbolNode)
|
|
247
|
+
and (found := self.use_lookup(base_cls))
|
|
248
|
+
and found
|
|
249
|
+
):
|
|
250
|
+
self.inherit.append(found.decl.sym_tab)
|
|
251
|
+
base_cls.name_spec.name_of = found.decl.name_of
|
|
252
|
+
|
|
200
253
|
def pp(self, depth: Optional[int] = None) -> str:
|
|
201
254
|
"""Pretty print."""
|
|
202
255
|
return print_symtab_tree(root=self, depth=depth)
|
jaclang/core/aott.py
CHANGED
|
@@ -18,14 +18,18 @@ except ImportError:
|
|
|
18
18
|
Image = None
|
|
19
19
|
|
|
20
20
|
from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from mtllm.llms import BaseLLM
|
|
24
|
+
except ImportError:
|
|
25
|
+
BaseLLM = None
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
IMG_FORMATS = ["PngImageFile", "JpegImageFile"]
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
def aott_raise(
|
|
28
|
-
model: BaseLLM,
|
|
32
|
+
model: BaseLLM, # type: ignore
|
|
29
33
|
information: str,
|
|
30
34
|
inputs_information: str | list[dict],
|
|
31
35
|
output_information: str,
|
|
@@ -298,7 +302,7 @@ def get_input_information(
|
|
|
298
302
|
return inputs_information_dict_list
|
|
299
303
|
|
|
300
304
|
|
|
301
|
-
def image_to_base64(image: Image) -> str:
|
|
305
|
+
def image_to_base64(image: Image) -> str: # type: ignore
|
|
302
306
|
"""Convert an image to base64 expected by OpenAI."""
|
|
303
307
|
if not Image:
|
|
304
308
|
log = logging.getLogger(__name__)
|
jaclang/core/importer.py
CHANGED
jaclang/langserve/engine.py
CHANGED
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from enum import IntEnum
|
|
7
|
-
from hashlib import md5
|
|
8
7
|
from typing import Optional
|
|
9
8
|
|
|
10
9
|
|
|
@@ -19,6 +18,8 @@ from jaclang.langserve.utils import (
|
|
|
19
18
|
collect_symbols,
|
|
20
19
|
create_range,
|
|
21
20
|
find_deepest_symbol_node_at_pos,
|
|
21
|
+
get_item_path,
|
|
22
|
+
get_mod_path,
|
|
22
23
|
)
|
|
23
24
|
from jaclang.vendor.pygls import uris
|
|
24
25
|
from jaclang.vendor.pygls.server import LanguageServer
|
|
@@ -27,7 +28,7 @@ import lsprotocol.types as lspt
|
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
class ALev(IntEnum):
|
|
30
|
-
"""Analysis Level."""
|
|
31
|
+
"""Analysis Level successfully completed."""
|
|
31
32
|
|
|
32
33
|
QUICK = 1
|
|
33
34
|
DEEP = 2
|
|
@@ -52,6 +53,7 @@ class ModuleInfo:
|
|
|
52
53
|
self.alev = alev
|
|
53
54
|
self.parent: Optional[ModuleInfo] = parent
|
|
54
55
|
self.diagnostics = self.gen_diagnostics()
|
|
56
|
+
self.sem_tokens: list[int] = self.gen_sem_tokens()
|
|
55
57
|
|
|
56
58
|
@property
|
|
57
59
|
def uri(self) -> str:
|
|
@@ -63,13 +65,19 @@ class ModuleInfo:
|
|
|
63
65
|
"""Return if there are syntax errors."""
|
|
64
66
|
return len(self.errors) > 0 and self.alev == ALev.QUICK
|
|
65
67
|
|
|
66
|
-
def update_with(self, new_info: ModuleInfo) -> None:
|
|
68
|
+
def update_with(self, new_info: ModuleInfo, refresh: bool = False) -> None:
|
|
67
69
|
"""Update module info."""
|
|
68
70
|
self.ir = new_info.ir
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
if refresh:
|
|
72
|
+
self.errors = new_info.errors
|
|
73
|
+
self.warnings = new_info.warnings
|
|
74
|
+
else:
|
|
75
|
+
self.errors += [i for i in new_info.errors if i not in self.errors]
|
|
76
|
+
self.warnings += [i for i in new_info.warnings if i not in self.warnings]
|
|
71
77
|
self.alev = new_info.alev
|
|
72
78
|
self.diagnostics = self.gen_diagnostics()
|
|
79
|
+
if self.alev == ALev.TYPE:
|
|
80
|
+
self.sem_tokens = self.gen_sem_tokens()
|
|
73
81
|
|
|
74
82
|
def gen_diagnostics(self) -> list[lspt.Diagnostic]:
|
|
75
83
|
"""Return diagnostics."""
|
|
@@ -89,6 +97,27 @@ class ModuleInfo:
|
|
|
89
97
|
for warning in self.warnings
|
|
90
98
|
]
|
|
91
99
|
|
|
100
|
+
def gen_sem_tokens(self) -> list[int]:
|
|
101
|
+
"""Return semantic tokens."""
|
|
102
|
+
tokens = []
|
|
103
|
+
prev_line, prev_col = 0, 0
|
|
104
|
+
for node in self.ir._in_mod_nodes:
|
|
105
|
+
if isinstance(node, ast.NameAtom) and node.sem_token:
|
|
106
|
+
line, col_start, col_end = (
|
|
107
|
+
node.loc.first_line - 1,
|
|
108
|
+
node.loc.col_start - 1,
|
|
109
|
+
node.loc.col_end - 1,
|
|
110
|
+
)
|
|
111
|
+
length = col_end - col_start
|
|
112
|
+
tokens += [
|
|
113
|
+
line - prev_line,
|
|
114
|
+
col_start if line != prev_line else col_start - prev_col,
|
|
115
|
+
length,
|
|
116
|
+
*node.sem_token,
|
|
117
|
+
]
|
|
118
|
+
prev_line, prev_col = line, col_start
|
|
119
|
+
return tokens
|
|
120
|
+
|
|
92
121
|
|
|
93
122
|
class JacLangServer(LanguageServer):
|
|
94
123
|
"""Class for managing workspace."""
|
|
@@ -98,19 +127,6 @@ class JacLangServer(LanguageServer):
|
|
|
98
127
|
super().__init__("jac-lsp", "v0.1")
|
|
99
128
|
self.modules: dict[str, ModuleInfo] = {}
|
|
100
129
|
|
|
101
|
-
def module_not_diff(self, uri: str, alev: ALev) -> bool:
|
|
102
|
-
"""Check if module was changed."""
|
|
103
|
-
doc = self.workspace.get_text_document(uri)
|
|
104
|
-
return (
|
|
105
|
-
doc.uri in self.modules
|
|
106
|
-
and self.modules[doc.uri].ir.source.hash
|
|
107
|
-
== md5(doc.source.encode()).hexdigest()
|
|
108
|
-
and (
|
|
109
|
-
self.modules[doc.uri].alev >= alev
|
|
110
|
-
or self.modules[doc.uri].has_syntax_error
|
|
111
|
-
)
|
|
112
|
-
)
|
|
113
|
-
|
|
114
130
|
def push_diagnostics(self, file_path: str) -> None:
|
|
115
131
|
"""Push diagnostics for a file."""
|
|
116
132
|
if file_path in self.modules:
|
|
@@ -153,8 +169,8 @@ class JacLangServer(LanguageServer):
|
|
|
153
169
|
],
|
|
154
170
|
alev=alev,
|
|
155
171
|
)
|
|
156
|
-
if
|
|
157
|
-
self.modules[file_path].update_with(new_mod)
|
|
172
|
+
if file_path in self.modules:
|
|
173
|
+
self.modules[file_path].update_with(new_mod, refresh=refresh)
|
|
158
174
|
else:
|
|
159
175
|
self.modules[file_path] = new_mod
|
|
160
176
|
for p in build.ir.mod_deps.keys():
|
|
@@ -173,10 +189,8 @@ class JacLangServer(LanguageServer):
|
|
|
173
189
|
self.modules[file_path] if file_path != uri else None
|
|
174
190
|
)
|
|
175
191
|
|
|
176
|
-
def quick_check(self, file_path: str
|
|
192
|
+
def quick_check(self, file_path: str) -> bool:
|
|
177
193
|
"""Rebuild a file."""
|
|
178
|
-
if not force and self.module_not_diff(file_path, ALev.QUICK):
|
|
179
|
-
return
|
|
180
194
|
try:
|
|
181
195
|
document = self.workspace.get_text_document(file_path)
|
|
182
196
|
build = jac_str_to_pass(
|
|
@@ -184,27 +198,27 @@ class JacLangServer(LanguageServer):
|
|
|
184
198
|
)
|
|
185
199
|
except Exception as e:
|
|
186
200
|
self.log_error(f"Error during syntax check: {e}")
|
|
201
|
+
return False
|
|
187
202
|
self.update_modules(file_path, build, ALev.QUICK, refresh=True)
|
|
203
|
+
return len(self.modules[file_path].errors) == 0
|
|
188
204
|
|
|
189
|
-
def deep_check(self, file_path: str
|
|
205
|
+
def deep_check(self, file_path: str) -> bool:
|
|
190
206
|
"""Rebuild a file and its dependencies."""
|
|
191
|
-
if file_path in self.modules:
|
|
192
|
-
self.quick_check(file_path
|
|
193
|
-
if not force and self.module_not_diff(file_path, ALev.DEEP):
|
|
194
|
-
return
|
|
207
|
+
if file_path not in self.modules:
|
|
208
|
+
self.quick_check(file_path)
|
|
195
209
|
try:
|
|
196
210
|
file_path = self.unwind_to_parent(file_path)
|
|
197
211
|
build = jac_ir_to_pass(ir=self.modules[file_path].ir)
|
|
198
212
|
except Exception as e:
|
|
199
213
|
self.log_error(f"Error during syntax check: {e}")
|
|
214
|
+
return False
|
|
200
215
|
self.update_modules(file_path, build, ALev.DEEP)
|
|
216
|
+
return len(self.modules[file_path].errors) == 0
|
|
201
217
|
|
|
202
|
-
def type_check(self, file_path: str
|
|
218
|
+
def type_check(self, file_path: str) -> bool:
|
|
203
219
|
"""Rebuild a file and its dependencies."""
|
|
204
220
|
if file_path not in self.modules:
|
|
205
|
-
self.deep_check(file_path
|
|
206
|
-
if not force and self.module_not_diff(file_path, ALev.TYPE):
|
|
207
|
-
return
|
|
221
|
+
self.deep_check(file_path)
|
|
208
222
|
try:
|
|
209
223
|
file_path = self.unwind_to_parent(file_path)
|
|
210
224
|
build = jac_ir_to_pass(
|
|
@@ -212,7 +226,21 @@ class JacLangServer(LanguageServer):
|
|
|
212
226
|
)
|
|
213
227
|
except Exception as e:
|
|
214
228
|
self.log_error(f"Error during type check: {e}")
|
|
229
|
+
return False
|
|
215
230
|
self.update_modules(file_path, build, ALev.TYPE)
|
|
231
|
+
return len(self.modules[file_path].errors) == 0
|
|
232
|
+
|
|
233
|
+
def analyze_and_publish(self, uri: str, level: int = 2) -> None:
|
|
234
|
+
"""Analyze and publish diagnostics."""
|
|
235
|
+
self.log_py(f"Analyzing {uri}...")
|
|
236
|
+
success = self.quick_check(uri)
|
|
237
|
+
self.push_diagnostics(uri)
|
|
238
|
+
if success and level > 0:
|
|
239
|
+
success = self.deep_check(uri)
|
|
240
|
+
self.push_diagnostics(uri)
|
|
241
|
+
if level > 1:
|
|
242
|
+
self.type_check(uri)
|
|
243
|
+
self.push_diagnostics(uri)
|
|
216
244
|
|
|
217
245
|
def get_completion(
|
|
218
246
|
self, file_path: str, position: lspt.Position
|
|
@@ -310,8 +338,7 @@ class JacLangServer(LanguageServer):
|
|
|
310
338
|
|
|
311
339
|
def get_document_symbols(self, file_path: str) -> list[lspt.DocumentSymbol]:
|
|
312
340
|
"""Return document symbols for a file."""
|
|
313
|
-
root_node
|
|
314
|
-
if root_node:
|
|
341
|
+
if root_node := self.modules[file_path].ir._sym_tab:
|
|
315
342
|
return collect_symbols(root_node)
|
|
316
343
|
return []
|
|
317
344
|
|
|
@@ -323,7 +350,39 @@ class JacLangServer(LanguageServer):
|
|
|
323
350
|
self.modules[file_path].ir, position.line, position.character
|
|
324
351
|
)
|
|
325
352
|
if node_selected:
|
|
326
|
-
if
|
|
353
|
+
if (
|
|
354
|
+
isinstance(node_selected, ast.Name)
|
|
355
|
+
and node_selected.parent
|
|
356
|
+
and isinstance(node_selected.parent, ast.ModulePath)
|
|
357
|
+
):
|
|
358
|
+
spec = get_mod_path(node_selected.parent, node_selected)
|
|
359
|
+
if spec:
|
|
360
|
+
return lspt.Location(
|
|
361
|
+
uri=uris.from_fs_path(spec),
|
|
362
|
+
range=lspt.Range(
|
|
363
|
+
start=lspt.Position(line=0, character=0),
|
|
364
|
+
end=lspt.Position(line=0, character=0),
|
|
365
|
+
),
|
|
366
|
+
)
|
|
367
|
+
else:
|
|
368
|
+
return None
|
|
369
|
+
elif node_selected.parent and isinstance(
|
|
370
|
+
node_selected.parent, ast.ModuleItem
|
|
371
|
+
):
|
|
372
|
+
path_range = get_item_path(node_selected.parent)
|
|
373
|
+
if path_range:
|
|
374
|
+
path, range = path_range
|
|
375
|
+
if path and range:
|
|
376
|
+
return lspt.Location(
|
|
377
|
+
uri=uris.from_fs_path(path),
|
|
378
|
+
range=lspt.Range(
|
|
379
|
+
start=lspt.Position(line=range[0], character=0),
|
|
380
|
+
end=lspt.Position(line=range[1], character=5),
|
|
381
|
+
),
|
|
382
|
+
)
|
|
383
|
+
else:
|
|
384
|
+
return None
|
|
385
|
+
elif isinstance(node_selected, (ast.ElementStmt, ast.BuiltinType)):
|
|
327
386
|
return None
|
|
328
387
|
decl_node = (
|
|
329
388
|
node_selected.parent.body.target
|
|
@@ -349,9 +408,14 @@ class JacLangServer(LanguageServer):
|
|
|
349
408
|
|
|
350
409
|
return decl_location
|
|
351
410
|
else:
|
|
352
|
-
self.log_info("No declaration found for the selected node.")
|
|
353
411
|
return None
|
|
354
412
|
|
|
413
|
+
def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
|
|
414
|
+
"""Return semantic tokens for a file."""
|
|
415
|
+
if file_path not in self.modules:
|
|
416
|
+
return lspt.SemanticTokens(data=[])
|
|
417
|
+
return lspt.SemanticTokens(data=self.modules[file_path].sem_tokens)
|
|
418
|
+
|
|
355
419
|
def log_error(self, message: str) -> None:
|
|
356
420
|
"""Log an error message."""
|
|
357
421
|
self.show_message_log(message, lspt.MessageType.Error)
|