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
@@ -2,21 +2,19 @@
2
2
 
3
3
  import os
4
4
  import tempfile
5
-
5
+ from typing import Optional
6
+ from dataclasses import dataclass
7
+
8
+ from lsprotocol.types import (
9
+ DidOpenTextDocumentParams,
10
+ TextDocumentItem,
11
+ DidSaveTextDocumentParams,
12
+ DidChangeTextDocumentParams,
13
+ VersionedTextDocumentIdentifier,
14
+ )
6
15
  from jaclang.vendor.pygls.uris import from_fs_path
7
16
  from jaclang.vendor.pygls.workspace import Workspace
8
17
 
9
- from textwrap import dedent
10
-
11
-
12
- def get_jac_file_path():
13
- """Return the absolute path to the sample Jac file used for testing."""
14
- return os.path.abspath(
15
- os.path.join(
16
- os.path.dirname(__file__), "../../../../examples/manual_code/circle.jac"
17
- )
18
- )
19
-
20
18
 
21
19
  def create_temp_jac_file(initial_content: str = "") -> str:
22
20
  """Create a temporary Jac file with optional initial content and return its path."""
@@ -28,110 +26,11 @@ def create_temp_jac_file(initial_content: str = "") -> str:
28
26
  return temp.name
29
27
 
30
28
 
31
- def get_code(code: str) -> str:
32
- """Generate a sample Jac code snippet with optional test code injected."""
33
- jac_code = dedent(
34
- f'''
35
- """
36
- This module demonstrates a simple circle class and a function to calculate
37
- the area of a circle in all of Jac's glory.
38
- """
39
-
40
- import math;
41
-
42
- # Module-level global variable
43
- glob RAD = 5;
44
-
45
- """Function to calculate the area of a circle."""
46
- def calculate_area(radius: float) -> float {{
47
- return math.pi * radius * radius;
48
- }}
49
-
50
- #* (This is a multiline comment in Jac)
51
- Above we have the demonstration of a function to calculate the area of a circle.
52
- Below we have the demonstration of a class to calculate the area of a circle.
53
- *#
54
-
55
- """Enum for shape types"""
56
- enum ShapeType {{
57
- CIRCLE = "Circle",
58
- UNKNOWN = "Unknown"
59
- }}
60
-
61
- """Base class for a shape."""
62
- obj Shape {{
63
- has shape_type: ShapeType;
64
-
65
- """Abstract method to calculate the area of a shape."""
66
- def area -> float abs;
67
- }}
68
-
69
- """Circle class inherits from Shape."""
70
- obj Circle(Shape) {{
71
- def init(radius: float) {{
72
- super.init(ShapeType.CIRCLE);
73
- self.radius = radius;
74
- }}
75
-
76
- """Overridden method to calculate the area of the circle."""
77
- override def area -> float {{
78
- return math.pi * self.radius * self.radius;
79
- }}
80
- }}
81
-
82
- with entry {{
83
- c = Circle(RAD);
84
- }}
85
-
86
- # Global also works here
87
-
88
- with entry:__main__ {{
89
- # To run the program functionality
90
- print(
91
- f"Area of a circle with radius {{RAD}} using function: {{calculate_area(RAD)}}"
92
- );
93
- print(
94
- f"Area of a {{c.shape_type.value}} with radius {{RAD}} using class: {{c.area()}}"
95
- );
96
- }}
97
-
98
- # Unit Tests!
99
- glob expected_area = 78.53981633974483;
100
- {code}
101
-
102
- test calc_area {{
103
- check almostEqual(calculate_area(RAD), expected_area);
104
- }}
105
-
106
- test circle_area {{
107
- c = Circle(RAD);
108
- check almostEqual(c.area(), expected_area);
109
- }}
110
-
111
- test circle_type {{
112
- c = Circle(RAD);
113
- check c.shape_type == ShapeType.CIRCLE;
114
- }}
115
- '''
116
- )
117
- return jac_code
118
-
119
-
120
- def get_simple_code(code: str) -> str:
121
- """Generate a sample Jac code snippet with optional test code injected."""
122
- jac_code = dedent(
123
- f"""
124
-
125
- # Unit Tests!
126
- glob expected_area0 = 78.53981633974483;
127
- glob expected_area1 = 78.53981633974483;
128
- {code}
129
- glob expected_area2 = 78.53981633974483;
130
-
131
-
132
- """
133
- )
134
- return jac_code
29
+ def load_jac_template(template_file: str, code: str = "") -> str:
30
+ """Load a Jac template file and inject code into placeholder."""
31
+ with open(template_file, "r") as f:
32
+ jac_template = f.read()
33
+ return jac_template.replace("#{{INJECT_CODE}}", code)
135
34
 
