jaclang 0.7.14__py3-none-any.whl → 0.7.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/cli/cli.py +15 -10
- jaclang/cli/cmdreg.py +9 -12
- jaclang/compiler/__init__.py +19 -53
- jaclang/compiler/absyntree.py +86 -13
- jaclang/compiler/jac.lark +4 -3
- jaclang/compiler/parser.py +31 -23
- jaclang/compiler/passes/ir_pass.py +4 -13
- jaclang/compiler/passes/main/access_modifier_pass.py +1 -1
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +4 -5
- jaclang/compiler/passes/main/import_pass.py +18 -23
- jaclang/compiler/passes/main/pyast_gen_pass.py +307 -559
- jaclang/compiler/passes/main/pyast_load_pass.py +32 -6
- jaclang/compiler/passes/main/registry_pass.py +37 -3
- jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
- jaclang/compiler/passes/main/tests/__init__.py +1 -1
- jaclang/compiler/passes/main/type_check_pass.py +7 -0
- jaclang/compiler/passes/tool/jac_formatter_pass.py +124 -86
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
- jaclang/compiler/passes/transform.py +4 -0
- jaclang/compiler/semtable.py +31 -7
- jaclang/compiler/tests/test_importer.py +12 -5
- jaclang/langserve/engine.py +65 -118
- jaclang/langserve/sem_manager.py +379 -0
- jaclang/langserve/server.py +8 -10
- jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
- jaclang/langserve/tests/test_sem_tokens.py +277 -0
- jaclang/langserve/tests/test_server.py +72 -16
- jaclang/langserve/utils.py +163 -96
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +212 -24
- jaclang/plugin/feature.py +59 -11
- jaclang/plugin/spec.py +58 -6
- jaclang/{core → runtimelib}/architype.py +1 -1
- jaclang/{core → runtimelib}/context.py +8 -1
- jaclang/runtimelib/importer.py +361 -0
- jaclang/runtimelib/machine.py +94 -0
- jaclang/{core → runtimelib}/utils.py +13 -5
- jaclang/settings.py +4 -1
- jaclang/tests/fixtures/abc.jac +3 -3
- jaclang/tests/fixtures/byllmissue.jac +1 -5
- jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
- jaclang/tests/fixtures/cls_method.jac +41 -0
- jaclang/tests/fixtures/dblhello.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +3 -3
- jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
- jaclang/tests/fixtures/deep_import_mods.jac +13 -0
- jaclang/tests/fixtures/err.impl.jac +3 -0
- jaclang/tests/fixtures/err.jac +4 -2
- jaclang/tests/fixtures/err.test.jac +3 -0
- jaclang/tests/fixtures/err_runtime.jac +15 -0
- jaclang/tests/fixtures/game1.jac +1 -1
- jaclang/tests/fixtures/hello.jac +4 -0
- jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
- jaclang/tests/fixtures/impl_grab.jac +4 -1
- jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/needs_import.jac +2 -2
- jaclang/tests/fixtures/pyfunc_2.py +3 -0
- jaclang/tests/fixtures/registry.jac +9 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/fixtures/semstr.jac +1 -4
- jaclang/tests/fixtures/simple_archs.jac +1 -1
- jaclang/tests/test_cli.py +65 -2
- jaclang/tests/test_language.py +74 -7
- jaclang/tests/test_reference.py +6 -0
- jaclang/utils/helpers.py +45 -21
- jaclang/utils/test.py +9 -0
- jaclang/utils/treeprinter.py +0 -4
- {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
- {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/RECORD +89 -74
- jaclang/core/importer.py +0 -344
- jaclang/tests/fixtures/aott_raise.jac +0 -25
- jaclang/tests/fixtures/package_import.jac +0 -6
- /jaclang/{core → runtimelib}/__init__.py +0 -0
- /jaclang/{core → runtimelib}/constructs.py +0 -0
- /jaclang/{core → runtimelib}/memory.py +0 -0
- /jaclang/{core → runtimelib}/test.py +0 -0
- {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
- {jaclang-0.7.14.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
jaclang/langserve/utils.py
CHANGED
|
@@ -14,7 +14,6 @@ from jaclang.compiler.codeloc import CodeLocInfo
|
|
|
14
14
|
from jaclang.compiler.constant import SymbolType
|
|
15
15
|
from jaclang.compiler.passes.transform import Alert
|
|
16
16
|
from jaclang.compiler.symtable import Symbol, SymbolTable
|
|
17
|
-
from jaclang.utils.helpers import import_target_to_relative_path
|
|
18
17
|
from jaclang.vendor.pygls import uris
|
|
19
18
|
|
|
20
19
|
import lsprotocol.types as lspt
|
|
@@ -130,12 +129,25 @@ def position_within_node(node: ast.AstNode, line: int, character: int) -> bool:
|
|
|
130
129
|
return False
|
|
131
130
|
|
|
132
131
|
|
|
133
|
-
def
|
|
132
|
+
def find_index(
|
|
133
|
+
sem_tokens: list[int],
|
|
134
|
+
line: int,
|
|
135
|
+
char: int,
|
|
136
|
+
) -> Optional[int]:
|
|
137
|
+
"""Find index."""
|
|
138
|
+
index = None
|
|
139
|
+
for i, j in enumerate(
|
|
140
|
+
[get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5)]
|
|
141
|
+
):
|
|
142
|
+
if j[0] == line and j[1] <= char <= j[2]:
|
|
143
|
+
return i
|
|
144
|
+
|
|
145
|
+
return index
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def get_symbols_for_outline(node: SymbolTable) -> list[lspt.DocumentSymbol]:
|
|
134
149
|
"""Recursively collect symbols from the AST."""
|
|
135
150
|
symbols = []
|
|
136
|
-
if node is None:
|
|
137
|
-
return symbols
|
|
138
|
-
|
|
139
151
|
for key, item in node.tab.items():
|
|
140
152
|
if (
|
|
141
153
|
key in dir(builtins)
|
|
@@ -143,23 +155,20 @@ def collect_symbols(node: SymbolTable) -> list[lspt.DocumentSymbol]:
|
|
|
143
155
|
or item.decl.loc.mod_path != node.owner.loc.mod_path
|
|
144
156
|
):
|
|
145
157
|
continue
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
156
|
-
symbols.append(symbol)
|
|
158
|
+
pos = create_range(item.decl.loc)
|
|
159
|
+
symbol = lspt.DocumentSymbol(
|
|
160
|
+
name=key,
|
|
161
|
+
kind=kind_map(item.decl),
|
|
162
|
+
range=pos,
|
|
163
|
+
selection_range=pos,
|
|
164
|
+
children=[],
|
|
165
|
+
)
|
|
166
|
+
symbols.append(symbol)
|
|
157
167
|
|
|
158
168
|
for sub_tab in [
|
|
159
169
|
i for i in node.kid if i.owner.loc.mod_path == node.owner.loc.mod_path
|
|
160
170
|
]:
|
|
161
|
-
sub_symbols =
|
|
162
|
-
|
|
171
|
+
sub_symbols = get_symbols_for_outline(sub_tab)
|
|
163
172
|
if isinstance(
|
|
164
173
|
sub_tab.owner,
|
|
165
174
|
(ast.IfStmt, ast.ElseStmt, ast.WhileStmt, ast.IterForStmt, ast.InForStmt),
|
|
@@ -267,16 +276,15 @@ def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
|
|
|
267
276
|
def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
|
|
268
277
|
"""Get path for a module import name."""
|
|
269
278
|
ret_target = None
|
|
270
|
-
module_location_path = mod_path.loc.mod_path
|
|
271
279
|
if mod_path.parent and (
|
|
272
280
|
(
|
|
273
281
|
isinstance(mod_path.parent.parent, ast.Import)
|
|
274
|
-
and mod_path.parent.parent.
|
|
282
|
+
and mod_path.parent.parent.is_py
|
|
275
283
|
)
|
|
276
284
|
or (
|
|
277
285
|
isinstance(mod_path.parent, ast.Import)
|
|
278
286
|
and mod_path.parent.from_loc
|
|
279
|
-
and mod_path.parent.
|
|
287
|
+
and mod_path.parent.is_py
|
|
280
288
|
)
|
|
281
289
|
):
|
|
282
290
|
if mod_path.path and name_node in mod_path.path:
|
|
@@ -287,38 +295,34 @@ def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
|
|
|
287
295
|
)
|
|
288
296
|
else:
|
|
289
297
|
temporary_path_str = mod_path.path_str
|
|
290
|
-
sys.path.append(os.path.dirname(
|
|
298
|
+
sys.path.append(os.path.dirname(mod_path.loc.mod_path))
|
|
291
299
|
spec = importlib.util.find_spec(temporary_path_str)
|
|
292
|
-
sys.path.remove(os.path.dirname(
|
|
300
|
+
sys.path.remove(os.path.dirname(mod_path.loc.mod_path))
|
|
293
301
|
if spec and spec.origin and spec.origin.endswith(".py"):
|
|
294
302
|
ret_target = spec.origin
|
|
295
303
|
elif mod_path.parent and (
|
|
296
304
|
(
|
|
297
305
|
isinstance(mod_path.parent.parent, ast.Import)
|
|
298
|
-
and mod_path.parent.parent.
|
|
306
|
+
and mod_path.parent.parent.is_jac
|
|
299
307
|
)
|
|
300
308
|
or (
|
|
301
309
|
isinstance(mod_path.parent, ast.Import)
|
|
302
310
|
and mod_path.parent.from_loc
|
|
303
|
-
and mod_path.parent.
|
|
311
|
+
and mod_path.parent.is_jac
|
|
304
312
|
)
|
|
305
313
|
):
|
|
306
|
-
ret_target =
|
|
307
|
-
level=mod_path.level,
|
|
308
|
-
target=mod_path.path_str,
|
|
309
|
-
base_path=os.path.dirname(module_location_path),
|
|
310
|
-
)
|
|
314
|
+
ret_target = mod_path.resolve_relative_path()
|
|
311
315
|
return ret_target
|
|
312
316
|
|
|
313
317
|
|
|
314
318
|
def get_item_path(mod_item: ast.ModuleItem) -> tuple[str, tuple[int, int]] | None:
|
|
315
319
|
"""Get path."""
|
|
316
320
|
item_name = mod_item.name.value
|
|
317
|
-
if mod_item.from_parent.
|
|
321
|
+
if mod_item.from_parent.is_py and mod_item.from_parent.from_loc:
|
|
318
322
|
path = get_mod_path(mod_item.from_parent.from_loc, mod_item.name)
|
|
319
323
|
if path:
|
|
320
324
|
return get_definition_range(path, item_name)
|
|
321
|
-
elif mod_item.from_parent.
|
|
325
|
+
elif mod_item.from_parent.is_jac:
|
|
322
326
|
mod_node = mod_item.from_mod_path
|
|
323
327
|
if mod_node.sub_module and mod_node.sub_module._sym_tab:
|
|
324
328
|
for symbol_name, symbol in mod_node.sub_module._sym_tab.tab.items():
|
|
@@ -364,50 +368,6 @@ def get_definition_range(
|
|
|
364
368
|
return None
|
|
365
369
|
|
|
366
370
|
|
|
367
|
-
def locate_affected_token(
|
|
368
|
-
tokens: list[int],
|
|
369
|
-
change_start_line: int,
|
|
370
|
-
change_start_char: int,
|
|
371
|
-
change_end_line: int,
|
|
372
|
-
change_end_char: int,
|
|
373
|
-
) -> Optional[int]:
|
|
374
|
-
"""Find in which token change is occurring."""
|
|
375
|
-
token_index = 0
|
|
376
|
-
current_line = 0
|
|
377
|
-
line_char_offset = 0
|
|
378
|
-
|
|
379
|
-
while token_index < len(tokens):
|
|
380
|
-
token_line_delta = tokens[token_index]
|
|
381
|
-
token_start_char = tokens[token_index + 1]
|
|
382
|
-
token_length = tokens[token_index + 2]
|
|
383
|
-
|
|
384
|
-
if token_line_delta > 0:
|
|
385
|
-
current_line += token_line_delta
|
|
386
|
-
line_char_offset = 0
|
|
387
|
-
token_abs_start_char = line_char_offset + token_start_char
|
|
388
|
-
token_abs_end_char = token_abs_start_char + token_length
|
|
389
|
-
if (
|
|
390
|
-
current_line == change_start_line == change_end_line
|
|
391
|
-
and token_abs_start_char <= change_start_char
|
|
392
|
-
and change_end_char <= token_abs_end_char
|
|
393
|
-
):
|
|
394
|
-
return token_index
|
|
395
|
-
if (
|
|
396
|
-
current_line == change_start_line
|
|
397
|
-
and token_abs_start_char <= change_start_char < token_abs_end_char
|
|
398
|
-
):
|
|
399
|
-
return token_index
|
|
400
|
-
if (
|
|
401
|
-
current_line == change_end_line
|
|
402
|
-
and token_abs_start_char < change_end_char <= token_abs_end_char
|
|
403
|
-
):
|
|
404
|
-
return token_index
|
|
405
|
-
|
|
406
|
-
line_char_offset += token_start_char
|
|
407
|
-
token_index += 5
|
|
408
|
-
return None
|
|
409
|
-
|
|
410
|
-
|
|
411
371
|
def collect_all_symbols_in_scope(
|
|
412
372
|
sym_tab: SymbolTable, up_tree: bool = True
|
|
413
373
|
) -> list[lspt.CompletionItem]:
|
|
@@ -419,7 +379,7 @@ def collect_all_symbols_in_scope(
|
|
|
419
379
|
while current_tab is not None and current_tab not in visited:
|
|
420
380
|
visited.add(current_tab)
|
|
421
381
|
for name, symbol in current_tab.tab.items():
|
|
422
|
-
if name not in dir(builtins):
|
|
382
|
+
if name not in dir(builtins) and symbol.sym_type != SymbolType.IMPL:
|
|
423
383
|
symbols.append(
|
|
424
384
|
lspt.CompletionItem(label=name, kind=label_map(symbol.sym_type))
|
|
425
385
|
)
|
|
@@ -431,26 +391,32 @@ def collect_all_symbols_in_scope(
|
|
|
431
391
|
|
|
432
392
|
def parse_symbol_path(text: str, dot_position: int) -> list[str]:
|
|
433
393
|
"""Parse text and return a list of symbols."""
|
|
434
|
-
text = text[:dot_position].strip()
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
elif matches[i] == "":
|
|
448
|
-
pass
|
|
394
|
+
text = text[:dot_position][:-1].strip()
|
|
395
|
+
valid_character_pattern = re.compile(r"[a-zA-Z0-9_]")
|
|
396
|
+
|
|
397
|
+
reversed_text = text[::-1]
|
|
398
|
+
all_words = []
|
|
399
|
+
current_word = []
|
|
400
|
+
for char in reversed_text:
|
|
401
|
+
if valid_character_pattern.fullmatch(char):
|
|
402
|
+
current_word.append(char)
|
|
403
|
+
elif char == ".":
|
|
404
|
+
if current_word:
|
|
405
|
+
all_words.append("".join(current_word[::-1]))
|
|
406
|
+
current_word = []
|
|
449
407
|
else:
|
|
450
|
-
|
|
451
|
-
|
|
408
|
+
if current_word:
|
|
409
|
+
all_words.append("".join(current_word[::-1]))
|
|
410
|
+
current_word = []
|
|
411
|
+
break
|
|
412
|
+
|
|
413
|
+
all_words = (
|
|
414
|
+
all_words[::-1]
|
|
415
|
+
if not current_word
|
|
416
|
+
else ["".join(current_word[::-1])] + all_words[::-1]
|
|
417
|
+
)
|
|
452
418
|
|
|
453
|
-
return
|
|
419
|
+
return all_words
|
|
454
420
|
|
|
455
421
|
|
|
456
422
|
def resolve_symbol_path(sym_name: str, node_tab: SymbolTable) -> str:
|
|
@@ -463,6 +429,11 @@ def resolve_symbol_path(sym_name: str, node_tab: SymbolTable) -> str:
|
|
|
463
429
|
for name, symbol in current_tab.tab.items():
|
|
464
430
|
if name not in dir(builtins) and name == sym_name:
|
|
465
431
|
path = symbol.defn[0]._sym_type
|
|
432
|
+
if symbol.sym_type == SymbolType.ENUM_ARCH:
|
|
433
|
+
if isinstance(current_tab.owner, ast.Module):
|
|
434
|
+
return current_tab.owner.name + "." + sym_name
|
|
435
|
+
elif isinstance(current_tab.owner, ast.AstSymbolNode):
|
|
436
|
+
return current_tab.owner.name_spec._sym_type + "." + sym_name
|
|
466
437
|
return path
|
|
467
438
|
current_tab = current_tab.parent if current_tab.parent != current_tab else None
|
|
468
439
|
return ""
|
|
@@ -553,8 +524,104 @@ def resolve_completion_symbol_table(
|
|
|
553
524
|
)
|
|
554
525
|
else:
|
|
555
526
|
completion_items = []
|
|
556
|
-
|
|
527
|
+
if isinstance(current_symbol_table.owner, (ast.Ability, ast.AbilityDef)):
|
|
528
|
+
return completion_items
|
|
557
529
|
completion_items.extend(
|
|
558
530
|
collect_all_symbols_in_scope(current_symbol_table, up_tree=False)
|
|
559
531
|
)
|
|
560
532
|
return completion_items
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def get_token_start(
|
|
536
|
+
token_index: int | None, sem_tokens: list[int]
|
|
537
|
+
) -> tuple[int, int, int]:
|
|
538
|
+
"""Return the starting position of a token."""
|
|
539
|
+
if token_index is None or token_index >= len(sem_tokens):
|
|
540
|
+
return 0, 0, 0
|
|
541
|
+
|
|
542
|
+
current_line = 0
|
|
543
|
+
current_char = 0
|
|
544
|
+
current_tok_index = 0
|
|
545
|
+
|
|
546
|
+
while current_tok_index < len(sem_tokens):
|
|
547
|
+
token_line_delta = sem_tokens[current_tok_index]
|
|
548
|
+
token_start_char = sem_tokens[current_tok_index + 1]
|
|
549
|
+
|
|
550
|
+
if token_line_delta > 0:
|
|
551
|
+
current_line += token_line_delta
|
|
552
|
+
current_char = 0
|
|
553
|
+
if current_tok_index == token_index:
|
|
554
|
+
if token_line_delta > 0:
|
|
555
|
+
return (
|
|
556
|
+
current_line,
|
|
557
|
+
token_start_char,
|
|
558
|
+
token_start_char + sem_tokens[current_tok_index + 2],
|
|
559
|
+
)
|
|
560
|
+
return (
|
|
561
|
+
current_line,
|
|
562
|
+
current_char + token_start_char,
|
|
563
|
+
current_char + token_start_char + sem_tokens[current_tok_index + 2],
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
current_char += token_start_char
|
|
567
|
+
current_tok_index += 5
|
|
568
|
+
|
|
569
|
+
return (
|
|
570
|
+
current_line,
|
|
571
|
+
current_char,
|
|
572
|
+
current_char + sem_tokens[current_tok_index + 2],
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def find_surrounding_tokens(
|
|
577
|
+
change_start_line: int,
|
|
578
|
+
change_start_char: int,
|
|
579
|
+
change_end_line: int,
|
|
580
|
+
change_end_char: int,
|
|
581
|
+
sem_tokens: list[int],
|
|
582
|
+
) -> tuple[int | None, int | None, bool]:
|
|
583
|
+
"""Find the indices of the previous and next tokens surrounding the change."""
|
|
584
|
+
prev_token_index = None
|
|
585
|
+
next_token_index = None
|
|
586
|
+
inside_tok = False
|
|
587
|
+
for i, tok in enumerate(
|
|
588
|
+
[get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5)][0:]
|
|
589
|
+
):
|
|
590
|
+
if (not (prev_token_index is None or next_token_index is None)) and (
|
|
591
|
+
tok[0] > change_end_line
|
|
592
|
+
or (tok[0] == change_end_line and tok[1] > change_end_char)
|
|
593
|
+
):
|
|
594
|
+
prev_token_index = i * 5
|
|
595
|
+
break
|
|
596
|
+
elif (
|
|
597
|
+
change_start_line == tok[0] == change_end_line
|
|
598
|
+
and tok[1] <= change_start_char
|
|
599
|
+
and tok[2] >= change_end_char
|
|
600
|
+
):
|
|
601
|
+
prev_token_index = i * 5
|
|
602
|
+
inside_tok = True
|
|
603
|
+
break
|
|
604
|
+
elif (tok[0] < change_start_line) or (
|
|
605
|
+
tok[0] == change_start_line and tok[1] < change_start_char
|
|
606
|
+
):
|
|
607
|
+
prev_token_index = i * 5
|
|
608
|
+
elif (tok[0] > change_end_line) or (
|
|
609
|
+
tok[0] == change_end_line and tok[1] > change_end_char
|
|
610
|
+
):
|
|
611
|
+
next_token_index = i * 5
|
|
612
|
+
break
|
|
613
|
+
|
|
614
|
+
return prev_token_index, next_token_index, inside_tok
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
def get_line_of_code(line_number: int, lines: list[str]) -> Optional[tuple[str, int]]:
|
|
618
|
+
"""Get the line of code, and the first non-space character index."""
|
|
619
|
+
if 0 <= line_number < len(lines):
|
|
620
|
+
line = lines[line_number].rstrip("\n")
|
|
621
|
+
first_non_space = len(line) - len(line.lstrip())
|
|
622
|
+
return line, (
|
|
623
|
+
first_non_space + 4
|
|
624
|
+
if line.strip().endswith(("(", "{", "["))
|
|
625
|
+
else first_non_space
|
|
626
|
+
)
|
|
627
|
+
return None
|
jaclang/plugin/builtin.py
CHANGED
jaclang/plugin/default.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import ast as ast3
|
|
5
6
|
import fnmatch
|
|
6
7
|
import html
|
|
7
8
|
import os
|
|
@@ -10,12 +11,13 @@ import types
|
|
|
10
11
|
from collections import OrderedDict
|
|
11
12
|
from dataclasses import field
|
|
12
13
|
from functools import wraps
|
|
13
|
-
from typing import Any, Callable, Optional, Type, Union
|
|
14
|
+
from typing import Any, Callable, Mapping, Optional, Sequence, Type, Union
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
import jaclang.compiler.absyntree as ast
|
|
16
17
|
from jaclang.compiler.constant import EdgeDir, colors
|
|
18
|
+
from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass
|
|
17
19
|
from jaclang.compiler.semtable import SemInfo, SemRegistry, SemScope
|
|
18
|
-
from jaclang.
|
|
20
|
+
from jaclang.runtimelib.constructs import (
|
|
19
21
|
Architype,
|
|
20
22
|
DSFunc,
|
|
21
23
|
EdgeAnchor,
|
|
@@ -32,18 +34,20 @@ from jaclang.core.constructs import (
|
|
|
32
34
|
WalkerArchitype,
|
|
33
35
|
exec_context,
|
|
34
36
|
)
|
|
35
|
-
from jaclang.
|
|
36
|
-
from jaclang.
|
|
37
|
-
from jaclang.plugin.feature import JacFeature as Jac
|
|
38
|
-
from jaclang.plugin.spec import T
|
|
37
|
+
from jaclang.runtimelib.importer import ImportPathSpec, JacImporter, PythonImporter
|
|
38
|
+
from jaclang.runtimelib.utils import traverse_graph
|
|
39
|
+
from jaclang.plugin.feature import JacFeature as Jac # noqa: I100
|
|
40
|
+
from jaclang.plugin.spec import P, T
|
|
39
41
|
|
|
40
42
|
|
|
41
43
|
import pluggy
|
|
42
44
|
|
|
45
|
+
hookimpl = pluggy.HookimplMarker("jac")
|
|
43
46
|
|
|
44
47
|
__all__ = [
|
|
45
48
|
"EdgeAnchor",
|
|
46
49
|
"GenericEdge",
|
|
50
|
+
"hookimpl",
|
|
47
51
|
"JacTestCheck",
|
|
48
52
|
"NodeAnchor",
|
|
49
53
|
"ObjectAnchor",
|
|
@@ -54,14 +58,10 @@ __all__ = [
|
|
|
54
58
|
"WalkerArchitype",
|
|
55
59
|
"Architype",
|
|
56
60
|
"DSFunc",
|
|
57
|
-
"jac_importer",
|
|
58
61
|
"T",
|
|
59
62
|
]
|
|
60
63
|
|
|
61
64
|
|
|
62
|
-
hookimpl = pluggy.HookimplMarker("jac")
|
|
63
|
-
|
|
64
|
-
|
|
65
65
|
class JacFeatureDefaults:
|
|
66
66
|
"""Jac Feature."""
|
|
67
67
|
|
|
@@ -202,6 +202,43 @@ class JacFeatureDefaults:
|
|
|
202
202
|
|
|
203
203
|
return decorator
|
|
204
204
|
|
|
205
|
+
@staticmethod
|
|
206
|
+
@hookimpl
|
|
207
|
+
def impl_patch_filename(
|
|
208
|
+
file_loc: str,
|
|
209
|
+
) -> Callable[[Callable[P, T]], Callable[P, T]]:
|
|
210
|
+
"""Update impl file location."""
|
|
211
|
+
|
|
212
|
+
def decorator(func: Callable[P, T]) -> Callable[P, T]:
|
|
213
|
+
try:
|
|
214
|
+
code = func.__code__
|
|
215
|
+
new_code = types.CodeType(
|
|
216
|
+
code.co_argcount,
|
|
217
|
+
code.co_posonlyargcount,
|
|
218
|
+
code.co_kwonlyargcount,
|
|
219
|
+
code.co_nlocals,
|
|
220
|
+
code.co_stacksize,
|
|
221
|
+
code.co_flags,
|
|
222
|
+
code.co_code,
|
|
223
|
+
code.co_consts,
|
|
224
|
+
code.co_names,
|
|
225
|
+
code.co_varnames,
|
|
226
|
+
file_loc,
|
|
227
|
+
code.co_name,
|
|
228
|
+
code.co_qualname,
|
|
229
|
+
code.co_firstlineno,
|
|
230
|
+
code.co_linetable,
|
|
231
|
+
code.co_exceptiontable,
|
|
232
|
+
code.co_freevars,
|
|
233
|
+
code.co_cellvars,
|
|
234
|
+
)
|
|
235
|
+
func.__code__ = new_code
|
|
236
|
+
except AttributeError:
|
|
237
|
+
pass
|
|
238
|
+
return func
|
|
239
|
+
|
|
240
|
+
return decorator
|
|
241
|
+
|
|
205
242
|
@staticmethod
|
|
206
243
|
@hookimpl
|
|
207
244
|
def jac_import(
|
|
@@ -211,23 +248,32 @@ class JacFeatureDefaults:
|
|
|
211
248
|
cachable: bool,
|
|
212
249
|
mdl_alias: Optional[str],
|
|
213
250
|
override_name: Optional[str],
|
|
214
|
-
mod_bundle: Optional[Module | str],
|
|
215
251
|
lng: Optional[str],
|
|
216
252
|
items: Optional[dict[str, Union[str, Optional[str]]]],
|
|
253
|
+
reload_module: Optional[bool],
|
|
217
254
|
) -> tuple[types.ModuleType, ...]:
|
|
218
255
|
"""Core Import Process."""
|
|
219
|
-
|
|
220
|
-
target
|
|
221
|
-
base_path
|
|
222
|
-
absorb
|
|
223
|
-
cachable
|
|
224
|
-
mdl_alias
|
|
225
|
-
override_name
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
256
|
+
spec = ImportPathSpec(
|
|
257
|
+
target,
|
|
258
|
+
base_path,
|
|
259
|
+
absorb,
|
|
260
|
+
cachable,
|
|
261
|
+
mdl_alias,
|
|
262
|
+
override_name,
|
|
263
|
+
lng,
|
|
264
|
+
items,
|
|
265
|
+
)
|
|
266
|
+
if lng == "py":
|
|
267
|
+
import_result = PythonImporter(Jac.context().jac_machine).run_import(spec)
|
|
268
|
+
else:
|
|
269
|
+
import_result = JacImporter(Jac.context().jac_machine).run_import(
|
|
270
|
+
spec, reload_module
|
|
271
|
+
)
|
|
272
|
+
return (
|
|
273
|
+
(import_result.ret_mod,)
|
|
274
|
+
if absorb or not items
|
|
275
|
+
else tuple(import_result.ret_items)
|
|
229
276
|
)
|
|
230
|
-
return result
|
|
231
277
|
|
|
232
278
|
@staticmethod
|
|
233
279
|
@hookimpl
|
|
@@ -628,11 +674,153 @@ class JacFeatureDefaults:
|
|
|
628
674
|
inputs: list[tuple[str, str, str, Any]],
|
|
629
675
|
outputs: tuple,
|
|
630
676
|
action: str,
|
|
677
|
+
_globals: dict,
|
|
678
|
+
_locals: Mapping,
|
|
631
679
|
) -> Any: # noqa: ANN401
|
|
632
680
|
"""Jac's with_llm feature."""
|
|
633
681
|
raise ImportError(
|
|
634
|
-
"mtllm is not installed. Please install it with `pip install mtllm`."
|
|
682
|
+
"mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`."
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
@staticmethod
|
|
686
|
+
@hookimpl
|
|
687
|
+
def gen_llm_body(_pass: PyastGenPass, node: ast.Ability) -> list[ast3.AST]:
|
|
688
|
+
"""Generate the by LLM body."""
|
|
689
|
+
_pass.log_warning(
|
|
690
|
+
"MT-LLM is not installed. Please install it with `pip install mtllm`."
|
|
691
|
+
)
|
|
692
|
+
return [
|
|
693
|
+
_pass.sync(
|
|
694
|
+
ast3.Raise(
|
|
695
|
+
_pass.sync(
|
|
696
|
+
ast3.Call(
|
|
697
|
+
func=_pass.sync(
|
|
698
|
+
ast3.Name(id="ImportError", ctx=ast3.Load())
|
|
699
|
+
),
|
|
700
|
+
args=[
|
|
701
|
+
_pass.sync(
|
|
702
|
+
ast3.Constant(
|
|
703
|
+
value="mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`." # noqa: E501
|
|
704
|
+
)
|
|
705
|
+
)
|
|
706
|
+
],
|
|
707
|
+
keywords=[],
|
|
708
|
+
)
|
|
709
|
+
)
|
|
710
|
+
)
|
|
711
|
+
)
|
|
712
|
+
]
|
|
713
|
+
|
|
714
|
+
@staticmethod
|
|
715
|
+
@hookimpl
|
|
716
|
+
def by_llm_call(
|
|
717
|
+
_pass: PyastGenPass,
|
|
718
|
+
model: ast3.AST,
|
|
719
|
+
model_params: dict[str, ast.Expr],
|
|
720
|
+
scope: ast3.AST,
|
|
721
|
+
inputs: Sequence[Optional[ast3.AST]],
|
|
722
|
+
outputs: Sequence[Optional[ast3.AST]] | ast3.Call,
|
|
723
|
+
action: Optional[ast3.AST],
|
|
724
|
+
include_info: list[tuple[str, ast3.AST]],
|
|
725
|
+
exclude_info: list[tuple[str, ast3.AST]],
|
|
726
|
+
) -> ast3.Call:
|
|
727
|
+
"""Return the LLM Call, e.g. _Jac.with_llm()."""
|
|
728
|
+
_pass.log_warning(
|
|
729
|
+
"MT-LLM is not installed. Please install it with `pip install mtllm`."
|
|
635
730
|
)
|
|
731
|
+
return ast3.Call(
|
|
732
|
+
func=_pass.sync(
|
|
733
|
+
ast3.Attribute(
|
|
734
|
+
value=_pass.sync(ast3.Name(id="_Jac", ctx=ast3.Load())),
|
|
735
|
+
attr="with_llm",
|
|
736
|
+
ctx=ast3.Load(),
|
|
737
|
+
)
|
|
738
|
+
),
|
|
739
|
+
args=[],
|
|
740
|
+
keywords=[
|
|
741
|
+
_pass.sync(
|
|
742
|
+
ast3.keyword(
|
|
743
|
+
arg="file_loc",
|
|
744
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
745
|
+
)
|
|
746
|
+
),
|
|
747
|
+
_pass.sync(
|
|
748
|
+
ast3.keyword(
|
|
749
|
+
arg="model",
|
|
750
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
751
|
+
)
|
|
752
|
+
),
|
|
753
|
+
_pass.sync(
|
|
754
|
+
ast3.keyword(
|
|
755
|
+
arg="model_params",
|
|
756
|
+
value=_pass.sync(ast3.Dict(keys=[], values=[])),
|
|
757
|
+
)
|
|
758
|
+
),
|
|
759
|
+
_pass.sync(
|
|
760
|
+
ast3.keyword(
|
|
761
|
+
arg="scope",
|
|
762
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
763
|
+
)
|
|
764
|
+
),
|
|
765
|
+
_pass.sync(
|
|
766
|
+
ast3.keyword(
|
|
767
|
+
arg="incl_info",
|
|
768
|
+
value=_pass.sync(ast3.List(elts=[], ctx=ast3.Load())),
|
|
769
|
+
)
|
|
770
|
+
),
|
|
771
|
+
_pass.sync(
|
|
772
|
+
ast3.keyword(
|
|
773
|
+
arg="excl_info",
|
|
774
|
+
value=_pass.sync(ast3.List(elts=[], ctx=ast3.Load())),
|
|
775
|
+
)
|
|
776
|
+
),
|
|
777
|
+
_pass.sync(
|
|
778
|
+
ast3.keyword(
|
|
779
|
+
arg="inputs",
|
|
780
|
+
value=_pass.sync(ast3.List(elts=[], ctx=ast3.Load())),
|
|
781
|
+
)
|
|
782
|
+
),
|
|
783
|
+
_pass.sync(
|
|
784
|
+
ast3.keyword(
|
|
785
|
+
arg="outputs",
|
|
786
|
+
value=_pass.sync(ast3.List(elts=[], ctx=ast3.Load())),
|
|
787
|
+
)
|
|
788
|
+
),
|
|
789
|
+
_pass.sync(
|
|
790
|
+
ast3.keyword(
|
|
791
|
+
arg="action",
|
|
792
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
793
|
+
)
|
|
794
|
+
),
|
|
795
|
+
_pass.sync(
|
|
796
|
+
ast3.keyword(
|
|
797
|
+
arg="_globals",
|
|
798
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
799
|
+
)
|
|
800
|
+
),
|
|
801
|
+
_pass.sync(
|
|
802
|
+
ast3.keyword(
|
|
803
|
+
arg="_locals",
|
|
804
|
+
value=_pass.sync(ast3.Constant(value="None")),
|
|
805
|
+
)
|
|
806
|
+
),
|
|
807
|
+
],
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
@staticmethod
|
|
811
|
+
@hookimpl
|
|
812
|
+
def get_by_llm_call_args(_pass: PyastGenPass, node: ast.FuncCall) -> dict:
|
|
813
|
+
"""Get the by LLM call args."""
|
|
814
|
+
return {
|
|
815
|
+
"model": None,
|
|
816
|
+
"model_params": {},
|
|
817
|
+
"scope": None,
|
|
818
|
+
"inputs": [],
|
|
819
|
+
"outputs": [],
|
|
820
|
+
"action": None,
|
|
821
|
+
"include_info": [],
|
|
822
|
+
"exclude_info": [],
|
|
823
|
+
}
|
|
636
824
|
|
|
637
825
|
|
|
638
826
|
class JacBuiltin:
|