jaclang 0.0.1__py3-none-any.whl → 0.0.3__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 (73) hide show
  1. jaclang/__init__.py +4 -0
  2. jaclang/cli/__init__.py +7 -0
  3. jaclang/cli/cli.jac +46 -0
  4. jaclang/cli/cmds.jac +14 -0
  5. jaclang/cli/impl/__init__.py +1 -0
  6. jaclang/cli/impl/cli_impl.jac +93 -0
  7. jaclang/cli/impl/cmds_impl.jac +26 -0
  8. jaclang/core/__init__.py +12 -0
  9. jaclang/core/impl/__init__.py +1 -0
  10. jaclang/core/impl/arch_impl.jac +112 -0
  11. jaclang/core/impl/element_impl.jac +95 -0
  12. jaclang/core/impl/exec_ctx_impl.jac +17 -0
  13. jaclang/core/impl/memory_impl.jac +57 -0
  14. jaclang/core/primitives.jac +104 -0
  15. jaclang/jac/__init__.py +1 -0
  16. jaclang/jac/absyntree.py +1787 -0
  17. jaclang/jac/constant.py +46 -0
  18. jaclang/jac/importer.py +130 -0
  19. jaclang/jac/lexer.py +538 -0
  20. jaclang/jac/parser.py +1474 -0
  21. jaclang/jac/passes/__init__.py +5 -0
  22. jaclang/jac/passes/blue/__init__.py +25 -0
  23. jaclang/jac/passes/blue/ast_build_pass.py +3190 -0
  24. jaclang/jac/passes/blue/blue_pygen_pass.py +1335 -0
  25. jaclang/jac/passes/blue/decl_def_match_pass.py +278 -0
  26. jaclang/jac/passes/blue/import_pass.py +75 -0
  27. jaclang/jac/passes/blue/sub_node_tab_pass.py +30 -0
  28. jaclang/jac/passes/blue/tests/__init__.py +1 -0
  29. jaclang/jac/passes/blue/tests/test_ast_build_pass.py +61 -0
  30. jaclang/jac/passes/blue/tests/test_blue_pygen_pass.py +117 -0
  31. jaclang/jac/passes/blue/tests/test_decl_def_match_pass.py +43 -0
  32. jaclang/jac/passes/blue/tests/test_import_pass.py +18 -0
  33. jaclang/jac/passes/blue/tests/test_sub_node_pass.py +26 -0
  34. jaclang/jac/passes/blue/tests/test_type_analyze_pass.py +53 -0
  35. jaclang/jac/passes/blue/type_analyze_pass.py +731 -0
  36. jaclang/jac/passes/ir_pass.py +154 -0
  37. jaclang/jac/passes/purple/__init__.py +17 -0
  38. jaclang/jac/passes/purple/impl/__init__.py +1 -0
  39. jaclang/jac/passes/purple/impl/purple_pygen_pass_impl.jac +289 -0
  40. jaclang/jac/passes/purple/purple_pygen_pass.jac +35 -0
  41. jaclang/jac/sym_table.py +127 -0
  42. jaclang/jac/tests/__init__.py +1 -0
  43. jaclang/jac/tests/fixtures/__init__.py +1 -0
  44. jaclang/jac/tests/fixtures/activity.py +10 -0
  45. jaclang/jac/tests/fixtures/fam.jac +68 -0
  46. jaclang/jac/tests/fixtures/hello_world.jac +5 -0
  47. jaclang/jac/tests/fixtures/lexer_fam.jac +61 -0
  48. jaclang/jac/tests/fixtures/stuff.jac +6 -0
  49. jaclang/jac/tests/test_importer.py +24 -0
  50. jaclang/jac/tests/test_lexer.py +57 -0
  51. jaclang/jac/tests/test_parser.py +50 -0
  52. jaclang/jac/tests/test_utils.py +12 -0
  53. jaclang/jac/transform.py +63 -0
  54. jaclang/jac/transpiler.py +69 -0
  55. jaclang/jac/utils.py +120 -0
  56. jaclang/utils/__init__.py +1 -0
  57. jaclang/utils/fstring_parser.py +73 -0
  58. jaclang/utils/log.py +9 -0
  59. jaclang/utils/sly/__init__.py +6 -0
  60. jaclang/utils/sly/docparse.py +62 -0
  61. jaclang/utils/sly/lex.py +510 -0
  62. jaclang/utils/sly/yacc.py +2398 -0
  63. jaclang/utils/test.py +81 -0
  64. jaclang/utils/tests/__init__.py +1 -0
  65. jaclang/utils/tests/test_fstring_parser.py +55 -0
  66. jaclang-0.0.3.dist-info/METADATA +12 -0
  67. jaclang-0.0.3.dist-info/RECORD +70 -0
  68. {jaclang-0.0.1.dist-info → jaclang-0.0.3.dist-info}/WHEEL +1 -1
  69. jaclang-0.0.3.dist-info/entry_points.txt +3 -0
  70. jaclang-0.0.3.dist-info/top_level.txt +1 -0
  71. jaclang-0.0.1.dist-info/METADATA +0 -7
  72. jaclang-0.0.1.dist-info/RECORD +0 -4
  73. jaclang-0.0.1.dist-info/top_level.txt +0 -1