136
35
 
137
36
  def create_ls_with_workspace(file_path: str):
@@ -142,3 +41,141 @@ def create_ls_with_workspace(file_path: str):
142
41
  uri = from_fs_path(file_path)
143
42
  ls.lsp._workspace = Workspace(os.path.dirname(file_path), ls)
144
43
  return uri, ls
44
+
45
+
46
+ @dataclass
47
+ class TestFile:
48
+ """Encapsulates test file information and operations."""
49
+
50
+ path: str
51
+ uri: str
52
+ code: str
53
+ version: int = 1
54
+
55
+ @classmethod
56
+ def from_template(cls, template_name: str, content: str = "") -> "TestFile":
57
+ """Create a test file from a template."""
58
+ code = load_jac_template(cls._get_template_path(template_name), content)
59
+ temp_path = create_temp_jac_file(code)
60
+ uri = from_fs_path(temp_path)
61
+ return cls(
62
+ path=temp_path,
63
+ uri=uri or "",
64
+ code=code,
65
+ )
66
+
67
+ @staticmethod
68
+ def _get_template_path(file_name: str) -> str:
69
+ """Get absolute path to test template file."""
70
+ return os.path.abspath(
71
+ os.path.join(os.path.dirname(__file__), file_name)
72
+ )
73
+
74
+ def cleanup(self):
75
+ """Remove temporary test file."""
76
+ if os.path.exists(self.path):
77
+ os.remove(self.path)
78
+
79
+ def increment_version(self) -> int:
80
+ """Increment and return the version number."""
81
+ self.version += 1
82
+ return self.version
83
+
84
+
85
+ class LanguageServerTestHelper:
86
+ """Helper class for language server testing operations."""
87
+
88
+ def __init__(self, ls, test_file: TestFile):
89
+ self.ls = ls
90
+ self.test_file = test_file
91
+
92
+ async def open_document(self) -> None:
93
+ """Open a document in the language server."""
94
+ from jaclang.langserve.server import did_open
95
+
96
+ params = DidOpenTextDocumentParams(
97
+ text_document=TextDocumentItem(
98
+ uri=self.test_file.uri,
99
+ language_id="jac",
100
+ version=self.test_file.version,
101
+ text=self.test_file.code,
102
+ )
103
+ )
104
+ await did_open(self.ls, params)
105
+
106
+ async def save_document(self, code: Optional[str] = None) -> None:
107
+ """Save a document in the language server."""
108
+ from jaclang.langserve.server import did_save
109
+
110
+ content = code if code is not None else self.test_file.code
111
+ version = self.test_file.increment_version()
112
+
113
+ if code:
114
+ self._update_workspace(code, version)
115
+
116
+ from lsprotocol.types import TextDocumentIdentifier
117
+
118
+ params = DidSaveTextDocumentParams(
119
+ text_document=TextDocumentIdentifier(uri=self.test_file.uri),
120
+ text=content
121
+ )
122
+ await did_save(self.ls, params)
123
+
124
+ async def change_document(self, code: str) -> None:
125
+ """Change document content in the language server."""
126
+ from jaclang.langserve.server import did_change
127
+
128
+ version = self.test_file.increment_version()
129
+ self._update_workspace(code, version)
130
+
131
+ params = DidChangeTextDocumentParams(
132
+ text_document=VersionedTextDocumentIdentifier(
133
+ uri=self.test_file.uri,
134
+ version=version
135
+ ),
136
+ content_changes=[{"text": code}], # type: ignore
137
+ )
138
+ await did_change(self.ls, params)
139
+
140
+ def _update_workspace(self, code: str, version: int) -> None:
141
+ """Update workspace with new document content."""
142
+ self.ls.workspace.put_text_document(
143
+ TextDocumentItem(
144
+ uri=self.test_file.uri,
145
+ language_id="jac",
146
+ version=version,
147
+ text=code,
148
+ )
149
+ )
150
+
151
+ def get_diagnostics(self) -> list:
152
+ """Get diagnostics for the current document."""
153
+ return self.ls.diagnostics.get(self.test_file.uri, [])
154
+
155
+ def get_semantic_tokens(self):
156
+ """Get semantic tokens for the current document."""
157
+ return self.ls.get_semantic_tokens(self.test_file.uri)
158
+
159
+ def assert_no_diagnostics(self) -> None:
160
+ """Assert that there are no diagnostics."""
161
+ diagnostics = self.get_diagnostics()
162
+ assert isinstance(diagnostics, list)
163
+ assert len(diagnostics) == 0, f"Expected no diagnostics, found {len(diagnostics)}"
164
+
165
+ def assert_has_diagnostics(self, count: int = 1, message_contains: Optional[str] = None) -> None:
166
+ """Assert that diagnostics exist with optional message validation."""
167
+ diagnostics = self.get_diagnostics()
168
+ assert isinstance(diagnostics, list)
169
+ assert len(diagnostics) == count, f"Expected {count} diagnostic(s), found {len(diagnostics)}"
170
+
171
+ if message_contains:
172
+ assert message_contains in diagnostics[0].message, \
173
+ f"Expected '{message_contains}' in diagnostic message"
174
+
175
+ def assert_semantic_tokens_count(self, expected_count: int) -> None:
176
+ """Assert semantic tokens data has expected count."""
177
+ tokens = self.get_semantic_tokens()
178
+ assert hasattr(tokens, "data")
179
+ assert isinstance(tokens.data, list)
180
+ assert len(tokens.data) == expected_count, \
181
+ f"Expected {expected_count} tokens, found {len(tokens.data)}"
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from jaclang.utils.test import TestCase
2
3
  from jaclang.vendor.pygls import uris
