jaclang 0.8.4__py3-none-any.whl → 0.8.5__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 (53) hide show
  1. jaclang/cli/cli.py +74 -22
  2. jaclang/compiler/jac.lark +3 -3
  3. jaclang/compiler/larkparse/jac_parser.py +2 -2
  4. jaclang/compiler/parser.py +14 -21
  5. jaclang/compiler/passes/main/__init__.py +3 -1
  6. jaclang/compiler/passes/main/binder_pass.py +594 -0
  7. jaclang/compiler/passes/main/import_pass.py +8 -256
  8. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  9. jaclang/compiler/passes/main/pyast_gen_pass.py +35 -69
  10. jaclang/compiler/passes/main/pyast_load_pass.py +24 -13
  11. jaclang/compiler/passes/main/sem_def_match_pass.py +1 -1
  12. jaclang/compiler/passes/main/tests/fixtures/M1.jac +3 -0
  13. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +47 -0
  14. jaclang/compiler/passes/main/tests/test_binder_pass.py +111 -0
  15. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +13 -13
  16. jaclang/compiler/passes/main/tests/test_sem_def_match_pass.py +6 -6
  17. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +2 -0
  18. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +6 -0
  19. jaclang/compiler/program.py +15 -8
  20. jaclang/compiler/tests/test_sr_errors.py +32 -0
  21. jaclang/compiler/unitree.py +21 -15
  22. jaclang/langserve/engine.jac +23 -4
  23. jaclang/langserve/tests/test_server.py +13 -0
  24. jaclang/runtimelib/importer.py +33 -62
  25. jaclang/runtimelib/utils.py +29 -0
  26. jaclang/tests/fixtures/pyfunc_fmt.py +60 -0
  27. jaclang/tests/fixtures/pyfunc_fstr.py +25 -0
  28. jaclang/tests/fixtures/pyfunc_kwesc.py +33 -0
  29. jaclang/tests/fixtures/python_run_test.py +19 -0
  30. jaclang/tests/test_cli.py +67 -0
  31. jaclang/tests/test_language.py +96 -1
  32. jaclang/utils/lang_tools.py +3 -3
  33. jaclang/utils/module_resolver.py +90 -0
  34. jaclang/utils/symtable_test_helpers.py +125 -0
  35. jaclang/utils/test.py +3 -4
  36. jaclang/vendor/interegular/__init__.py +34 -0
  37. jaclang/vendor/interegular/comparator.py +163 -0
  38. jaclang/vendor/interegular/fsm.py +1015 -0
  39. jaclang/vendor/interegular/patterns.py +732 -0
  40. jaclang/vendor/interegular/py.typed +0 -0
  41. jaclang/vendor/interegular/utils/__init__.py +15 -0
  42. jaclang/vendor/interegular/utils/simple_parser.py +165 -0
  43. jaclang/vendor/interegular-0.3.3.dist-info/INSTALLER +1 -0
  44. jaclang/vendor/interegular-0.3.3.dist-info/LICENSE.txt +21 -0
  45. jaclang/vendor/interegular-0.3.3.dist-info/METADATA +64 -0
  46. jaclang/vendor/interegular-0.3.3.dist-info/RECORD +20 -0
  47. jaclang/vendor/interegular-0.3.3.dist-info/REQUESTED +0 -0
  48. jaclang/vendor/interegular-0.3.3.dist-info/WHEEL +5 -0
  49. jaclang/vendor/interegular-0.3.3.dist-info/top_level.txt +1 -0
  50. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/METADATA +1 -1
  51. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/RECORD +53 -29
  52. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/WHEEL +0 -0
  53. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,163 @@