@@ -0,0 +1,1335 @@
1
+ """Jac Blue pass for Jaseci Ast."""
2
+ import jaclang.jac.absyntree as ast
3
+ from jaclang.jac.constant import Constants as Con
4
+ from jaclang.jac.lexer import Tokens as Tok
5
+ from jaclang.jac.passes import Pass
6
+
7
+
8
+ class BluePygenPass(Pass):
9
+ """Jac blue transpilation to python pass."""
10
+
11
+ def before_pass(self) -> None:
12
+ """Initialize pass."""
13
+ self.indent_size = 4
14
+ self.indent_level = 0
15
+ self.debuginfo = {"jac_mods": []}
16
+ self.preamble = ast.AstNode(parent=None, mod_link=None, kid=[], line=0)
17
+ self.preamble.meta["py_code"] = "from __future__ import annotations\n"
18
+ self.cur_arch = None # tracks current architype during transpilation
19
+
20
+ def enter_node(self, node: ast.AstNode) -> None:
21
+ """Enter node."""
22
+ if node:
23
+ node.meta["py_code"] = ""
24
+ return Pass.enter_node(self, node)
25
+
26
+ def indent_str(self) -> str:
27
+ """Return string for indent."""
28
+ return " " * self.indent_size * self.indent_level
29
+
30
+ def emit_ln(self, node: ast.AstNode, s: str) -> None:
31
+ """Emit code to node."""
32
+ self.emit(node, s.strip().strip("\n"))
33
+ self.emit(node, f" # {self.get_mod_index(node)} {node.line}\n")
34
+
35
+ def emit_ln_unique(self, node: ast.AstNode, s: str) -> None:
36
+ """Emit code to node."""
37
+ if s not in node.meta["py_code"]:
38
+ ilev = self.indent_level
39
+ self.indent_level = 0
40
+ self.emit_ln(node, s)
41
+ self.indent_level = ilev
42
+
43
+ def get_mod_index(self, node: ast.AstNode) -> int:
44
+ """Get module index."""
45
+ path = node.mod_link.mod_path if node.mod_link else None
46
+ if not path:
47
+ return -1
48
+ if path not in self.debuginfo["jac_mods"]:
49
+ self.debuginfo["jac_mods"].append(path)
50
+ return self.debuginfo["jac_mods"].index(path)
51
+
52
+ def emit(self, node: ast.AstNode, s: str) -> None:
53
+ """Emit code to node."""
54
+ node.meta["py_code"] += self.indent_str() + s.replace(
55
+ "\n", "\n" + self.indent_str()
56
+ )
57
+ if "\n" in node.meta["py_code"]:
58
+ node.meta["py_code"] = node.meta["py_code"].rstrip(" ")
59
+
60
+ def needs_jac_import(self) -> None:
61
+ """Check if import is needed."""
62
+ self.emit_ln_unique(
63
+ self.preamble, "from jaclang import jac_blue_import as __jac_import__"
64
+ )
65
+
66
+ def needs_enum(self) -> None:
67
+ """Check if enum is needed."""
68
+ self.emit_ln_unique(
69
+ self.preamble,
70
+ "from enum import Enum as __jac_Enum__, auto as __jac_auto__",
71
+ )
72
+
73
+ def emit_jac_error_handler(self, node: ast.AstNode) -> None:
74
+ """Emit error handler."""
75
+ self.emit_ln_unique(self.preamble, "import traceback as __jac_traceback__")
76
+ self.emit_ln_unique(
77
+ self.preamble, "from jaclang import handle_jac_error as __jac_error__"
78
+ )
79
+ self.emit_ln(node, "except Exception as e:")
80
+ self.indent_level += 1
81
+ # self.emit_ln(node, "__jac_traceback__.print_exc()")
82
+ self.emit_ln(node, "tb = __jac_traceback__.extract_tb(e.__traceback__)")
83
+ self.emit_ln(node, "__jac_tmp__ = __jac_error__(_jac_pycodestring_, e, tb)")
84
+ self.emit_ln(node, "print(__jac_tmp__)\nraise e")
85
+ self.emit_ln(
86
+ node,
87
+ "raise type(e)(str(e) + '\\nOriginal Snippet:\\n' + __jac_tmp__) "
88
+ "if 'Original Snippet:' not in str(e) else e",
89
+ )
90
+ self.indent_level -= 1
91
+
92
+ def decl_def_missing(self, decl: str = "this") -> None:
93
+ """Warn about declaration."""
94
+ self.error(
95
+ f"Unable to find definition for {decl} declaration. Perhaps there's an `include` missing?"
96
+ )
97
+
98
+ def ds_feature_warn(self) -> None:
99
+ """Warn about feature."""
100
+ self.warning("Data spatial features not supported in bootstrap Jac.")
101
+
102
+ def exit_parse(self, node: ast.Parse) -> None:
103
+ """Sub objects.
104
+
105
+ name: str,
106
+ """
107
+ self.error(f"Parse node should not be in this AST!! {node.name}")
108
+ raise ValueError("Parse node should not be in AST after being Built!!")
109
+
110
+ def exit_token(self, node: ast.Token) -> None:
111
+ """Sub objects.
112
+
113
+ name: str,
114
+ value: str,
115
+ col_start: int,
116
+ col_end: int,
117
+ """
118
+ self.emit(node, node.value)
119
+
120
+ def exit_name(self, node: ast.Name) -> None:
121
+ """Sub objects.
122
+
123
+ name: str,
124
+ value: str,
125
+ col_start: int,
126
+ col_end: int,
127
+ already_declared: bool,
128
+ """
129
+ self.emit(node, node.value)
130
+
131
+ def exit_constant(self, node: ast.Constant) -> None:
132
+ """Sub objects.
133
+
134
+ name: str,
135
+ value: str,
136
+ col_start: int,
137
+ col_end: int,
138
+ typ: type,
139
+ """
140
+ self.emit(node, node.value)
141
+
142
+ def exit_module(self, node: ast.Module) -> None:
143
+ """Sub objects.
144
+
145
+ name: str,
146
+ doc: Token,
147
+ body: "Elements",
148
+ """
149
+ self.emit_ln(node, node.doc.value)
150
+ self.emit(node, self.preamble.meta["py_code"])
151
+ if node.body:
152
+ self.emit(node, node.body.meta["py_code"])
153
+ self.emit(node, f'""" {Con.JAC_DEBUG_SPLITTER}\n')
154
+ for i in self.debuginfo["jac_mods"]:
155
+ self.emit(node, f"{i}\n")
156
+ self.emit(node, f'{Con.JAC_DEBUG_SPLITTER} """\n')
157
+ self.ir = node
158
+ self.ir.meta["py_code"] = self.ir.meta["py_code"].rstrip()
159
+
160
+ def exit_elements(self, node: ast.Elements) -> None:
161
+ """Sub objects.
162
+
163
+ elements: list[GlobalVars | Test | ModuleCode | Import | Architype | Ability | AbilitySpec],
164
+ """
165
+ for i in node.elements:
166
+ self.emit(node, i.meta["py_code"])
167
+ self.emit(node, "\n")
168
+
169
+ def exit_global_vars(self, node: ast.GlobalVars) -> None:
170
+ """Sub objects.
171
+
172
+ doc: Optional["Token"],
173
+ access: Optional[Token],
174
+ assignments: "AssignmentList",
175
+ is_frozen: bool,
176
+ """
177
+ if node.doc:
178
+ self.emit_ln(node, node.doc.value)
179
+ self.emit(node, node.assignments.meta["py_code"])
180
+
181
+ # NOTE: Incomplete for Jac Purple and Red
182
+ def exit_test(self, node: ast.Test) -> None:
183
+ """Sub objects.
184
+
185
+ name: Token,
186
+ doc: Optional["Token"],
187
+ description: Token,
188
+ body: "CodeBlock",
189
+ """
190
+ self.warning("Test feature not supported in bootstrap Jac.")
191
+
192
+ def exit_module_code(self, node: ast.ModuleCode) -> None:
193
+ """Sub objects.
194
+
195
+ doc: Optional["Token"],
196
+ body: "CodeBlock",
197
+ """
198
+ if node.doc:
199
+ self.emit_ln(node, node.doc.value)
200
+ self.emit(node, node.body.meta["py_code"])
201
+
202
+ def exit_import(self, node: ast.Import) -> None:
203
+ """Sub objects.
204
+
205
+ lang: Token,
206
+ path: "ModulePath",
207
+ alias: Optional[Token],
208
+ items: Optional["ModuleItems"],
209
+ is_absorb: bool, # For includes
210
+ self.sub_module = None
211
+ """
212
+ if node.lang.value == Con.JAC_LANG_IMP: # injects module into sys.modules
213
+ self.needs_jac_import()
214
+ self.emit_ln(
215
+ node,
216
+ f"__jac_import__(target='{node.path.meta['py_code']}', base_path=__file__)",
217
+ )
218
+ if node.is_absorb:
219
+ self.emit_ln(
220
+ node,
221
+ f"from {node.path.meta['py_code']} import *",
222
+ )
223
+ if node.items:
224
+ self.warning(
225
+ "Includes import * in target module into current namespace."
226
+ )
227
+ if not node.items:
228
+ if not node.alias:
229
+ self.emit_ln(node, f"import {node.path.meta['py_code']}")
230
+ else:
231
+ self.emit_ln(
232
+ node,
233
+ f"import {node.path.meta['py_code']} as {node.alias.meta['py_code']}",
234
+ )
235
+ else:
236
+ self.emit_ln(
237
+ node,
238
+ f"from {node.path.meta['py_code']} import {node.items.meta['py_code']}",
239
+ )
240
+
241
+ def exit_module_path(self, node: ast.ModulePath) -> None:
242
+ """Sub objects.
243
+
244
+ path: list[Token],
245
+ """
246
+ self.emit(node, "".join([i.value for i in node.path]))
247
+
248
+ def exit_module_items(self, node: ast.ModuleItems) -> None:
249
+ """Sub objects.
250
+
251
+ items: list["ModuleItem"],
252
+ """
253
+ self.emit(node, ", ".join([i.meta["py_code"] for i in node.items]))
254
+
255
+ def exit_module_item(self, node: ast.ModuleItem) -> None:
256
+ """Sub objects.
257
+
258
+ name: Token,
259
+ alias: Optional[Token],
260
+ """
261
+ if node.alias:
262
+ self.emit(node, node.name.value + " as " + node.alias.value)
263
+ else:
264
+ self.emit(node, node.name.value)
265
+
266
+ # NOTE: Incomplete for Jac Purple and Red
267
+ def exit_architype(self, node: ast.Architype) -> None:
268
+ """Sub objects.
269
+
270
+ name: Name,
271
+ arch_type: Token,
272
+ doc: Optional[Token],
273
+ decorators: Optional["Decorators"],
274
+ access: Optional[Token],
275
+ base_classes: "BaseClasses",
276
+ body: Optional["ArchBlock"],
277
+ """
278
+ if node.decorators:
279
+ self.emit(node, node.decorators.meta["py_code"])
280
+ if not len(node.base_classes.base_classes):
281
+ self.emit_ln(node, f"class {node.name.meta['py_code']}:")
282
+ else:
283
+ self.emit_ln(
284
+ node,
285
+ f"class {node.name.meta['py_code']}({node.base_classes.meta['py_code']}):",
286
+ )
287
+ self.indent_level += 1
288
+ if node.doc:
289
+ self.emit_ln(node, node.doc.value)
290
+ if node.body:
291
+ self.emit(node, node.body.meta["py_code"])
292
+ else:
293
+ self.decl_def_missing(node.name.meta["py_code"])
294
+ self.indent_level -= 1
295
+
296
+ def exit_arch_def(self, node: ast.ArchDef) -> None:
297
+ """Sub objects.
298
+
299
+ doc: Optional[Token],
300
+ mod: Optional["NameList"],
301
+ arch: "ObjectRef | NodeRef | EdgeRef | WalkerRef",
302
+ body: "ArchBlock",
303
+ """
304
+
305
+ def exit_decorators(self, node: ast.Decorators) -> None:
306
+ """Sub objects.
307
+
308
+ calls: list["ExprType"],
309
+ """
310
+ for i in node.calls:
311
+ self.emit_ln(node, "@" + i.meta["py_code"])
312
+
313
+ def exit_base_classes(self, node: ast.BaseClasses) -> None:
314
+ """Sub objects.
315
+
316
+ base_classes: list[NameList],
317
+ """
318
+ self.emit(node, ", ".join([i.meta["py_code"] for i in node.base_classes]))
319
+
320
+ # NOTE: Incomplete for Jac Purple and Red
321
+ def exit_ability(self, node: ast.Ability) -> None:
322
+ """Sub objects.
323
+
324
+ name: Name,
325
+ is_func: bool,
326
+ is_async: bool,
327
+ is_static: bool,
328
+ doc: Optional[Token],
329
+ decorators: Optional["Decorators"],
330
+ access: Optional[Token],
331
+ signature: Optional["FuncSignature | TypeSpec | EventSignature"],
332
+ body: Optional["CodeBlock"],
333
+ arch_attached: Optional["ArchBlock"] = None,
334
+ """
335
+ if node.decorators:
336
+ self.emit(node, node.decorators.meta["py_code"])
337
+ if node.signature and node.is_func:
338
+ if node.arch_attached and not node.is_static:
339
+ self.emit_ln(
340
+ node, f"def {node.name.value}(self{node.signature.meta['py_code']}:"
341
+ )
342
+ else:
343
+ if node.arch_attached and node.is_static:
344
+ self.emit_ln(node, "@classmethod")
345
+ self.emit_ln(
346
+ node, f"def {node.name.value}({node.signature.meta['py_code']}:"
347
+ )
348
+ else:
349
+ if node.arch_attached:
350
+ self.emit_ln(node, f"def {node.name.value}(self):")
351
+ else:
352
+ self.emit_ln(node, f"def {node.name.value}():")
353
+ self.indent_level += 1
354
+ if node.doc:
355
+ self.emit_ln(node, node.doc.value)
356
+ if node.body:
357
+ self.emit_ln(node, "try:")
358
+ self.indent_level += 1
359
+ self.emit(node, node.body.meta["py_code"])
360
+ self.indent_level -= 1
361
+ self.emit_jac_error_handler(node)
362
+ else:
363
+ self.decl_def_missing(node.name.value)
364
+ self.indent_level -= 1
365
+
366
+ def exit_ability_def(self, node: ast.AbilityDef) -> None:
367
+ """Sub objects.
368
+
369
+ doc: Optional[Token],
370
+ mod: Optional["NameList"],
371
+ ability: AbilityRef,
372
+ body: CodeBlock,
373
+ """
374
+
375
+ def exit_arch_block(self, node: ast.ArchBlock) -> None:
376
+ """Sub objects.
377
+
378
+ members: list["ArchHas | Ability"],
379
+ """
380
+ init_func = None
381
+ for i in node.members:
382
+ if type(i) == ast.Ability and i.name.value == Con.INIT_FUNC:
383
+ init_func = i
384
+ break
385
+ if init_func and init_func.signature and init_func.is_func:
386
+ self.emit_ln(
387
+ node, f"def __init__(self{init_func.signature.meta['py_code']}:"
388
+ )
389
+ else:
390
+ self.emit_ln(node, "def __init__(self, *args, **kwargs):")
391
+
392
+ self.indent_level += 1
393
+ self.emit_ln(node, '"""Init generated by Jac."""')
394
+ for i in node.members:
395
+ if type(i) == ast.ArchHas and not i.is_static:
396
+ self.emit_ln(node, f"self.has_{i.h_id}()")
397
+ if init_func:
398
+ params = []
399
+ if (
400
+ type(init_func.signature) == ast.FuncSignature
401
+ and init_func.signature.params
402
+ ):
403
+ params = [x.name.value for x in init_func.signature.params.params]
404
+ self.emit_ln(node, f"self.{Con.INIT_FUNC}({', '.join(params)})")
405
+ self.emit_ln(node, "super().__init__(*args, **kwargs)")
406
+ self.indent_level -= 1
407
+ for i in node.members:
408
+ self.emit(node, i.meta["py_code"])
409
+ self.emit(node, "\n")
410
+
411
+ def exit_arch_has(self, node: ast.ArchHas) -> None:
412
+ """Sub objects.
413
+
414
+ doc: Optional[Token],
415
+ is_static: bool,
416
+ access: Optional[Token],
417
+ vars: "HasVarList",
418
+ is_frozen: bool,
419
+ """
420
+ if node.is_static:
421
+ if node.doc:
422
+ self.emit_ln(node, node.doc.value)
423
+ self.emit_ln(node, node.vars.meta["py_code"].replace("self.", ""))
424
+ else:
425
+ self.emit_ln(node, f"def has_{node.h_id}(self):")
426
+ self.indent_level += 1
427
+ if node.doc:
428
+ self.emit_ln(node, node.doc.value)
429
+ self.emit(node, node.vars.meta["py_code"])
430
+ self.indent_level -= 1
431
+
432
+ def exit_has_var_list(self, node: ast.HasVarList) -> None:
433
+ """Sub objects.
434
+
435
+ vars: list[HasVar],
436
+ """
437
+ for i in node.vars:
438
+ self.emit_ln(node, i.meta["py_code"])
439
+
440
+ def exit_has_var(self, node: ast.HasVar) -> None:
441
+ """Sub objects.
442
+
443
+ name: Token,
444
+ type_tag: TypeSpec,
445
+ value: Optional["ExprType"],
446
+ """
447
+ if node.value:
448
+ self.emit(
449
+ node,
450
+ f"self.{node.name.value}: {node.type_tag.meta['py_code']} = {node.value.meta['py_code']}",
451
+ )
452
+ else:
453
+ self.emit(
454
+ node, f"self.{node.name.value}: {node.type_tag.meta['py_code']} = None"
455
+ )
456
+
457
+ def exit_type_spec_list(self, node: ast.TypeSpecList) -> None:
458
+ """Sub objects.
459
+
460
+ types: list[TypeSpec],
461
+ """
462
+ self.emit(node, "|".join([i.meta["py_code"] for i in node.types]))
463
+
464
+ def exit_type_spec(self, node: ast.TypeSpec) -> None:
465
+ """Sub objects.
466
+
467
+ typ: "Token | NameList",
468
+ list_nest: TypeSpec,
469
+ dict_nest: TypeSpec,
470
+ """
471
+ if node.dict_nest:
472
+ self.emit(
473
+ node,
474
+ f"dict[{node.list_nest.meta['py_code']}, {node.dict_nest.meta['py_code']}]",
475
+ )
476
+ elif node.list_nest:
477
+ self.emit(node, f"list[{node.list_nest.meta['py_code']}]")
478
+ else:
479
+ self.emit(node, node.spec_type.meta["py_code"])
480
+
481
+ # NOTE: Incomplete for Jac Purple and Red
482
+ def exit_event_signature(self, node: ast.EventSignature) -> None:
483
+ """Sub objects.
484
+
485
+ event: Token,
486
+ arch_tag_info: Optional["TypeList | TypeSpec"],
487
+ return_type: Optional["TypeSpec"],
488
+ """
489
+ self.error("Event style abilities not supported in bootstrap Jac")
490
+
491
+ def exit_name_list(self, node: ast.NameList) -> None:
492
+ """Sub objects.
493
+
494
+ names: list[all_refs],
495
+ """
496
+ self.emit(node, ".".join([i.meta["py_code"] for i in node.names]))
497
+
498
+ def exit_func_signature(self, node: ast.FuncSignature) -> None:
499
+ """Sub objects.
500
+
501
+ params: Optional[FuncParams],
502
+ return_type: Optional[TypeSpec],
503
+ self.is_arch_attached = False
504
+ """
505
+ if node.params:
506
+ if (
507
+ type(node.parent) == ast.Ability
508
+ and node.parent.arch_attached
509
+ and not node.parent.is_static
510
+ ):
511
+ self.emit(node, ", ")
512
+ self.emit(node, node.params.meta["py_code"])
513
+ if (
514
+ type(node.parent) == ast.Ability
515
+ and node.parent.arch_attached
516
+ and node.parent.name.value == Con.INIT_FUNC
517
+ ):
518
+ self.emit(node, ", *args, **kwargs")
519
+ self.emit(node, ")")
520
+ if node.return_type:
521
+ self.emit(node, f" -> {node.return_type.meta['py_code']}")
522
+
523
+ def exit_func_params(self, node: ast.FuncParams) -> None:
524
+ """Sub objects.
525
+
526
+ params: list["ParamVar"],
527
+ """
528
+ first_out = False
529
+ for i in node.params:
530
+ self.emit(node, ", ") if first_out else None
531
+ self.emit(node, i.meta["py_code"])
532
+ first_out = True
533
+
534
+ def exit_param_var(self, node: ast.ParamVar) -> None:
535
+ """Sub objects.
536
+
537
+ name: Token,
538
+ unpack: Optional[Token],
539
+ type_tag: "TypeSpec",
540
+ value: Optional["ExprType"],
541
+ """
542
+ if node.unpack:
543
+ self.emit(node, f"{node.unpack.value}")
544
+ if node.value:
545
+ self.emit(
546
+ node,
547
+ f"{node.name.value}: {node.type_tag.meta['py_code']} = {node.value.meta['py_code']}",
548
+ )
549
+ else:
550
+ self.emit(node, f"{node.name.value}: {node.type_tag.meta['py_code']}")
551
+
552
+ def exit_enum(self, node: ast.Enum) -> None:
553
+ """Sub objects.
554
+
555
+ name: Name,
556
+ doc: Optional[Token],
557
+ decorators: Optional[Decorators],
558
+ access: Optional[Token],
559
+ base_classes: BaseClasses,
560
+ body: Optional[EnumBlock],
561
+ """
562
+ if node.decorators:
563
+ self.emit_ln(node, node.decorators.meta["py_code"])
564
+ if len(node.base_classes.base_classes):
565
+ self.emit_ln(
566
+ node,
567
+ f"class {node.name.meta['py_code']}({node.base_classes.meta['py_code']}):",
568
+ )
569
+ else:
570
+ self.needs_enum()
571
+ self.emit_ln(node, f"class {node.name.value}(__jac_Enum__):")
572
+ self.indent_level += 1
573
+ if node.doc:
574
+ self.emit_ln(node, node.doc.value)
575
+ if node.body:
576
+ self.emit(node, node.body.meta["py_code"])
577
+ else:
578
+ self.decl_def_missing(node.name.meta["py_code"])
579
+ self.indent_level -= 1
580
+
581
+ def exit_enum_def(self, node: ast.EnumDef) -> None:
582
+ """Sub objects.
583
+
584
+ doc: Optional[Token],
585
+ mod: Optional[NameList],
586
+ body: EnumBlock,
587
+ """
588
+
589
+ def exit_enum_block(self, node: ast.EnumBlock) -> None:
590
+ """Sub objects.
591
+
592
+ stmts: list['Name|Assignment'],
593
+ """
594
+ for i in node.stmts:
595
+ if type(i) == ast.Name:
596
+ self.emit_ln(node, i.meta["py_code"] + " = __jac_auto__()")
597
+ else:
598
+ self.emit(node, i.meta["py_code"])
599
+
600
+ def exit_code_block(self, node: ast.CodeBlock) -> None:
601
+ """Sub objects.
602
+
603
+ stmts: list["StmtType"],
604
+ """
605
+ if len(node.stmts) == 0:
606
+ self.emit_ln(node, "pass")
607
+ for i in node.stmts:
608
+ self.emit(node, i.meta["py_code"])
609
+ if len(i.meta["py_code"]) and i.meta["py_code"][-1] != "\n":
610
+ self.emit_ln(node, "\n")
611
+
612
+ def exit_if_stmt(self, node: ast.IfStmt) -> None:
613
+ """Sub objects.
614
+
615
+ condition: ExprType,
616
+ body: CodeBlock,
617
+ elseifs: Optional[ElseIfs],
618
+ else_body: Optional[ElseStmt],
619
+ """
620
+ self.emit_ln(node, f"if {node.condition.meta['py_code']}:")
621
+ self.indent_level += 1
622
+ self.emit(node, node.body.meta["py_code"])
623
+ self.indent_level -= 1
624
+ self.emit(node, "\n")
625
+ if node.elseifs:
626
+ self.emit(node, node.elseifs.meta["py_code"])
627
+ if node.else_body:
628
+ self.emit(node, node.else_body.meta["py_code"])
629
+
630
+ def exit_typed_ctx_block(self, node: ast.TypedCtxBlock) -> None:
631
+ """Sub objects.
632
+
633
+ type_ctx: TypeList,
634
+ body: CodeBlock,
635
+ """
636
+ self.ds_feature_warn()
637
+
638
+ def exit_else_ifs(self, node: ast.ElseIfs) -> None:
639
+ """Sub objects.
640
+
641
+ elseifs: list[IfStmt],
642
+ """
643
+ for i in node.elseifs:
644
+ self.emit_ln(node, f"elif {i.condition.meta['py_code']}:")
645
+ self.indent_level += 1
646
+ self.emit(node, i.body.meta["py_code"])
647
+ self.indent_level -= 1
648
+ self.emit(node, "\n")
649
+
650
+ def exit_else_stmt(self, node: ast.ElseStmt) -> None:
651
+ """Sub objects.
652
+
653
+ body: CodeBlock,
654
+ """
655
+ self.emit_ln(node, "else:")
656
+ self.indent_level += 1
657
+ self.emit(node, node.body.meta["py_code"])
658
+ self.indent_level -= 1
659
+ self.emit(node, "\n")
660
+
661
+ def exit_try_stmt(self, node: ast.TryStmt) -> None:
662
+ """Sub objects.
663
+
664
+ body: CodeBlock,
665
+ excepts: Optional[ExceptList],
666
+ finally_body: Optional[FinallyStmt],
667
+ """
668
+ self.emit_ln(node, "try:")
669
+ self.indent_level += 1
670
+ self.emit_ln(node, node.body.meta["py_code"])
671
+ self.indent_level -= 1
672
+ if node.excepts:
673
+ self.emit_ln(node, node.excepts.meta["py_code"])
674
+ if node.finally_body:
675
+ self.emit_ln(node, node.finally_body.meta["py_code"])
676
+
677
+ def exit_except(self, node: ast.Except) -> None:
678
+ """Sub objects.
679
+
680
+ typ: ExprType,
681
+ name: Optional[Token],
682
+ body: CodeBlock,
683
+ """
684
+ if node.name:
685
+ self.emit_ln(
686
+ node, f"except {node.ex_type.meta['py_code']} as {node.name.value}:"
687
+ )
688
+ else:
689
+ self.emit_ln(node, f"except {node.ex_type.meta['py_code']}:")
690
+ self.indent_level += 1
691
+ self.emit_ln(node, node.body.meta["py_code"])
692
+ self.indent_level -= 1
693
+
694
+ def exit_except_list(self, node: ast.ExceptList) -> None:
695
+ """Sub objects.
696
+
697
+ excepts: list[Except],
698
+ """
699
+ for i in node.excepts:
700
+ self.emit_ln(node, i.meta["py_code"])
701
+
702
+ def exit_finally_stmt(self, node: ast.FinallyStmt) -> None:
703
+ """Sub objects.
704
+
705
+ body: CodeBlock,
706
+ """
707
+ self.emit_ln(node, "finally:")
708
+ self.indent_level += 1
709
+ self.emit_ln(node, node.body.meta["py_code"])
710
+ self.indent_level -= 1
711
+
712
+ def exit_iter_for_stmt(self, node: ast.IterForStmt) -> None:
713
+ """Sub objects.
714
+
715
+ iter: Assignment,
716
+ condition: ExprType,
717
+ count_by: ExprType,
718
+ body: CodeBlock,
719
+ """
720
+ self.emit_ln(node, f"{node.iter.meta['py_code']}")
721
+ self.emit_ln(node, f"while {node.condition.meta['py_code']}:")
722
+ self.indent_level += 1
723
+ self.emit_ln(node, node.body.meta["py_code"])
724
+ self.emit_ln(node, f"{node.count_by.meta['py_code']}")
725
+ self.indent_level -= 1
726
+
727
+ def exit_in_for_stmt(self, node: ast.InForStmt) -> None:
728
+ """Sub objects.
729
+
730
+ name: Token,
731
+ collection: ExprType,
732
+ body: CodeBlock,
733
+ """
734
+ self.emit_ln(
735
+ node, f"for {node.name.value} in {node.collection.meta['py_code']}:"
736
+ )
737
+ self.indent_level += 1
738
+ self.emit_ln(node, node.body.meta["py_code"])
739
+ self.indent_level -= 1
740
+
741
+ def exit_dict_for_stmt(self, node: ast.DictForStmt) -> None:
742
+ """Sub objects.
743
+
744
+ k_name: Token,
745
+ v_name: Token,
746
+ collection: ExprType,
747
+ body: CodeBlock,
748
+ """
749
+ self.emit_ln(
750
+ node,
751
+ f"for {node.k_name.value}, {node.v_name.value} in {node.collection.meta['py_code']}:",
752
+ )
753
+ self.indent_level += 1
754
+ self.emit_ln(node, node.body.meta["py_code"])
755
+ self.indent_level -= 1
756
+
757
+ def exit_while_stmt(self, node: ast.WhileStmt) -> None:
758
+ """Sub objects.
759
+
760
+ condition: ExprType,
761
+ body: CodeBlock,
762
+ """
763
+ self.emit_ln(node, f"while {node.condition.meta['py_code']}:")
764
+ self.indent_level += 1
765
+ self.emit_ln(node, node.body.meta["py_code"])
766
+ self.indent_level -= 1
767
+
768
+ def exit_with_stmt(self, node: ast.WithStmt) -> None:
769
+ """Sub objects.
770
+
771
+ exprs: "ExprAsItemList",
772
+ body: "CodeBlock",
773
+ """
774
+ self.emit_ln(node, f"with {node.exprs.meta['py_code']}:")
775
+ self.indent_level += 1
776
+ self.emit_ln(node, node.body.meta["py_code"])
777
+ self.indent_level -= 1
778
+
779
+ def exit_expr_as_item_list(self, node: ast.ExprAsItemList) -> None:
780
+ """Sub objects.
781
+
782
+ items: list["ExprAsItem"],
783
+ """
784
+ self.emit(node, ", ".join([i.meta["py_code"] for i in node.items]))
785
+
786
+ def exit_expr_as_item(self, node: ast.ExprAsItem) -> None:
787
+ """Sub objects.
788
+
789
+ expr: "ExprType",
790
+ alias: Optional[Token],
791
+ """
792
+ if node.alias:
793
+ self.emit(node, node.expr.meta["py_code"] + " as " + node.alias.value)
794
+ else:
795
+ self.emit(node, node.expr.meta["py_code"])
796
+
797
+ def exit_raise_stmt(self, node: ast.RaiseStmt) -> None:
798
+ """Sub objects.
799
+
800
+ cause: Optional[ExprType],
801
+ """
802
+ if node.cause:
803
+ self.emit_ln(node, f"raise {node.cause.meta['py_code']}")
804
+ else:
805
+ self.emit_ln(node, "raise")
806
+
807
+ def exit_assert_stmt(self, node: ast.AssertStmt) -> None:
808
+ """Sub objects.
809
+
810
+ condition: ExprType,
811
+ error_msg: Optional[ExprType],
812
+ """
813
+ if node.error_msg:
814
+ self.emit_ln(
815
+ node,
816
+ f"assert {node.condition.meta['py_code']}, {node.error_msg.meta['py_code']}",
817
+ )
818
+ else:
819
+ self.emit_ln(node, f"assert {node.condition.meta['py_code']}")
820
+
821
+ # NOTE: Incomplete for Jac Purple and Red
822
+ def exit_ctrl_stmt(self, node: ast.CtrlStmt) -> None:
823
+ """Sub objects.
824
+
825
+ ctrl: Token,
826
+ """
827
+ if node.ctrl.name == Tok.KW_SKIP:
828
+ self.error("skip is not supported in bootstrap Jac")
829
+ else:
830
+ self.emit_ln(node, node.ctrl.value)
831
+
832
+ def exit_delete_stmt(self, node: ast.DeleteStmt) -> None:
833
+ """Sub objects.
834
+
835
+ target: ExprType,
836
+ """
837
+ self.emit_ln(node, f"del {node.target.meta['py_code']}")
838
+
839
+ # NOTE: Incomplete for Jac Purple and Red
840
+ def exit_report_stmt(self, node: ast.ReportStmt) -> None:
841
+ """Sub objects.
842
+
843
+ expr: ExprType,
844
+ """
845
+ self.ds_feature_warn()
846
+
847
+ def exit_return_stmt(self, node: ast.ReturnStmt) -> None:
848
+ """Sub objects.
849
+
850
+ expr: Optional[ExprType],
851
+ """
852
+ if node.expr:
853
+ self.emit_ln(node, f"return {node.expr.meta['py_code']}")
854
+ else:
855
+ self.emit_ln(node, "return")
856
+
857
+ def exit_yield_stmt(self, node: ast.YieldStmt) -> None:
858
+ """Sub objects.
859
+
860
+ expr: Optional[ExprType],
861
+ """
862
+ if node.expr:
863
+ self.emit_ln(node, f"yield {node.expr.meta['py_code']}")
864
+ else:
865
+ self.emit_ln(node, "yield")
866
+
867
+ # NOTE: Incomplete for Jac Purple and Red
868
+ def exit_ignore_stmt(self, node: ast.IgnoreStmt) -> None:
869
+ """Sub objects.
870
+
871
+ target: ExprType,
872
+ """
873
+ self.ds_feature_warn()
874
+
875
+ # NOTE: Incomplete for Jac Purple and Red
876
+ def exit_visit_stmt(self, node: ast.VisitStmt) -> None:
877
+ """Sub objects.
878
+
879
+ vis_type: Optional[Token],
880
+ target: Optional["ExprType"],
881
+ else_body: Optional["ElseStmt"],
882
+ """
883
+ self.ds_feature_warn()
884
+
885
+ # NOTE: Incomplete for Jac Purple and Red
886
+ def exit_revisit_stmt(self, node: ast.RevisitStmt) -> None:
887
+ """Sub objects.
888
+
889
+ hops: Optional[ExprType],
890
+ else_body: Optional[ElseStmt],
891
+ """
892
+ self.ds_feature_warn()
893
+
894
+ # NOTE: Incomplete for Jac Purple and Red
895
+ def exit_disengage_stmt(self, node: ast.DisengageStmt) -> None:
896
+ """Sub objects."""
897
+ self.ds_feature_warn()
898
+
899
+ # NOTE: Incomplete for Jac Purple and Red
900
+ def exit_await_stmt(self, node: ast.AwaitStmt) -> None:
901
+ """Sub objects.
902
+
903
+ target: ExprType,
904
+ """
905
+ self.ds_feature_warn()
906
+
907
+ def exit_assignment(self, node: ast.Assignment) -> None:
908
+ """Sub objects.
909
+
910
+ is_static: bool,
911
+ target: AtomType,
912
+ value: ExprType,
913
+ """
914
+ if node.is_static:
915
+ self.warning("Static variable semantics is not supported in bootstrap Jac")
916
+ self.emit(node, f"{node.target.meta['py_code']} = {node.value.meta['py_code']}")
917
+
918
+ # NOTE: Incomplete for Jac Purple and Red
919
+ def exit_binary_expr(self, node: ast.BinaryExpr) -> None:
920
+ """Sub objects.
921
+
922
+ left: ExprType,
923
+ right: ExprType,
924
+ op: Token | DisconnectOp | ConnectOp,
925
+ """
926
+ if type(node.op) in [ast.DisconnectOp, ast.ConnectOp]:
927
+ self.ds_feature_warn()
928
+ if type(node.op) == ast.Token:
929
+ if node.op.value in [
930
+ *["+", "-", "*", "/", "%", "**"],
931
+ *["+=", "-=", "*=", "/=", "%=", "**="],
932
+ *[">>", "<<", ">>=", "<<="],
933
+ *["//=", "&=", "|=", "^=", "~="],
934
+ *["//", "&", "|", "^"],
935
+ *[">", "<", ">=", "<=", "==", "!=", ":="],
936
+ *["and", "or", "in", "not in", "is", "is not"],
937
+ ]:
938
+ self.emit(
939
+ node,
940
+ f"{node.left.meta['py_code']} {node.op.value} {node.right.meta['py_code']}",
941
+ )
942
+ elif (
943
+ node.op.name in [Tok.PIPE_FWD, Tok.KW_SPAWN, Tok.A_PIPE_FWD]
944
+ and type(node.left) == ast.TupleVal
945
+ ):
946
+ params = node.left.meta["py_code"]
947
+ params = params.replace(",)", ")") if params[-2:] == ",)" else params
948
+ self.emit(node, f"{node.right.meta['py_code']}{params}")
949
+ elif (
950
+ node.op.name in [Tok.PIPE_BKWD, Tok.A_PIPE_BKWD]
951
+ and type(node.right) == ast.TupleVal
952
+ ):
953
+ params = node.right.meta["py_code"]
954
+ params = params.replace(",)", ")") if params[-2:] == ",)" else params
955
+ self.emit(node, f"{node.left.meta['py_code']}{params}")
956
+ elif node.op.name == Tok.PIPE_FWD and type(node.right) == ast.TupleVal:
957
+ self.ds_feature_warn()
958
+ elif node.op.name == Tok.PIPE_FWD:
959
+ self.emit(
960
+ node, f"{node.right.meta['py_code']}({node.left.meta['py_code']}"
961
+ )
962
+ paren_count = (
963
+ node.meta["pipe_chain_count"]
964
+ if "pipe_chain_count" in node.meta
965
+ else 1
966
+ )
967
+ if (
968
+ type(node.parent) == ast.BinaryExpr
969
+ and type(node.parent.op) == ast.Token
970
+ and node.parent.op.name == Tok.PIPE_FWD
971
+ ):
972
+ node.parent.meta["pipe_chain_count"] = paren_count + 1
973
+ else:
974
+ self.emit(node, ")" * paren_count)
975
+
976
+ elif node.op.name in [Tok.KW_SPAWN, Tok.A_PIPE_FWD]:
977
+ self.emit(
978
+ node, f"{node.right.meta['py_code']}({node.left.meta['py_code']}"
979
+ )
980
+ paren_count = (
981
+ node.meta["a_pipe_chain_count"]
982
+ if "a_pipe_chain_count" in node.meta
983
+ else 1
984
+ )
985
+ if (
986
+ type(node.parent) == ast.BinaryExpr
987
+ and type(node.parent.op) == ast.Token
988
+ and node.parent.op.name
989
+ in [
990
+ Tok.KW_SPAWN,
991
+ Tok.A_PIPE_FWD,
992
+ ]
993
+ ):
994
+ node.parent.meta["a_pipe_chain_count"] = paren_count + 1
995
+ else:
996
+ self.emit(node, ")" * paren_count)
997
+
998
+ elif node.op.name in [Tok.PIPE_BKWD, Tok.A_PIPE_BKWD]:
999
+ self.emit(
1000
+ node, f"{node.left.meta['py_code']}({node.right.meta['py_code']})"
1001
+ )
1002
+ elif node.op.name == Tok.ELVIS_OP:
1003
+ self.emit(
1004
+ node,
1005
+ f"{Con.JAC_TMP} "
1006
+ f"if ({Con.JAC_TMP} := ({node.left.meta['py_code']})) is not None "
1007
+ f"else {node.right.meta['py_code']}",
1008
+ )
1009
+ else:
1010
+ self.error(
1011
+ f"Binary operator {node.op.value} not supported in bootstrap Jac"
1012
+ )
1013
+
1014
+ def exit_if_else_expr(self, node: ast.IfElseExpr) -> None:
1015
+ """Sub objects.
1016
+
1017
+ condition: BinaryExpr | IfElseExpr,
1018
+ value: ExprType,
1019
+ else_value: ExprType,
1020
+ """
1021
+ self.emit(
1022
+ node,
1023
+ f"{node.value.meta['py_code']} if {node.condition.meta['py_code']} "
1024
+ f"else {node.else_value.meta['py_code']}",
1025
+ )
1026
+
1027
+ def exit_unary_expr(self, node: ast.UnaryExpr) -> None:
1028
+ """Sub objects.
1029
+
1030
+ operand: ExprType,
1031
+ op: Token,
1032
+ """
1033
+ if node.op.value in ["-", "~", "+"]:
1034
+ self.emit(node, f"{node.op.value}{node.operand.meta['py_code']}")
1035
+ elif node.op.value == "(": # (expression) reuses unary expr
1036
+ self.emit(node, f"({node.operand.meta['py_code']})")
1037
+ elif node.op.value == "not":
1038
+ self.emit(node, f"not {node.operand.meta['py_code']}")
1039
+ elif node.op.name in [Tok.PIPE_FWD, Tok.KW_SPAWN, Tok.A_PIPE_FWD]:
1040
+ self.emit(node, f"{node.operand.meta['py_code']}()")
1041
+ else:
1042
+ self.error(f"Unary operator {node.op.value} not supported in bootstrap Jac")
1043
+
1044
+ def exit_unpack_expr(self, node: ast.UnpackExpr) -> None:
1045
+ """Sub objects.
1046
+
1047
+ target: ExprType,
1048
+ is_dict: bool,
1049
+ """
1050
+ if node.is_dict:
1051
+ self.emit(node, f"**{node.target.meta['py_code']}")
1052
+ else:
1053
+ self.emit(node, f"*{node.target.meta['py_code']}")
1054
+
1055
+ def exit_multi_string(self, node: ast.MultiString) -> None:
1056
+ """Sub objects.
1057
+
1058
+ strings: list[Token],
1059
+ """
1060
+ for string in node.strings:
1061
+ self.emit(node, string.meta["py_code"])
1062
+
1063
+ def exit_list_val(self, node: ast.ListVal) -> None:
1064
+ """Sub objects.
1065
+
1066
+ values: list[ExprType],
1067
+ """
1068
+ self.emit(
1069
+ node, f"[{', '.join([value.meta['py_code'] for value in node.values])}]"
1070
+ )
1071
+
1072
+ def exit_set_val(self, node: ast.ListVal) -> None:
1073
+ """Sub objects.
1074
+
1075
+ values: list[ExprType],
1076
+ """
1077
+ self.emit(
1078
+ node, f"{{{', '.join([value.meta['py_code'] for value in node.values])}}}"
1079
+ )
1080
+
1081
+ def exit_tuple_val(self, node: ast.TupleVal) -> None:
1082
+ """Sub objects.
1083
+
1084
+ first_expr: Optional["ExprType"],
1085
+ exprs: Optional[ExprList],
1086
+ assigns: Optional[AssignmentList],
1087
+ """
1088
+ self.emit(node, "(")
1089
+ if node.first_expr:
1090
+ self.emit(node, f"{node.first_expr.meta['py_code']}")
1091
+ if not node.exprs and not node.assigns:
1092
+ self.emit(node, ",)")
1093
+ if node.exprs:
1094
+ self.emit(node, f", {node.exprs.meta['py_code']}")
1095
+
1096
+ if node.assigns:
1097
+ if node.first_expr:
1098
+ self.emit(node, f", {node.assigns.meta['py_code']}")
1099
+ else:
1100
+ self.emit(node, f"{node.assigns.meta['py_code']}")
1101
+ self.emit(node, ")")
1102
+
1103
+ def exit_expr_list(self, node: ast.ExprList) -> None:
1104
+ """Sub objects.
1105
+
1106
+ values: list[ExprType],
1107
+ """
1108
+ self.emit(
1109
+ node, f"{', '.join([value.meta['py_code'] for value in node.values])}"
1110
+ )
1111
+
1112
+ def exit_dict_val(self, node: ast.DictVal) -> None:
1113
+ """Sub objects.
1114
+
1115
+ kv_pairs: list["KVPair"],
1116
+ """
1117
+ self.emit(
1118
+ node,
1119
+ f"{{{', '.join([kv_pair.meta['py_code'] for kv_pair in node.kv_pairs])}}}",
1120
+ )
1121
+
1122
+ def exit_inner_compr(self, node: ast.InnerCompr) -> None:
1123
+ """Sub objects.
1124
+
1125
+ out_expr: "ExprType",
1126
+ name: Name,
1127
+ collection: "ExprType",
1128
+ conditional: Optional["ExprType"],
1129
+ is_list: bool,
1130
+ is_gen: bool,
1131
+ is_set: bool,
1132
+ """
1133
+ partial = (
1134
+ f"{node.out_expr.meta['py_code']} for {node.name.value} "
1135
+ f"in {node.collection.meta['py_code']}"
1136
+ )
1137
+ if node.conditional:
1138
+ partial += f" if {node.conditional.meta['py_code']}"
1139
+ if node.is_list:
1140
+ self.emit(node, f"[{partial}]")
1141
+ elif node.is_set:
1142
+ self.emit(node, f"{{{partial}}}")
1143
+ elif node.is_gen:
1144
+ self.emit(node, f"({partial})")
1145
+
1146
+ def exit_dict_compr(self, node: ast.DictCompr) -> None:
1147
+ """Sub objects.
1148
+
1149
+ outk_expr: "ExprType",
1150
+ outv_expr: "ExprType",
1151
+ k_name: Token,
1152
+ v_name: Optional[Token],
1153
+ collection: "ExprType",
1154
+ conditional: Optional["ExprType"],
1155
+ """
1156
+ partial = (
1157
+ f"{node.outk_expr.meta['py_code']}: {node.outv_expr.meta['py_code']} for "
1158
+ f"{node.k_name.value}"
1159
+ )
1160
+ if node.v_name:
1161
+ partial += f", {node.v_name.value}"
1162
+ partial += f" in {node.collection.meta['py_code']}"
1163
+ if node.conditional:
1164
+ partial += f" if {node.conditional.meta['py_code']}"
1165
+ self.emit(node, f"{{{partial}}}")
1166
+
1167
+ def exit_k_v_pair(self, node: ast.KVPair) -> None:
1168
+ """Sub objects.
1169
+
1170
+ key: ExprType,
1171
+ value: ExprType,
1172
+ """
1173
+ self.emit(node, f"{node.key.meta['py_code']}: {node.value.meta['py_code']}")
1174
+
1175
+ def exit_atom_trailer(self, node: ast.AtomTrailer) -> None:
1176
+ """Sub objects.
1177
+
1178
+ target: AtomType,
1179
+ right: IndexSlice | ArchRefType | Token,
1180
+ null_ok: bool,
1181
+ """
1182
+ if node.null_ok:
1183
+ if type(node.right) == ast.IndexSlice:
1184
+ self.emit(
1185
+ node,
1186
+ f"({node.target.meta['py_code']}{node.right.meta['py_code']} "
1187
+ f"if {node.target.meta['py_code']} is not None else None)",
1188
+ )
1189
+ else:
1190
+ self.emit(
1191
+ node,
1192
+ f"({node.target.meta['py_code']}.{node.right.meta['py_code']} "
1193
+ f"if {node.target.meta['py_code']} is not None else None)",
1194
+ )
1195
+ else:
1196
+ if type(node.right) == ast.IndexSlice:
1197
+ self.emit(
1198
+ node,
1199
+ f"{node.target.meta['py_code']}{node.right.meta['py_code']}",
1200
+ )
1201
+ else:
1202
+ self.emit(
1203
+ node,
1204
+ f"{node.target.meta['py_code']}.{node.right.meta['py_code']}",
1205
+ )
1206
+
1207
+ # NOTE: Incomplete for Jac Purple and Red
1208
+ def exit_func_call(self, node: ast.FuncCall) -> None:
1209
+ """Sub objects.
1210
+
1211
+ target: AtomType,
1212
+ params: Optional[ParamList],
1213
+ """
1214
+ if node.params:
1215
+ self.emit(
1216
+ node,
1217
+ f"{node.target.meta['py_code']}({node.params.meta['py_code']})",
1218
+ )
1219
+ else:
1220
+ self.emit(node, f"{node.target.meta['py_code']}()")
1221
+
1222
+ def exit_param_list(self, node: ast.ParamList) -> None:
1223
+ """Sub objects.
1224
+
1225
+ p_args: Optional[ExprList],
1226
+ p_kwargs: Optional[AssignmentList],
1227
+ """
1228
+ if node.p_args and node.p_kwargs:
1229
+ self.emit(
1230
+ node,
1231
+ f"{node.p_args.meta['py_code']}, {node.p_kwargs.meta['py_code']}",
1232
+ )
1233
+ elif node.p_args:
1234
+ self.emit(node, f"{node.p_args.meta['py_code']}")
1235
+ elif node.p_kwargs:
1236
+ self.emit(node, f"{node.p_kwargs.meta['py_code']}")
1237
+
1238
+ def exit_assignment_list(self, node: ast.AssignmentList) -> None:
1239
+ """Sub objects.
1240
+
1241
+ values: list[Assignment],
1242
+ """
1243
+ self.emit(
1244
+ node, f"{', '.join([value.meta['py_code'] for value in node.values])}"
1245
+ )
1246
+
1247
+ def exit_index_slice(self, node: ast.IndexSlice) -> None:
1248
+ """Sub objects.
1249
+
1250
+ start: ExprType,
1251
+ stop: Optional[ExprType],
1252
+ """
1253
+ if node.is_range:
1254
+ self.emit(
1255
+ node,
1256
+ f"[{node.start.meta['py_code'] if node.start else ''}:"
1257
+ f"{node.stop.meta['py_code'] if node.stop else ''}]",
1258
+ )
1259
+ elif node.start:
1260
+ self.emit(node, f"[{node.start.meta['py_code']}]")
1261
+ else:
1262
+ self.ice("Something went horribly wrong.")
1263
+
1264
+ def exit_special_var_ref(self, node: ast.SpecialVarRef) -> None:
1265
+ """Sub objects.
1266
+
1267
+ var: Token,
1268
+ """
1269
+ if node.var.name == Tok.SELF_OP:
1270
+ self.emit(node, "self")
1271
+ elif node.var.name == Tok.SUPER_OP:
1272
+ self.emit(node, "super()")
1273
+ elif node.var.name == Tok.ROOT_OP:
1274
+ self.emit(node, Con.ROOT)
1275
+ elif node.var.name == Tok.HERE_OP:
1276
+ self.emit(node, Con.HERE)
1277
+ else:
1278
+ self.ice("Special variable not handled.")
1279
+
1280
+ # NOTE: Incomplete for Jac Purple and Red
1281
+ def exit_arch_ref(self, node: ast.ArchRef) -> None:
1282
+ """Sub objects.
1283
+
1284
+ name: Name,
1285
+ arch: Token,
1286
+ """
1287
+ self.emit(node, f"{node.name.value}")
1288
+
1289
+ # NOTE: Incomplete for Jac Purple and Red
1290
+ def exit_edge_op_ref(self, node: ast.EdgeOpRef) -> None:
1291
+ """Sub objects.
1292
+
1293
+ filter_cond: Optional[ExprType],
1294
+ edge_dir: EdgeDir,
1295
+ """
1296
+ self.ds_feature_warn()
1297
+
1298
+ # NOTE: Incomplete for Jac Purple and Red
1299
+ def exit_disconnect_op(self, node: ast.DisconnectOp) -> None:
1300
+ """Sub objects.
1301
+
1302
+ filter_cond: Optional[ExprType],
1303
+ edge_dir: EdgeDir,
1304
+ """
1305
+ self.ds_feature_warn()
1306
+
1307
+ # NOTE: Incomplete for Jac Purple and Red
1308
+ def exit_connect_op(self, node: ast.ConnectOp) -> None:
1309
+ """Sub objects.
1310
+
1311
+ spawn: Optional[ExprType],
1312
+ edge_dir: EdgeDir,
1313
+ """
1314
+ self.ds_feature_warn()
1315
+
1316
+ # NOTE: Incomplete for Jac Purple and Red
1317
+ def exit_filter_compr(self, node: ast.FilterCompr) -> None:
1318
+ """Sub objects.
1319
+
1320
+ compares: list[BinaryExpr],
1321
+ """
1322
+ self.ds_feature_warn()
1323
+
1324
+ def exit_f_string(self, node: ast.FString) -> None:
1325
+ """Sub objects.
1326
+
1327
+ parts: list["Token | ExprType"],
1328
+ """
1329
+ self.emit(node, 'f"')
1330
+ for part in node.parts:
1331
+ if type(part) == ast.Token and part.name == "PIECE":
1332
+ self.emit(node, f"{part.meta['py_code']}")
1333
+ else:
1334
+ self.emit(node, "{" + part.meta["py_code"] + "}")
1335
+ self.emit(node, '"')