3
4
  from jaclang.vendor.pygls.workspace import Workspace
@@ -310,7 +311,6 @@ class TestJacLangServer(TestCase):
310
311
  for token_type, expected_count in expected_counts:
311
312
  self.assertEqual(str(sem_list).count(token_type), expected_count)
312
313
 
313
- @pytest.mark.xfail(reason="TODO: Fix when we have the type checker")
314
314
  def test_completion(self) -> None:
315
315
  """Test that the completions are correct."""
316
316
  lsp = JacLangServer()
@@ -318,95 +318,28 @@ class TestJacLangServer(TestCase):
318
318
  workspace = Workspace(workspace_path, lsp)
319
319
  lsp.lsp._workspace = workspace
320
320
  base_module_file = uris.from_fs_path(
321
- self.fixture_abs_path("base_module_structure.jac")
321
+ self.fixture_abs_path("completion_test_err.jac")
322
322
  )
323
323
  lsp.deep_check(base_module_file)
324
- test_cases = [
325
- (lspt.Position(38, 16), ["get_color1", "color1", "point1"], 3),
326
- (lspt.Position(42, 22), ["RED", "GREEN", "BLUE"], 3),
327
- (lspt.Position(42, 33), ["RED", "GREEN", "BLUE"], 3),
328
- (lspt.Position(42, 45), ["RED", "GREEN", "BLUE"], 3),
329
- (lspt.Position(46, 20), ["RED22", "GREEN22", "BLUE22"], 3),
330
- (lspt.Position(46, 30), ["RED22", "GREEN22", "BLUE22"], 3),
331
- (lspt.Position(46, 41), ["RED22", "GREEN22", "BLUE22"], 3),
332
- (
333
- lspt.Position(51, 32),
334
- ["RED22", "GREEN22", "BLUE22"],
335
- 3,
336
- ),
337
- (
338
- lspt.Position(65, 13),
339
- [
340
- "get_color1",
341
- "color1",
342
- "point1",
343
- "base_colorred",
344
- "pointred",
345
- "inner_red",
346
- "doubleinner",
347
- "apply_red",
348
- ],
349
- 11,
350
- ),
351
- (
352
- lspt.Position(65, 23),
353
- ["color22", "doublepoint22", "point22", "apply_inner_red", "enum_red"],
354
- 5,
355
- ),
356
- (
357
- lspt.Position(65, 31),
358
- ["RED22", "GREEN22", "BLUE22"],
359
- 3,
360
- ),
361
- (
362
- lspt.Position(35, 28),
363
- [],
364
- 0,
365
- ),
366
- (
367
- lspt.Position(72, 12),
368
- [
369
- "get_color1",
370
- "color1",
371
- "point1",
372
- "base_colorred",
373
- "pointred",
374
- "inner_red",
375
- "doubleinner",
376
- "apply_red",
377
- ],
378
- 11,
379
- ),
380
- (
381
- lspt.Position(73, 22),
382
- ["color22", "doublepoint22", "apply_inner_red", "point22", "enum_red"],
383
- 5,
384
- ),
385
- (
386
- lspt.Position(37, 12),
387
- ["self", "add", "subtract", "x", "Colorenum", "Colour1", "red", "r"],
388
- 153,
389
- None,
324
+
325
+ @dataclass
326
+ class Case:
327
+ pos: lspt.Position
328
+ expected: list[str]
329
+ trigger: str = "."
330
+
331
+ test_cases: list[Case] = [
332
+ Case(
333
+ lspt.Position(8, 8),
334
+ ["bar", "baz"],
390
335
  ),
391
336
  ]
392
- default_trigger = "."
393
337
  for case in test_cases:
394
- position, expected_completions, expected_length = case[:3]
395
- completion_trigger = case[3] if len(case) > 3 else default_trigger
396
338
  completions = lsp.get_completion(
397
- base_module_file, position, completion_trigger=completion_trigger
339
+ base_module_file, case.pos, completion_trigger=case.trigger
398
340
  ).items
399
- for completion in expected_completions:
341
+ for completion in case.expected:
400
342
  self.assertIn(completion, str(completions))
401
- self.assertEqual(expected_length, len(completions))
402
-
403
- if position == lspt.Position(73, 12):
404
- self.assertEqual(
405
- 2, str(completions).count("kind=<CompletionItemKind.Function: 3>")
406
- )
407
- self.assertEqual(
408
- 4, str(completions).count("kind=<CompletionItemKind.Field: 5>")
409
- )
410
343
 
411
344
  def test_go_to_reference(self) -> None:
412
345
  """Test that the go to reference is correct."""
@@ -419,8 +352,8 @@ class TestJacLangServer(TestCase):
419
352
  lsp.deep_check(circle_file)
420
353
  test_cases = [
421
354
  (47, 12, ["circle.jac:47:8-47:14", "69:8-69:14", "74:8-74:14"]),
422
- (54, 66, ["54:62-54:76", "65:22-65:36"]),
423
- (62, 14, ["65:43-65:56", "70:32-70:45"]),
355
+ (54, 66, ["54:62-54:76", "65:23-65:37"]),
356
+ (62, 14, ["65:44-65:57", "70:33-70:46"]),
424
357
  ]
425
358
  for line, char, expected_refs in test_cases:
426
359
  references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
@@ -608,3 +541,7 @@ class TestJacLangServer(TestCase):
608
541
  "/tests/fixtures/M1.jac:0:0-0:0",
609
542
  str(lsp.get_definition(guess_game_file, lspt.Position(29, 9))),
610
543
  )
544
+
545
+
546
+
547
+ TestJacLangServer().test_completion()
@@ -1,5 +1,6 @@
1
1
  """Utility functions for the language server."""
2
2
 
3
+
3
4
  import asyncio;
4
5
  import builtins;
5
6
  import re;
@@ -112,25 +113,21 @@ def find_deepest_symbol_node_at_pos(
112
113
 
113
114
 
114
115
  """Check if the position falls within the node's location."""
115
- def position_within_node(<>node: uni.UniNode, line: int, character: int) -> bool {
116
- if <>node.loc.first_line < (line + 1) < <>node.loc.last_line {
116
+ # All lines and columns are 1-Based
117
+ def position_within_node(n: uni.UniNode, line: int, character: int) -> bool {
118
+ if n.loc.first_line < line < n.loc.last_line {
117
119
  return True;
118
120
  }
119
- if <>node.loc.first_line == (line + 1)
120
- and <>node.loc.col_start <= (character + 1)
121
- and <>node.loc.last_line == (line + 1)
122
- and <>node.loc.col_end >= (character + 1)
123
-
124
- or <>node.loc.last_line > (line + 1)
125
- {
126
- return True;
121
+ if line < n.loc.first_line or line > n.loc.last_line {
122
+ return False;
127
123
  }
128
- if <>node.loc.last_line == (line + 1)
129
- and <>node.loc.col_start <= (character + 1) <= <>node.loc.col_end
130
- {
131
- return True;
124
+ if line == n.loc.first_line and character < n.loc.col_start {
125
+ return False;
126
+ }
127
+ if line == n.loc.last_line and character >= n.loc.col_end {
128
+ return False;
132
129
  }
133
- return False;
130
+ return True;
134
131
  }
135
132
 
136
133
 
jaclang/lib.py ADDED
@@ -0,0 +1,17 @@
1
+ """Jac Library - User-friendly interface for library mode."""
2
+
3
+ from jaclang.runtimelib.machine import JacMachineInterface
4
+
5
+ # Automatically expose all public attributes from JacMachineInterface
6
+ # This includes archetype classes (Obj, Node, Edge, Walker, Root, Path) and all methods
7
+ _jac_interface_attrs = {
8
+ name: getattr(JacMachineInterface, name)
9
+ for name in dir(JacMachineInterface)
10
+ if not name.startswith("_")
11
+ }
12
+
13
+ # Add to module globals
14
+ globals().update(_jac_interface_attrs)
15
+
16
+ # Build __all__ with all JacMachineInterface exports
17
+ __all__ = sorted(_jac_interface_attrs.keys())
@@ -69,13 +69,13 @@ class AnchorReport:
69
69
  context: dict[str, Any]
70
70
 
71
71
 
72
- DataSpatialFilter: TypeAlias = (
72
+ ObjectSpatialFilter: TypeAlias = (
73
73
  Callable[["Archetype"], bool] | "Archetype" | list["Archetype"] | None
74
74
  )
75
75
 
76
76
 
77
77
  @dataclass(eq=False, repr=False)
78
- class DataSpatialDestination:
78
+ class ObjectSpatialDestination:
79
79
  """Object-Spatial Destination."""
80
80
 
81
81
  direction: EdgeDir
@@ -92,18 +92,18 @@ class DataSpatialDestination:
92
92
 
93
93
 
94
94
  @dataclass(eq=False, repr=False)
95
- class DataSpatialPath:
95
+ class ObjectSpatialPath:
96
96
  """Object-Spatial Path."""
97
97
 
98
98
  origin: list[NodeArchetype]
99
- destinations: list[DataSpatialDestination]
99
+ destinations: list[ObjectSpatialDestination]
100
100
  edge_only: bool
101
101
  from_visit: bool
102
102
 
103
103
  def __init__(
104
104
  self,
105
105
  origin: NodeArchetype | list[NodeArchetype],
106
- destinations: list[DataSpatialDestination] | None = None,
106
+ destinations: list[ObjectSpatialDestination] | None = None,
107
107
  ) -> None:
108
108
  """Override Init."""
109
109
  if not isinstance(origin, list):
@@ -115,7 +115,7 @@ class DataSpatialPath:
115
115
 
116
116
  def convert(
117
117
  self,
118
- filter: DataSpatialFilter,
118
+ filter: ObjectSpatialFilter,
119
119
  ) -> Callable[["Archetype"], bool] | None:
120
120
  """Convert filter."""
121
121
  if not filter:
@@ -129,44 +129,44 @@ class DataSpatialPath:
129
129
  def append(
130
130
  self,
131
131
  direction: EdgeDir,
132
- edge: DataSpatialFilter,
133
- node: DataSpatialFilter,
134
- ) -> DataSpatialPath:
132
+ edge: ObjectSpatialFilter,
133
+ node: ObjectSpatialFilter,
134
+ ) -> ObjectSpatialPath:
135
135
  """Append destination."""
136
136
  self.destinations.append(
137
- DataSpatialDestination(direction, self.convert(edge), self.convert(node))
137
+ ObjectSpatialDestination(direction, self.convert(edge), self.convert(node))
138
138
  )
139
139
  return self
140
140
 
141
- def _out(
142
- self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
143
- ) -> DataSpatialPath:
141
+ def edge_out(
142
+ self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
143
+ ) -> ObjectSpatialPath:
144
144
  """Override greater than function."""
145
145
  return self.append(EdgeDir.OUT, edge, node)
146
146
 
147
- def _in(
148
- self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
149
- ) -> DataSpatialPath:
147
+ def edge_in(
148
+ self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
149
+ ) -> ObjectSpatialPath:
150
150
  """Override greater than function."""
151
151
  return self.append(EdgeDir.IN, edge, node)
152
152
 
153
- def _any(
154
- self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
155
- ) -> DataSpatialPath:
153
+ def edge_any(
154
+ self, edge: ObjectSpatialFilter = None, node: ObjectSpatialFilter = None
155
+ ) -> ObjectSpatialPath:
156
156
  """Override greater than function."""
157
157
  return self.append(EdgeDir.ANY, edge, node)
158
158
 
159
- def edge(self) -> DataSpatialPath:
159
+ def edge(self) -> ObjectSpatialPath:
160
160
  """Set edge only."""
161
161
  self.edge_only = True
162
162
  return self
163
163
 
164
- def visit(self) -> DataSpatialPath:
164
+ def visit(self) -> ObjectSpatialPath:
165
165
  """Set from visit."""
166
166
  self.from_visit = True
167
167
  return self
168
168
 
169
- def repr_builder(self, repr: str, dest: DataSpatialDestination, mark: str) -> str:
169
+ def repr_builder(self, repr: str, dest: ObjectSpatialDestination, mark: str) -> str:
170
170
  """Repr builder."""
171
171
  repr += mark
172
172
  repr += f' (edge{" filter" if dest.edge else ""}) '
@@ -361,8 +361,8 @@ class ObjectAnchor(Anchor):
361
361
  class Archetype:
362
362
  """Archetype Protocol."""
363
363
 
364
- _jac_entry_funcs_: ClassVar[list[DataSpatialFunction]] = []
365
- _jac_exit_funcs_: ClassVar[list[DataSpatialFunction]] = []
364
+ _jac_entry_funcs_: ClassVar[list[ObjectSpatialFunction]] = []
365
+ _jac_exit_funcs_: ClassVar[list[ObjectSpatialFunction]] = []
366
366
 
367
367
  @cached_property
368
368
  def __jac__(self) -> Anchor:
@@ -454,7 +454,7 @@ class Root(NodeArchetype):
454
454
 
455
455
 
456
456
  @dataclass(eq=False)
457
- class DataSpatialFunction:
457
+ class ObjectSpatialFunction:
458
458
  """Object-Spatial Function."""
459
459
 
460
460
  name: str
@@ -7,12 +7,12 @@ from .archetype import (
7
7
  AccessLevel,
8
8
  Anchor,
9
9
  Archetype,
10
- DataSpatialFunction,
11
10
  EdgeAnchor,
12
11
  EdgeArchetype,
13
12
  GenericEdge,
14
13
  NodeAnchor,
15
14
  NodeArchetype,
15
+ ObjectSpatialFunction,
16
16
  Root,
17
17
  WalkerAnchor,
18
18
  WalkerArchetype,
@@ -32,7 +32,7 @@ __all__ = [
32
32
  "WalkerArchetype",
33
33
  "GenericEdge",
34
34
  "Root",
35
- "DataSpatialFunction",
35
+ "ObjectSpatialFunction",
36
36
  "Memory",
37
37
  "ShelfStorage",
38
38
  "JacTestResult",