1
+ from collections import namedtuple
2
+ from dataclasses import dataclass
3
+ from itertools import combinations
4
+ from typing import List, Tuple, Any, Dict, Iterable, Set, FrozenSet, Optional
5
+
6
+ from interegular import InvalidSyntax, REFlags
7
+ from interegular.fsm import FSM, Alphabet, anything_else
8
+ from interegular.patterns import Pattern, Unsupported, parse_pattern
9
+ from interegular.utils import logger, soft_repr
10
+
11
+
12
+ @dataclass
13
+ class ExampleCollision:
14
+ """
15
+ Captures the full text of an example collision between two regex.
16
+ `main_text` is the part that actually gets captured by the two regex
17
+ `prefix` is the part that is potentially needed for lookbehinds
18
+ `postfix` is the part that is potentially needed for lookahead
19
+ """
20
+ prefix: str
21
+ main_text: str
22
+ postfix: str
23
+
24
+ def format_multiline(self, intro: str = "Example Collision: ", indent: str = "",
25
+ force_pointer: bool = False) -> str:
26
+ """
27
+ Formats this example somewhat similar to a python syntax error.
28
+ - intro is added on the first line
29
+ - indent is added on the second line
30
+ The three parts of the example are concatenated and `^` is used to underline them.
31
+
32
+ ExampleCollision(prefix='a', main_text='cd', postfix='ef').format_multiline()
33
+
34
+ leads to
35
+
36
+ Example Collision: acdef
37
+ ^^
38
+
39
+ This function will escape the character where necessary to stay readable.
40
+ if `force_pointer` is False, the function will not produce the second line if only main_text is set
41
+ """
42
+ if len(intro) < len(indent):
43
+ raise ValueError("Can't have intro be shorter than indent")
44
+ prefix = soft_repr(self.prefix)
45
+ main_text = soft_repr(self.main_text)
46
+ postfix = soft_repr(self.postfix)
47
+ text = f"{prefix}{main_text}{postfix}"
48
+ if len(text) != len(main_text):
49
+ whitespace = ' ' * (len(intro) - len(indent) + len(prefix))
50
+ pointers = '^' * len(main_text)
51
+ return f"{intro}{text}\n{indent}{whitespace}{pointers}"
52
+ else:
53
+ return f"{intro}{text}"
54
+
55
+ @property
56
+ def full_text(self):
57
+ return self.prefix + self.main_text + self.postfix
58
+
59
+
60
+ class Comparator:
61
+ """
62
+ A class that represents the main interface for comparing a list of regex to each other.
63
+ It expects a dictionary of arbitrary labels mapped to `Pattern` instances,
64
+ but there is a utility function to create the instances `from_regex` strings.
65
+
66
+ The main interface function all expect the abitrary labels to be given, which
67
+ then get mapped to the correct `Pattern` and/or `FSM` instance.
68
+
69
+ There is a utility function `mark(a,b)` which allows to mark pairs that shouldn't
70
+ be checked again by `check`.
71
+ """
72
+
73
+ def __init__(self, patterns: Dict[Any, Pattern]):
74
+ self._patterns = patterns
75
+ self._marked_pairs: Set[FrozenSet[Any]] = set()
76
+ if not patterns: # `isdisjoint` can not be called anyway, so we don't need to create a valid state
77
+ return
78
+ self._alphabet = Alphabet.union(*(p.get_alphabet(REFlags(0)) for p in patterns.values()))[0]
79
+ prefix_postfix_s = [p.prefix_postfix for p in patterns.values()]
80
+ self._prefix_postfix = max(p[0] for p in prefix_postfix_s), max(p[1] for p in prefix_postfix_s)
81
+ self._fsms: Dict[Any, FSM] = {}
82
+ self._know_pairs: Dict[Tuple[Any, Any], bool] = {}
83
+
84
+ def get_fsm(self, a: Any) -> FSM:
85
+ if a not in self._fsms:
86
+ try:
87
+ self._fsms[a] = self._patterns[a].to_fsm(self._alphabet, self._prefix_postfix)
88
+ except Unsupported as e:
89
+ self._fsms[a] = None
90
+ logger.warning(f"Can't compile Pattern to fsm for {a}\n {repr(e)}")
91
+ except KeyError:
92
+ self._fsms[a] = None # In case it was thrown away in `from_regexes`
93
+ return self._fsms[a]
94
+
95
+ def isdisjoint(self, a: Any, b: Any) -> bool:
96
+ if (a, b) not in self._know_pairs:
97
+ fa, fb = self.get_fsm(a), self.get_fsm(b)
98
+ if fa is None or fb is None:
99
+ self._know_pairs[a, b] = True # We can't know. Assume they are disjoint
100
+ else:
101
+ self._know_pairs[a, b] = fa.isdisjoint(fb)
102
+ return self._know_pairs[a, b]
103
+
104
+ def check(self, keys: Iterable[Any] = None, skip_marked: bool = False) -> Iterable[Tuple[Any, Any]]:
105
+ if keys is None:
106
+ keys = self._patterns
107
+ for a, b in combinations(keys, 2):
108
+ if skip_marked and self.is_marked(a, b):
109
+ continue
110
+ if not self.isdisjoint(a, b):
111
+ yield a, b
112
+
113
+ def get_example_overlap(self, a: Any, b: Any, max_time: float = None) -> ExampleCollision:
114
+ pa, pb = self._patterns[a], self._patterns[b]
115
+ needed_pre = max(pa.prefix_postfix[0], pb.prefix_postfix[0])
116
+ needed_post = max(pa.prefix_postfix[1], pb.prefix_postfix[1])
117
+
118
+ # We use the optimal alphabet here instead of the general one since that
119
+ # massively improves performance by every metric.
120
+ alphabet = pa.get_alphabet(REFlags(0)).union(pb.get_alphabet(REFlags(0)))[0]
121
+ fa, fb = pa.to_fsm(alphabet, (needed_pre, needed_post)), pb.to_fsm(alphabet, (needed_pre, needed_post))
122
+ intersection = fa.intersection(fb)
123
+ if max_time is None:
124
+ max_iterations = None
125
+ else:
126
+ # We calculate an approximation for that value of max_iterations
127
+ # that makes sure for this function to finish in under max_time seconds
128
+ # This values will heavily depend on CPU, python version, exact patterns
129
+ # and probably more factors, but this should generally be in the correct
130
+ # ballpark.
131
+ max_iterations = int((max_time - 0.09)/(1.4e-6 * len(alphabet)))
132
+ try:
133
+ text = next(intersection.strings(max_iterations))
134
+ except StopIteration:
135
+ raise ValueError(f"No overlap between {a} and {b} exists")
136
+ text = ''.join(c if c != anything_else else '?' for c in text)
137
+ if needed_post > 0:
138
+ return ExampleCollision(text[:needed_pre], text[needed_pre:-needed_post], text[-needed_post:])
139
+ else:
140
+ return ExampleCollision(text[:needed_pre], text[needed_pre:], '')
141
+
142
+ def is_marked(self, a: Any, b: Any) -> bool:
143
+ return frozenset({a, b}) in self._marked_pairs
144
+
145
+ @property
146
+ def marked_pairs(self):
147
+ return self._marked_pairs
148
+
149
+ def count_marked_pairs(self):
150
+ return len(self._marked_pairs)
151
+
152
+ def mark(self, a: Any, b: Any):
153
+ self._marked_pairs.add(frozenset({a, b}))
154
+
155
+ @classmethod
156
+ def from_regexes(cls, regexes: Dict[Any, str]):
157
+ patterns = {}
158
+ for k, r in regexes.items():
159
+ try:
160
+ patterns[k] = parse_pattern(r)
161
+ except (Unsupported, InvalidSyntax) as e:
162
+ logger.warning(f"Can't compile regex to Pattern for {k}\n {repr(e)}")
163
+ return cls(patterns)