lispython 0.3.2__tar.gz → 0.3.3__tar.gz
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.
- {lispython-0.3.2 → lispython-0.3.3}/PKG-INFO +1 -1
- {lispython-0.3.2 → lispython-0.3.3}/docs/syntax/expressions.md +3 -3
- lispython-0.3.3/docs/version_macro.py +11 -0
- {lispython-0.3.2 → lispython-0.3.3}/pyproject.toml +1 -1
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/compiler/expr.py +1 -1
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/compiler/stmt.py +511 -511
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/tools.lpy +8 -6
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_meta_functions.py +2 -2
- {lispython-0.3.2 → lispython-0.3.3}/uv.lock +1 -1
- lispython-0.3.2/docs/version_macro.py +0 -10
- {lispython-0.3.2 → lispython-0.3.3}/.claude/settings.local.json +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/.gitignore +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/.pre-commit-config.yaml +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/LICENSE.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/README.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/index.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/macros.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/syntax/overview.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/syntax/statements.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/usage/cli.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/usage/getting-started.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/docs/why-lispy.md +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/mkdocs.yml +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/__init__.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/compiler/__init__.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/compiler/literal.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/compiler/utils.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/importer.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/macro.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/meta_functions.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/nodes.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/parser.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core/utils.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/core_meta_functions.lpy +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/macros/__init__.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/macros/init.lpy +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/src/lispy/macros/sugar.lpy +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/__init__.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_expr.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_include_meta.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_literal.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_parser.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/test_stmt.py +0 -0
- {lispython-0.3.2 → lispython-0.3.3}/tests/utils.py +0 -0
|
@@ -250,13 +250,13 @@ obj[start:stop:step]
|
|
|
250
250
|
### Slice with Emptiness
|
|
251
251
|
LisPy version
|
|
252
252
|
```python
|
|
253
|
-
(sub obj [:
|
|
254
|
-
(sub obj [: _
|
|
253
|
+
(sub obj [: stop])
|
|
254
|
+
(sub obj [: start _])
|
|
255
255
|
(sub obj [: start _ step])
|
|
256
256
|
```
|
|
257
257
|
Python version
|
|
258
258
|
```python
|
|
259
|
-
obj[start:]
|
|
260
259
|
obj[:stop]
|
|
260
|
+
obj[start:]
|
|
261
261
|
obj[start::step]
|
|
262
262
|
```
|
|
@@ -359,7 +359,7 @@ def paren_compiler(sexp, ctx):
|
|
|
359
359
|
|
|
360
360
|
def slice_compile(sexp):
|
|
361
361
|
[_, *args] = sexp.list
|
|
362
|
-
assert
|
|
362
|
+
assert 1 <= len(args) <= 3
|
|
363
363
|
[lower, upper, step] = args if len(args) == 3 else args + ["_"] if len(args) == 2 else ["_"] + args + ["_"]
|
|
364
364
|
args_dict = {}
|
|
365
365
|
if lower != "None" and lower != "_":
|
|
@@ -1,511 +1,511 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
from collections import deque
|
|
3
|
-
from functools import reduce
|
|
4
|
-
|
|
5
|
-
from lispy.core.compiler.expr import def_args_parse, expr_compile
|
|
6
|
-
from lispy.core.compiler.utils import *
|
|
7
|
-
from lispy.core.utils import *
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def expr_wrapper(sexp):
|
|
11
|
-
return ast.Expr(value=expr_compile(sexp), **sexp.position_info)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def do_p(sexp):
|
|
15
|
-
return str(sexp.op) == "do"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def do_compile(sexp):
|
|
19
|
-
[op, *sexps] = sexp.list
|
|
20
|
-
return stmt_list_compile(sexps)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def assign_p(sexp):
|
|
24
|
-
return str(sexp.op) == "="
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def assign_compile(sexp):
|
|
28
|
-
body = sexp.operands
|
|
29
|
-
if isinstance(body[1], Annotation):
|
|
30
|
-
[target, annotation, *value] = body
|
|
31
|
-
value_dict = {"value": expr_compile(value[0])} if value else {}
|
|
32
|
-
return ast.AnnAssign(
|
|
33
|
-
target=expr_compile(target, ctx=ast.Store),
|
|
34
|
-
annotation=expr_compile(annotation),
|
|
35
|
-
simple=isinstance(target, Symbol) and (not "." in str(target)),
|
|
36
|
-
**value_dict,
|
|
37
|
-
**sexp.position_info
|
|
38
|
-
)
|
|
39
|
-
else:
|
|
40
|
-
[*targets, value] = body
|
|
41
|
-
return ast.Assign(
|
|
42
|
-
targets=list(map(lambda x: expr_compile(x, ctx=ast.Store), targets)),
|
|
43
|
-
value=expr_compile(value),
|
|
44
|
-
**sexp.position_info
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def augassign_p(sexp):
|
|
49
|
-
return str(sexp.op) in augassignop_dict
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def augassign_compile(sexp):
|
|
53
|
-
[op, target, *args] = sexp.list
|
|
54
|
-
op = augassignop_dict[str(op)]
|
|
55
|
-
value = reduce(
|
|
56
|
-
lambda x, y: ast.BinOp(x, op(), y, **sexp.position_info),
|
|
57
|
-
map(expr_compile, args),
|
|
58
|
-
)
|
|
59
|
-
return ast.AugAssign(
|
|
60
|
-
target=expr_compile(target, ast.Store),
|
|
61
|
-
op=op(),
|
|
62
|
-
value=value,
|
|
63
|
-
**sexp.position_info
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def del_compile(sexp):
|
|
68
|
-
[op, *args] = sexp.list
|
|
69
|
-
return ast.Delete(
|
|
70
|
-
targets=list(map(lambda x: expr_compile(x, ast.Del), args)),
|
|
71
|
-
**sexp.position_info
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def parse_names(names):
|
|
76
|
-
rst = []
|
|
77
|
-
q = deque([names] if names == "*" else names)
|
|
78
|
-
while q:
|
|
79
|
-
n = q.popleft()
|
|
80
|
-
if n == "as":
|
|
81
|
-
rst[-1].asname = str(q.popleft()).replace("-", "_")
|
|
82
|
-
else:
|
|
83
|
-
rst.append(ast.alias(name=n.name, **n.position_info))
|
|
84
|
-
return rst
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def import_compile(sexp):
|
|
88
|
-
[_, *names] = sexp.list
|
|
89
|
-
return ast.Import(names=parse_names(names), **sexp.position_info)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def importfrom_compile(sexp):
|
|
93
|
-
[_, *args] = sexp.list
|
|
94
|
-
modules = args[::2]
|
|
95
|
-
namess = args[1::2]
|
|
96
|
-
|
|
97
|
-
def helper(module):
|
|
98
|
-
i = 0
|
|
99
|
-
x = module.name
|
|
100
|
-
while x[i] == ".":
|
|
101
|
-
i += 1
|
|
102
|
-
return [x[i:], i, module.position_info]
|
|
103
|
-
|
|
104
|
-
module_level = map(helper, modules)
|
|
105
|
-
return [
|
|
106
|
-
ast.ImportFrom(
|
|
107
|
-
module=module,
|
|
108
|
-
names=parse_names(names),
|
|
109
|
-
level=level,
|
|
110
|
-
**merge_position_infos(module_pos_info, names.position_info)
|
|
111
|
-
)
|
|
112
|
-
for [[module, level, module_pos_info], names] in zip(module_level, namess)
|
|
113
|
-
]
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def if_p(sexp):
|
|
117
|
-
return str(sexp.op) == "if"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def if_stmt_compile(sexp):
|
|
121
|
-
[_, test, then, *orelse] = sexp.list
|
|
122
|
-
return ast.If(
|
|
123
|
-
test=expr_compile(test),
|
|
124
|
-
body=stmt_list_compile([then]),
|
|
125
|
-
orelse=stmt_list_compile([*orelse]),
|
|
126
|
-
**sexp.position_info
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def while_p(sexp):
|
|
131
|
-
return str(sexp.op) == "while"
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def while_compile(sexp):
|
|
135
|
-
[_, test, *body] = sexp.list
|
|
136
|
-
lastx = body[-1]
|
|
137
|
-
[then, orelse] = (
|
|
138
|
-
[body[:-1], lastx.operands]
|
|
139
|
-
if isinstance(lastx, Paren) and lastx.op == "else"
|
|
140
|
-
else [body, []]
|
|
141
|
-
)
|
|
142
|
-
return ast.While(
|
|
143
|
-
test=expr_compile(test),
|
|
144
|
-
body=stmt_list_compile(then),
|
|
145
|
-
orelse=stmt_list_compile(orelse),
|
|
146
|
-
**sexp.position_info
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def for_p(sexp):
|
|
151
|
-
return str(sexp.op) == "for"
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
def for_compile(sexp, async_p=False):
|
|
155
|
-
body = deque(sexp.operands)
|
|
156
|
-
target = body.popleft()
|
|
157
|
-
if body[0] == "in":
|
|
158
|
-
body.popleft()
|
|
159
|
-
iterable = body.popleft()
|
|
160
|
-
lastx = body[-1]
|
|
161
|
-
[then, orelse] = (
|
|
162
|
-
[list(body)[:-1], lastx.operands]
|
|
163
|
-
if isinstance(lastx, Paren) and lastx.op == "else"
|
|
164
|
-
else [body, []]
|
|
165
|
-
)
|
|
166
|
-
return (ast.AsyncFor if async_p else ast.For)(
|
|
167
|
-
target=expr_compile(target, ast.Store),
|
|
168
|
-
iter=expr_compile(iterable),
|
|
169
|
-
body=stmt_list_compile(then),
|
|
170
|
-
orelse=stmt_list_compile(orelse),
|
|
171
|
-
**sexp.position_info
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
def deco_p(sexp):
|
|
176
|
-
return str(sexp.op) == "deco"
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
def raise_compile(sexp):
|
|
180
|
-
body = sexp.operands
|
|
181
|
-
assert len(body) == 1 or (len(body) == 3 and body[1] == "from")
|
|
182
|
-
kwargs = {"exc": expr_compile(body[0])}
|
|
183
|
-
if len(body) > 1:
|
|
184
|
-
kwargs["cause"] = expr_compile(body[-1])
|
|
185
|
-
return ast.Raise(**kwargs, **sexp.position_info)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def assert_compile(sexp):
|
|
189
|
-
kwargs = {"test": expr_compile(sexp[1])}
|
|
190
|
-
if len(sexp) > 2:
|
|
191
|
-
kwargs["msg"] = expr_compile(sexp[2])
|
|
192
|
-
return ast.Assert(**kwargs, **sexp.position_info)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def parse_exception_bracket(bracket):
|
|
196
|
-
lst = bracket.list
|
|
197
|
-
name = (
|
|
198
|
-
str([lst.pop(), lst.pop()][0]).replace("-", "_")
|
|
199
|
-
if len(lst) > 2 and lst[-2] == "as"
|
|
200
|
-
else None
|
|
201
|
-
)
|
|
202
|
-
type = (
|
|
203
|
-
ast.Tuple(
|
|
204
|
-
elts=list(map(expr_compile, lst)), ctx=ast.Load(), **bracket.position_info
|
|
205
|
-
)
|
|
206
|
-
if len(lst) > 1
|
|
207
|
-
else expr_compile(lst[0])
|
|
208
|
-
)
|
|
209
|
-
return [type, name]
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def parse_except(handler):
|
|
213
|
-
body = handler.operands
|
|
214
|
-
if isinstance(body[0], Bracket):
|
|
215
|
-
body = deque(handler.operands)
|
|
216
|
-
[type, name] = parse_exception_bracket(body.popleft())
|
|
217
|
-
else:
|
|
218
|
-
[type, name] = [None, None]
|
|
219
|
-
kwargs = {"body": stmt_list_compile(body)}
|
|
220
|
-
if type:
|
|
221
|
-
kwargs["type"] = type
|
|
222
|
-
if name:
|
|
223
|
-
kwargs["name"] = name
|
|
224
|
-
return ast.ExceptHandler(**kwargs, **handler.position_info)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def try_compile(sexp):
|
|
228
|
-
body = sexp.operands
|
|
229
|
-
# finally
|
|
230
|
-
finalbody = (
|
|
231
|
-
body.pop().operands
|
|
232
|
-
if isinstance(body[-1], Paren) and body[-1].op == "finally"
|
|
233
|
-
else []
|
|
234
|
-
)
|
|
235
|
-
# else
|
|
236
|
-
orelse = (
|
|
237
|
-
body.pop().operands
|
|
238
|
-
if isinstance(body[-1], Paren) and body[-1].op == "else"
|
|
239
|
-
else []
|
|
240
|
-
)
|
|
241
|
-
# excepts
|
|
242
|
-
handlers = deque()
|
|
243
|
-
while isinstance(body[-1], Paren) and body[-1].op == "except":
|
|
244
|
-
handlers.appendleft(body.pop())
|
|
245
|
-
handlers = list(map(parse_except, handlers))
|
|
246
|
-
# except*s
|
|
247
|
-
starhandlers = deque()
|
|
248
|
-
while isinstance(body[-1], Paren) and body[-1].op == "except*":
|
|
249
|
-
starhandlers.appendleft(body.pop())
|
|
250
|
-
starhandlers = list(map(parse_except, starhandlers))
|
|
251
|
-
assert not starhandlers or not handlers
|
|
252
|
-
return (ast.Try if not starhandlers else ast.TryStar)(
|
|
253
|
-
body=stmt_list_compile(body),
|
|
254
|
-
handlers=handlers or starhandlers,
|
|
255
|
-
orelse=stmt_list_compile(orelse),
|
|
256
|
-
finalbody=stmt_list_compile(finalbody),
|
|
257
|
-
**sexp.position_info
|
|
258
|
-
)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
def with_items_parse(sexp):
|
|
262
|
-
rst = []
|
|
263
|
-
q = deque(sexp.list)
|
|
264
|
-
while q:
|
|
265
|
-
elt = q.popleft()
|
|
266
|
-
if str(elt) == "as":
|
|
267
|
-
rst[-1].optional_vars = expr_compile(q.popleft(), ctx=ast.Store)
|
|
268
|
-
else:
|
|
269
|
-
rst.append(ast.withitem(context_expr=expr_compile(elt)))
|
|
270
|
-
return rst
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
def with_compile(sexp, async_p=False):
|
|
274
|
-
[bracket_sexp, *body] = sexp.operands
|
|
275
|
-
items = with_items_parse(bracket_sexp)
|
|
276
|
-
return (ast.AsyncWith if async_p else ast.With)(
|
|
277
|
-
items=items, body=stmt_list_compile(body), **sexp.position_info
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def match_mapping_parse(lst):
|
|
282
|
-
keys = lst[::2]
|
|
283
|
-
patterns = lst[1::2]
|
|
284
|
-
rst = {}
|
|
285
|
-
if isinstance(keys[-1], DoubleStarred):
|
|
286
|
-
rst["rest"] = keys.pop().value.name
|
|
287
|
-
rst["keys"] = list(map(expr_compile, keys))
|
|
288
|
-
rst["patterns"] = list(map(pattern_parse, patterns))
|
|
289
|
-
return rst
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
def match_class_parse(lst):
|
|
293
|
-
q = deque(lst)
|
|
294
|
-
patterns = []
|
|
295
|
-
kwd_attrs = []
|
|
296
|
-
kwd_patterns = []
|
|
297
|
-
while q:
|
|
298
|
-
arg = q.popleft()
|
|
299
|
-
if isinstance(arg, Keyword):
|
|
300
|
-
kwd_attrs.append(arg.value.name)
|
|
301
|
-
kwd_patterns.append(pattern_parse(q.popleft()))
|
|
302
|
-
else:
|
|
303
|
-
patterns.append(pattern_parse(arg))
|
|
304
|
-
return {"patterns": patterns, "kwd_attrs": kwd_attrs, "kwd_patterns": kwd_patterns}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def pattern_parse(sexp):
|
|
308
|
-
return (
|
|
309
|
-
ast.MatchAs(**sexp.position_info)
|
|
310
|
-
if str(sexp) == "_"
|
|
311
|
-
else ast.MatchAs(name=sexp.name, **sexp.position_info)
|
|
312
|
-
if isinstance(sexp, Symbol)
|
|
313
|
-
else ast.MatchSingleton(value=eval(str(sexp)), **sexp.position_info)
|
|
314
|
-
if str(sexp) in ["True", "False", "None"]
|
|
315
|
-
else ast.MatchStar(
|
|
316
|
-
**{} if str(sexp.value) == "_" else {"name": sexp.value.name},
|
|
317
|
-
**sexp.position_info
|
|
318
|
-
)
|
|
319
|
-
if isinstance(sexp, Starred)
|
|
320
|
-
else ast.MatchValue(value=expr_compile(sexp), **sexp.position_info)
|
|
321
|
-
if not isinstance(sexp, Expression)
|
|
322
|
-
else ast.MatchSequence(
|
|
323
|
-
patterns=list(map(pattern_parse, sexp.list)), **sexp.position_info
|
|
324
|
-
)
|
|
325
|
-
if isinstance(sexp, Bracket)
|
|
326
|
-
else ast.MatchMapping(**match_mapping_parse(sexp.list), **sexp.position_info)
|
|
327
|
-
if isinstance(sexp, Brace)
|
|
328
|
-
else ast.MatchOr(
|
|
329
|
-
patterns=list(map(pattern_parse, sexp.operands)), **sexp.position_info
|
|
330
|
-
)
|
|
331
|
-
if sexp.op == "|"
|
|
332
|
-
else ast.MatchClass(
|
|
333
|
-
cls=expr_compile(sexp.op),
|
|
334
|
-
**match_class_parse(sexp.operands),
|
|
335
|
-
**sexp.position_info
|
|
336
|
-
)
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
def case_parse(case):
|
|
341
|
-
[pattern_expr, *body] = case.operands
|
|
342
|
-
pattern = pattern_parse(pattern_expr)
|
|
343
|
-
if body[0] == "as":
|
|
344
|
-
pattern = ast.MatchAs(
|
|
345
|
-
pattern=pattern,
|
|
346
|
-
name=body[1].name.replace("-", "_"),
|
|
347
|
-
**merge_position_infos(pattern_expr.position_info, body[1].position_info)
|
|
348
|
-
)
|
|
349
|
-
body = body[2:]
|
|
350
|
-
if body[0] == "if":
|
|
351
|
-
guard_dict = {"guard": expr_compile(body[1])}
|
|
352
|
-
body = body[2:]
|
|
353
|
-
else:
|
|
354
|
-
guard_dict = {}
|
|
355
|
-
return ast.match_case(pattern=pattern, **guard_dict, body=stmt_list_compile(body))
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
def match_compile(sexp):
|
|
359
|
-
[subject, *cases] = sexp.operands
|
|
360
|
-
cases = list(map(case_parse, cases))
|
|
361
|
-
return ast.Match(subject=expr_compile(subject), cases=cases, **sexp.position_info)
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
def deco_compile(sexp, decorator_list):
|
|
365
|
-
[op, decorator, def_statement] = sexp.list
|
|
366
|
-
new_deco_list = decorator.list if isinstance(decorator, Bracket) else [decorator]
|
|
367
|
-
return stmt_compile(
|
|
368
|
-
def_statement, (decorator_list if decorator_list else []) + new_deco_list
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
def functiondef_p(sexp):
|
|
373
|
-
return str(sexp.op) == "def"
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
def functiondef_compile(sexp, decorator_list, async_p=False):
|
|
377
|
-
[op, fnname, args, *body] = sexp.list
|
|
378
|
-
if body and isinstance(body[0], Annotation):
|
|
379
|
-
[ann, *body] = body
|
|
380
|
-
else:
|
|
381
|
-
ann = None
|
|
382
|
-
return (ast.AsyncFunctionDef if async_p else ast.FunctionDef)(
|
|
383
|
-
name=fnname.name,
|
|
384
|
-
args=def_args_parse(args),
|
|
385
|
-
body=stmt_list_compile(body),
|
|
386
|
-
decorator_list=list(map(expr_compile, decorator_list))
|
|
387
|
-
if decorator_list
|
|
388
|
-
else [],
|
|
389
|
-
returns=expr_compile(ann.value) if ann else None,
|
|
390
|
-
**sexp.position_info
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
def return_p(sexp):
|
|
395
|
-
return str(sexp.op) == "return"
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
def return_compile(sexp):
|
|
399
|
-
[op, value] = sexp.list if len(sexp) > 1 else [None, None]
|
|
400
|
-
return ast.Return(value=expr_compile(value) if value else None, **sexp.position_info)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def global_compile(sexp):
|
|
404
|
-
[_, *args] = sexp.list
|
|
405
|
-
return ast.Global(names=list(map(lambda x: x.name, args)), **sexp.position_info)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
def nonlocal_compile(sexp):
|
|
409
|
-
[_, *args] = sexp.list
|
|
410
|
-
return ast.Nonlocal(names=list(map(lambda x: x.name, args)), **sexp.position_info)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
def classdef_p(sexp):
|
|
414
|
-
return str(sexp.op) == "class"
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
def classdef_args_parse(args):
|
|
418
|
-
q = deque(args)
|
|
419
|
-
bases = []
|
|
420
|
-
keywords = []
|
|
421
|
-
while q:
|
|
422
|
-
arg = q.popleft()
|
|
423
|
-
keywords.append(
|
|
424
|
-
ast.keyword(
|
|
425
|
-
arg=arg.name, value=expr_compile(q.popleft()), **arg.position_info
|
|
426
|
-
)
|
|
427
|
-
) if keyword_arg_p(arg) else bases.append(expr_compile(arg))
|
|
428
|
-
return [bases, keywords]
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
def classdef_compile(sexp, decorator_list):
|
|
432
|
-
[_, clsname, args, *body] = sexp.list
|
|
433
|
-
[bases, keywords] = classdef_args_parse(args)
|
|
434
|
-
return ast.ClassDef(
|
|
435
|
-
name=clsname.name,
|
|
436
|
-
bases=bases,
|
|
437
|
-
keywords=keywords,
|
|
438
|
-
body=stmt_list_compile(body),
|
|
439
|
-
decorator_list=list(map(expr_compile, decorator_list))
|
|
440
|
-
if decorator_list
|
|
441
|
-
else [],
|
|
442
|
-
**sexp.position_info
|
|
443
|
-
)
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
def stmt_compile(sexp, decorator_list=None):
|
|
447
|
-
return (
|
|
448
|
-
expr_wrapper(sexp)
|
|
449
|
-
if not paren_p(sexp)
|
|
450
|
-
else do_compile(sexp)
|
|
451
|
-
if do_p(sexp)
|
|
452
|
-
else assign_compile(sexp)
|
|
453
|
-
if assign_p(sexp)
|
|
454
|
-
else augassign_compile(sexp)
|
|
455
|
-
if augassign_p(sexp)
|
|
456
|
-
else del_compile(sexp)
|
|
457
|
-
if str(sexp.op) == "del"
|
|
458
|
-
else ast.Pass(**sexp.position_info)
|
|
459
|
-
if str(sexp.op) == "pass"
|
|
460
|
-
else import_compile(sexp)
|
|
461
|
-
if str(sexp.op) == "import"
|
|
462
|
-
else importfrom_compile(sexp)
|
|
463
|
-
if str(sexp.op) == "from"
|
|
464
|
-
else if_stmt_compile(sexp)
|
|
465
|
-
if if_p(sexp)
|
|
466
|
-
else while_compile(sexp)
|
|
467
|
-
if while_p(sexp)
|
|
468
|
-
else for_compile(sexp)
|
|
469
|
-
if for_p(sexp)
|
|
470
|
-
else ast.Break(**sexp.position_info)
|
|
471
|
-
if str(sexp.op) == "break"
|
|
472
|
-
else ast.Continue(**sexp.position_info)
|
|
473
|
-
if str(sexp.op) == "continue"
|
|
474
|
-
else raise_compile(sexp)
|
|
475
|
-
if str(sexp.op) == "raise"
|
|
476
|
-
else assert_compile(sexp)
|
|
477
|
-
if str(sexp.op) == "assert"
|
|
478
|
-
else try_compile(sexp)
|
|
479
|
-
if str(sexp.op) == "try"
|
|
480
|
-
else with_compile(sexp)
|
|
481
|
-
if str(sexp.op) == "with"
|
|
482
|
-
else match_compile(sexp)
|
|
483
|
-
if str(sexp.op) == "match"
|
|
484
|
-
else deco_compile(sexp, decorator_list)
|
|
485
|
-
if deco_p(sexp)
|
|
486
|
-
else functiondef_compile(sexp, decorator_list)
|
|
487
|
-
if functiondef_p(sexp)
|
|
488
|
-
else return_compile(sexp)
|
|
489
|
-
if return_p(sexp)
|
|
490
|
-
else global_compile(sexp)
|
|
491
|
-
if str(sexp.op) == "global"
|
|
492
|
-
else nonlocal_compile(sexp)
|
|
493
|
-
if str(sexp.op) == "nonlocal"
|
|
494
|
-
else classdef_compile(sexp, decorator_list)
|
|
495
|
-
if classdef_p(sexp)
|
|
496
|
-
else functiondef_compile(sexp, decorator_list, async_p=True)
|
|
497
|
-
if str(sexp.op) == "async-def"
|
|
498
|
-
else for_compile(sexp, async_p=True)
|
|
499
|
-
if str(sexp.op) == "async-for"
|
|
500
|
-
else with_compile(sexp, async_p=True)
|
|
501
|
-
if str(sexp.op) == "async-with"
|
|
502
|
-
else expr_wrapper(sexp)
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
def stmt_list_compile(sexp_list):
|
|
507
|
-
return reduce(
|
|
508
|
-
lambda x, y: x + (y if isinstance(y, list) else [y]),
|
|
509
|
-
map(stmt_compile, sexp_list),
|
|
510
|
-
[],
|
|
511
|
-
)
|
|
1
|
+
import ast
|
|
2
|
+
from collections import deque
|
|
3
|
+
from functools import reduce
|
|
4
|
+
|
|
5
|
+
from lispy.core.compiler.expr import def_args_parse, expr_compile
|
|
6
|
+
from lispy.core.compiler.utils import *
|
|
7
|
+
from lispy.core.utils import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def expr_wrapper(sexp):
|
|
11
|
+
return ast.Expr(value=expr_compile(sexp), **sexp.position_info)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def do_p(sexp):
|
|
15
|
+
return str(sexp.op) == "do"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def do_compile(sexp):
|
|
19
|
+
[op, *sexps] = sexp.list
|
|
20
|
+
return stmt_list_compile(sexps)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def assign_p(sexp):
|
|
24
|
+
return str(sexp.op) == "="
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def assign_compile(sexp):
|
|
28
|
+
body = sexp.operands
|
|
29
|
+
if isinstance(body[1], Annotation):
|
|
30
|
+
[target, annotation, *value] = body
|
|
31
|
+
value_dict = {"value": expr_compile(value[0])} if value else {}
|
|
32
|
+
return ast.AnnAssign(
|
|
33
|
+
target=expr_compile(target, ctx=ast.Store),
|
|
34
|
+
annotation=expr_compile(annotation),
|
|
35
|
+
simple=isinstance(target, Symbol) and (not "." in str(target)),
|
|
36
|
+
**value_dict,
|
|
37
|
+
**sexp.position_info
|
|
38
|
+
)
|
|
39
|
+
else:
|
|
40
|
+
[*targets, value] = body
|
|
41
|
+
return ast.Assign(
|
|
42
|
+
targets=list(map(lambda x: expr_compile(x, ctx=ast.Store), targets)),
|
|
43
|
+
value=expr_compile(value),
|
|
44
|
+
**sexp.position_info
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def augassign_p(sexp):
|
|
49
|
+
return str(sexp.op) in augassignop_dict
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def augassign_compile(sexp):
|
|
53
|
+
[op, target, *args] = sexp.list
|
|
54
|
+
op = augassignop_dict[str(op)]
|
|
55
|
+
value = reduce(
|
|
56
|
+
lambda x, y: ast.BinOp(x, op(), y, **sexp.position_info),
|
|
57
|
+
map(expr_compile, args),
|
|
58
|
+
)
|
|
59
|
+
return ast.AugAssign(
|
|
60
|
+
target=expr_compile(target, ast.Store),
|
|
61
|
+
op=op(),
|
|
62
|
+
value=value,
|
|
63
|
+
**sexp.position_info
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def del_compile(sexp):
|
|
68
|
+
[op, *args] = sexp.list
|
|
69
|
+
return ast.Delete(
|
|
70
|
+
targets=list(map(lambda x: expr_compile(x, ast.Del), args)),
|
|
71
|
+
**sexp.position_info
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def parse_names(names):
|
|
76
|
+
rst = []
|
|
77
|
+
q = deque([names] if names == "*" else names)
|
|
78
|
+
while q:
|
|
79
|
+
n = q.popleft()
|
|
80
|
+
if n == "as":
|
|
81
|
+
rst[-1].asname = str(q.popleft()).replace("-", "_")
|
|
82
|
+
else:
|
|
83
|
+
rst.append(ast.alias(name=n.name, **n.position_info))
|
|
84
|
+
return rst
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def import_compile(sexp):
|
|
88
|
+
[_, *names] = sexp.list
|
|
89
|
+
return ast.Import(names=parse_names(names), **sexp.position_info)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def importfrom_compile(sexp):
|
|
93
|
+
[_, *args] = sexp.list
|
|
94
|
+
modules = args[::2]
|
|
95
|
+
namess = args[1::2]
|
|
96
|
+
|
|
97
|
+
def helper(module):
|
|
98
|
+
i = 0
|
|
99
|
+
x = module.name
|
|
100
|
+
while x[i] == ".":
|
|
101
|
+
i += 1
|
|
102
|
+
return [x[i:], i, module.position_info]
|
|
103
|
+
|
|
104
|
+
module_level = map(helper, modules)
|
|
105
|
+
return [
|
|
106
|
+
ast.ImportFrom(
|
|
107
|
+
module=module,
|
|
108
|
+
names=parse_names(names),
|
|
109
|
+
level=level,
|
|
110
|
+
**merge_position_infos(module_pos_info, names.position_info)
|
|
111
|
+
)
|
|
112
|
+
for [[module, level, module_pos_info], names] in zip(module_level, namess)
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def if_p(sexp):
|
|
117
|
+
return str(sexp.op) == "if"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def if_stmt_compile(sexp):
|
|
121
|
+
[_, test, then, *orelse] = sexp.list
|
|
122
|
+
return ast.If(
|
|
123
|
+
test=expr_compile(test),
|
|
124
|
+
body=stmt_list_compile([then]),
|
|
125
|
+
orelse=stmt_list_compile([*orelse]),
|
|
126
|
+
**sexp.position_info
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def while_p(sexp):
|
|
131
|
+
return str(sexp.op) == "while"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def while_compile(sexp):
|
|
135
|
+
[_, test, *body] = sexp.list
|
|
136
|
+
lastx = body[-1]
|
|
137
|
+
[then, orelse] = (
|
|
138
|
+
[body[:-1], lastx.operands]
|
|
139
|
+
if isinstance(lastx, Paren) and lastx.op == "else"
|
|
140
|
+
else [body, []]
|
|
141
|
+
)
|
|
142
|
+
return ast.While(
|
|
143
|
+
test=expr_compile(test),
|
|
144
|
+
body=stmt_list_compile(then),
|
|
145
|
+
orelse=stmt_list_compile(orelse),
|
|
146
|
+
**sexp.position_info
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def for_p(sexp):
|
|
151
|
+
return str(sexp.op) == "for"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def for_compile(sexp, async_p=False):
|
|
155
|
+
body = deque(sexp.operands)
|
|
156
|
+
target = body.popleft()
|
|
157
|
+
if body[0] == "in":
|
|
158
|
+
body.popleft()
|
|
159
|
+
iterable = body.popleft()
|
|
160
|
+
lastx = body[-1]
|
|
161
|
+
[then, orelse] = (
|
|
162
|
+
[list(body)[:-1], lastx.operands]
|
|
163
|
+
if isinstance(lastx, Paren) and lastx.op == "else"
|
|
164
|
+
else [body, []]
|
|
165
|
+
)
|
|
166
|
+
return (ast.AsyncFor if async_p else ast.For)(
|
|
167
|
+
target=expr_compile(target, ast.Store),
|
|
168
|
+
iter=expr_compile(iterable),
|
|
169
|
+
body=stmt_list_compile(then),
|
|
170
|
+
orelse=stmt_list_compile(orelse),
|
|
171
|
+
**sexp.position_info
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def deco_p(sexp):
|
|
176
|
+
return str(sexp.op) == "deco"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def raise_compile(sexp):
|
|
180
|
+
body = sexp.operands
|
|
181
|
+
assert len(body) == 1 or (len(body) == 3 and body[1] == "from")
|
|
182
|
+
kwargs = {"exc": expr_compile(body[0])}
|
|
183
|
+
if len(body) > 1:
|
|
184
|
+
kwargs["cause"] = expr_compile(body[-1])
|
|
185
|
+
return ast.Raise(**kwargs, **sexp.position_info)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def assert_compile(sexp):
|
|
189
|
+
kwargs = {"test": expr_compile(sexp[1])}
|
|
190
|
+
if len(sexp) > 2:
|
|
191
|
+
kwargs["msg"] = expr_compile(sexp[2])
|
|
192
|
+
return ast.Assert(**kwargs, **sexp.position_info)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def parse_exception_bracket(bracket):
|
|
196
|
+
lst = bracket.list
|
|
197
|
+
name = (
|
|
198
|
+
str([lst.pop(), lst.pop()][0]).replace("-", "_")
|
|
199
|
+
if len(lst) > 2 and lst[-2] == "as"
|
|
200
|
+
else None
|
|
201
|
+
)
|
|
202
|
+
type = (
|
|
203
|
+
ast.Tuple(
|
|
204
|
+
elts=list(map(expr_compile, lst)), ctx=ast.Load(), **bracket.position_info
|
|
205
|
+
)
|
|
206
|
+
if len(lst) > 1
|
|
207
|
+
else expr_compile(lst[0])
|
|
208
|
+
)
|
|
209
|
+
return [type, name]
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def parse_except(handler):
|
|
213
|
+
body = handler.operands
|
|
214
|
+
if isinstance(body[0], Bracket):
|
|
215
|
+
body = deque(handler.operands)
|
|
216
|
+
[type, name] = parse_exception_bracket(body.popleft())
|
|
217
|
+
else:
|
|
218
|
+
[type, name] = [None, None]
|
|
219
|
+
kwargs = {"body": stmt_list_compile(body)}
|
|
220
|
+
if type:
|
|
221
|
+
kwargs["type"] = type
|
|
222
|
+
if name:
|
|
223
|
+
kwargs["name"] = name
|
|
224
|
+
return ast.ExceptHandler(**kwargs, **handler.position_info)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def try_compile(sexp):
|
|
228
|
+
body = sexp.operands
|
|
229
|
+
# finally
|
|
230
|
+
finalbody = (
|
|
231
|
+
body.pop().operands
|
|
232
|
+
if isinstance(body[-1], Paren) and body[-1].op == "finally"
|
|
233
|
+
else []
|
|
234
|
+
)
|
|
235
|
+
# else
|
|
236
|
+
orelse = (
|
|
237
|
+
body.pop().operands
|
|
238
|
+
if isinstance(body[-1], Paren) and body[-1].op == "else"
|
|
239
|
+
else []
|
|
240
|
+
)
|
|
241
|
+
# excepts
|
|
242
|
+
handlers = deque()
|
|
243
|
+
while isinstance(body[-1], Paren) and body[-1].op == "except":
|
|
244
|
+
handlers.appendleft(body.pop())
|
|
245
|
+
handlers = list(map(parse_except, handlers))
|
|
246
|
+
# except*s
|
|
247
|
+
starhandlers = deque()
|
|
248
|
+
while isinstance(body[-1], Paren) and body[-1].op == "except*":
|
|
249
|
+
starhandlers.appendleft(body.pop())
|
|
250
|
+
starhandlers = list(map(parse_except, starhandlers))
|
|
251
|
+
assert not starhandlers or not handlers
|
|
252
|
+
return (ast.Try if not starhandlers else ast.TryStar)(
|
|
253
|
+
body=stmt_list_compile(body),
|
|
254
|
+
handlers=handlers or starhandlers,
|
|
255
|
+
orelse=stmt_list_compile(orelse),
|
|
256
|
+
finalbody=stmt_list_compile(finalbody),
|
|
257
|
+
**sexp.position_info
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def with_items_parse(sexp):
|
|
262
|
+
rst = []
|
|
263
|
+
q = deque(sexp.list)
|
|
264
|
+
while q:
|
|
265
|
+
elt = q.popleft()
|
|
266
|
+
if str(elt) == "as":
|
|
267
|
+
rst[-1].optional_vars = expr_compile(q.popleft(), ctx=ast.Store)
|
|
268
|
+
else:
|
|
269
|
+
rst.append(ast.withitem(context_expr=expr_compile(elt)))
|
|
270
|
+
return rst
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def with_compile(sexp, async_p=False):
|
|
274
|
+
[bracket_sexp, *body] = sexp.operands
|
|
275
|
+
items = with_items_parse(bracket_sexp)
|
|
276
|
+
return (ast.AsyncWith if async_p else ast.With)(
|
|
277
|
+
items=items, body=stmt_list_compile(body), **sexp.position_info
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def match_mapping_parse(lst):
|
|
282
|
+
keys = lst[::2]
|
|
283
|
+
patterns = lst[1::2]
|
|
284
|
+
rst = {}
|
|
285
|
+
if isinstance(keys[-1], DoubleStarred):
|
|
286
|
+
rst["rest"] = keys.pop().value.name
|
|
287
|
+
rst["keys"] = list(map(expr_compile, keys))
|
|
288
|
+
rst["patterns"] = list(map(pattern_parse, patterns))
|
|
289
|
+
return rst
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def match_class_parse(lst):
|
|
293
|
+
q = deque(lst)
|
|
294
|
+
patterns = []
|
|
295
|
+
kwd_attrs = []
|
|
296
|
+
kwd_patterns = []
|
|
297
|
+
while q:
|
|
298
|
+
arg = q.popleft()
|
|
299
|
+
if isinstance(arg, Keyword):
|
|
300
|
+
kwd_attrs.append(arg.value.name)
|
|
301
|
+
kwd_patterns.append(pattern_parse(q.popleft()))
|
|
302
|
+
else:
|
|
303
|
+
patterns.append(pattern_parse(arg))
|
|
304
|
+
return {"patterns": patterns, "kwd_attrs": kwd_attrs, "kwd_patterns": kwd_patterns}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def pattern_parse(sexp):
|
|
308
|
+
return (
|
|
309
|
+
ast.MatchAs(**sexp.position_info)
|
|
310
|
+
if str(sexp) == "_"
|
|
311
|
+
else ast.MatchAs(name=sexp.name, **sexp.position_info)
|
|
312
|
+
if isinstance(sexp, Symbol)
|
|
313
|
+
else ast.MatchSingleton(value=eval(str(sexp)), **sexp.position_info)
|
|
314
|
+
if str(sexp) in ["True", "False", "None"]
|
|
315
|
+
else ast.MatchStar(
|
|
316
|
+
**{} if str(sexp.value) == "_" else {"name": sexp.value.name},
|
|
317
|
+
**sexp.position_info
|
|
318
|
+
)
|
|
319
|
+
if isinstance(sexp, Starred)
|
|
320
|
+
else ast.MatchValue(value=expr_compile(sexp), **sexp.position_info)
|
|
321
|
+
if not isinstance(sexp, Expression)
|
|
322
|
+
else ast.MatchSequence(
|
|
323
|
+
patterns=list(map(pattern_parse, sexp.list)), **sexp.position_info
|
|
324
|
+
)
|
|
325
|
+
if isinstance(sexp, Bracket)
|
|
326
|
+
else ast.MatchMapping(**match_mapping_parse(sexp.list), **sexp.position_info)
|
|
327
|
+
if isinstance(sexp, Brace)
|
|
328
|
+
else ast.MatchOr(
|
|
329
|
+
patterns=list(map(pattern_parse, sexp.operands)), **sexp.position_info
|
|
330
|
+
)
|
|
331
|
+
if sexp.op == "|"
|
|
332
|
+
else ast.MatchClass(
|
|
333
|
+
cls=expr_compile(sexp.op),
|
|
334
|
+
**match_class_parse(sexp.operands),
|
|
335
|
+
**sexp.position_info
|
|
336
|
+
)
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def case_parse(case):
|
|
341
|
+
[pattern_expr, *body] = case.operands
|
|
342
|
+
pattern = pattern_parse(pattern_expr)
|
|
343
|
+
if body[0] == "as":
|
|
344
|
+
pattern = ast.MatchAs(
|
|
345
|
+
pattern=pattern,
|
|
346
|
+
name=body[1].name.replace("-", "_"),
|
|
347
|
+
**merge_position_infos(pattern_expr.position_info, body[1].position_info)
|
|
348
|
+
)
|
|
349
|
+
body = body[2:]
|
|
350
|
+
if body[0] == "if":
|
|
351
|
+
guard_dict = {"guard": expr_compile(body[1])}
|
|
352
|
+
body = body[2:]
|
|
353
|
+
else:
|
|
354
|
+
guard_dict = {}
|
|
355
|
+
return ast.match_case(pattern=pattern, **guard_dict, body=stmt_list_compile(body))
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def match_compile(sexp):
|
|
359
|
+
[subject, *cases] = sexp.operands
|
|
360
|
+
cases = list(map(case_parse, cases))
|
|
361
|
+
return ast.Match(subject=expr_compile(subject), cases=cases, **sexp.position_info)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def deco_compile(sexp, decorator_list):
|
|
365
|
+
[op, decorator, def_statement] = sexp.list
|
|
366
|
+
new_deco_list = decorator.list if isinstance(decorator, Bracket) else [decorator]
|
|
367
|
+
return stmt_compile(
|
|
368
|
+
def_statement, (decorator_list if decorator_list else []) + new_deco_list
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def functiondef_p(sexp):
|
|
373
|
+
return str(sexp.op) == "def"
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def functiondef_compile(sexp, decorator_list, async_p=False):
|
|
377
|
+
[op, fnname, args, *body] = sexp.list
|
|
378
|
+
if body and isinstance(body[0], Annotation):
|
|
379
|
+
[ann, *body] = body
|
|
380
|
+
else:
|
|
381
|
+
ann = None
|
|
382
|
+
return (ast.AsyncFunctionDef if async_p else ast.FunctionDef)(
|
|
383
|
+
name=fnname.name,
|
|
384
|
+
args=def_args_parse(args),
|
|
385
|
+
body=stmt_list_compile(body) if body else [ast.Pass(**sexp.position_info)],
|
|
386
|
+
decorator_list=list(map(expr_compile, decorator_list))
|
|
387
|
+
if decorator_list
|
|
388
|
+
else [],
|
|
389
|
+
returns=expr_compile(ann.value) if ann else None,
|
|
390
|
+
**sexp.position_info
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def return_p(sexp):
|
|
395
|
+
return str(sexp.op) == "return"
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def return_compile(sexp):
|
|
399
|
+
[op, value] = sexp.list if len(sexp) > 1 else [None, None]
|
|
400
|
+
return ast.Return(value=expr_compile(value) if value else None, **sexp.position_info)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def global_compile(sexp):
|
|
404
|
+
[_, *args] = sexp.list
|
|
405
|
+
return ast.Global(names=list(map(lambda x: x.name, args)), **sexp.position_info)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def nonlocal_compile(sexp):
|
|
409
|
+
[_, *args] = sexp.list
|
|
410
|
+
return ast.Nonlocal(names=list(map(lambda x: x.name, args)), **sexp.position_info)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def classdef_p(sexp):
|
|
414
|
+
return str(sexp.op) == "class"
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def classdef_args_parse(args):
|
|
418
|
+
q = deque(args)
|
|
419
|
+
bases = []
|
|
420
|
+
keywords = []
|
|
421
|
+
while q:
|
|
422
|
+
arg = q.popleft()
|
|
423
|
+
keywords.append(
|
|
424
|
+
ast.keyword(
|
|
425
|
+
arg=arg.name, value=expr_compile(q.popleft()), **arg.position_info
|
|
426
|
+
)
|
|
427
|
+
) if keyword_arg_p(arg) else bases.append(expr_compile(arg))
|
|
428
|
+
return [bases, keywords]
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
def classdef_compile(sexp, decorator_list):
|
|
432
|
+
[_, clsname, args, *body] = sexp.list
|
|
433
|
+
[bases, keywords] = classdef_args_parse(args)
|
|
434
|
+
return ast.ClassDef(
|
|
435
|
+
name=clsname.name,
|
|
436
|
+
bases=bases,
|
|
437
|
+
keywords=keywords,
|
|
438
|
+
body=stmt_list_compile(body) if body else [ast.Pass(**sexp.position_info)],
|
|
439
|
+
decorator_list=list(map(expr_compile, decorator_list))
|
|
440
|
+
if decorator_list
|
|
441
|
+
else [],
|
|
442
|
+
**sexp.position_info
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def stmt_compile(sexp, decorator_list=None):
|
|
447
|
+
return (
|
|
448
|
+
expr_wrapper(sexp)
|
|
449
|
+
if not paren_p(sexp)
|
|
450
|
+
else do_compile(sexp)
|
|
451
|
+
if do_p(sexp)
|
|
452
|
+
else assign_compile(sexp)
|
|
453
|
+
if assign_p(sexp)
|
|
454
|
+
else augassign_compile(sexp)
|
|
455
|
+
if augassign_p(sexp)
|
|
456
|
+
else del_compile(sexp)
|
|
457
|
+
if str(sexp.op) == "del"
|
|
458
|
+
else ast.Pass(**sexp.position_info)
|
|
459
|
+
if str(sexp.op) == "pass"
|
|
460
|
+
else import_compile(sexp)
|
|
461
|
+
if str(sexp.op) == "import"
|
|
462
|
+
else importfrom_compile(sexp)
|
|
463
|
+
if str(sexp.op) == "from"
|
|
464
|
+
else if_stmt_compile(sexp)
|
|
465
|
+
if if_p(sexp)
|
|
466
|
+
else while_compile(sexp)
|
|
467
|
+
if while_p(sexp)
|
|
468
|
+
else for_compile(sexp)
|
|
469
|
+
if for_p(sexp)
|
|
470
|
+
else ast.Break(**sexp.position_info)
|
|
471
|
+
if str(sexp.op) == "break"
|
|
472
|
+
else ast.Continue(**sexp.position_info)
|
|
473
|
+
if str(sexp.op) == "continue"
|
|
474
|
+
else raise_compile(sexp)
|
|
475
|
+
if str(sexp.op) == "raise"
|
|
476
|
+
else assert_compile(sexp)
|
|
477
|
+
if str(sexp.op) == "assert"
|
|
478
|
+
else try_compile(sexp)
|
|
479
|
+
if str(sexp.op) == "try"
|
|
480
|
+
else with_compile(sexp)
|
|
481
|
+
if str(sexp.op) == "with"
|
|
482
|
+
else match_compile(sexp)
|
|
483
|
+
if str(sexp.op) == "match"
|
|
484
|
+
else deco_compile(sexp, decorator_list)
|
|
485
|
+
if deco_p(sexp)
|
|
486
|
+
else functiondef_compile(sexp, decorator_list)
|
|
487
|
+
if functiondef_p(sexp)
|
|
488
|
+
else return_compile(sexp)
|
|
489
|
+
if return_p(sexp)
|
|
490
|
+
else global_compile(sexp)
|
|
491
|
+
if str(sexp.op) == "global"
|
|
492
|
+
else nonlocal_compile(sexp)
|
|
493
|
+
if str(sexp.op) == "nonlocal"
|
|
494
|
+
else classdef_compile(sexp, decorator_list)
|
|
495
|
+
if classdef_p(sexp)
|
|
496
|
+
else functiondef_compile(sexp, decorator_list, async_p=True)
|
|
497
|
+
if str(sexp.op) == "async-def"
|
|
498
|
+
else for_compile(sexp, async_p=True)
|
|
499
|
+
if str(sexp.op) == "async-for"
|
|
500
|
+
else with_compile(sexp, async_p=True)
|
|
501
|
+
if str(sexp.op) == "async-with"
|
|
502
|
+
else expr_wrapper(sexp)
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def stmt_list_compile(sexp_list):
|
|
507
|
+
return reduce(
|
|
508
|
+
lambda x, y: x + (y if isinstance(y, list) else [y]),
|
|
509
|
+
map(stmt_compile, sexp_list),
|
|
510
|
+
[],
|
|
511
|
+
)
|
|
@@ -58,11 +58,13 @@
|
|
|
58
58
|
scope
|
|
59
59
|
:include-meta include-meta)))))
|
|
60
60
|
|
|
61
|
-
(def src-to-python [src :include-meta False :scope None]
|
|
61
|
+
(def src-to-python [src :include-meta False :scope None :format True]
|
|
62
62
|
(if (is scope None)
|
|
63
63
|
(= scope SCOPE))
|
|
64
64
|
(= raw-pysrc (src-to-python-org src :include-meta include-meta :scope scope))
|
|
65
|
-
(
|
|
65
|
+
(if format
|
|
66
|
+
(return (format-python-source raw-pysrc))
|
|
67
|
+
(return raw-pysrc)))
|
|
66
68
|
|
|
67
69
|
(def format-python-source [pysrc]
|
|
68
70
|
(if (not HAS_RUFF)
|
|
@@ -93,19 +95,19 @@
|
|
|
93
95
|
:dest "no_lispy"
|
|
94
96
|
:action "store_true")
|
|
95
97
|
|
|
96
|
-
(def l2py-s [src :include-meta False :fresh-scope False :package "" :no-lispy False]
|
|
98
|
+
(def l2py-s [src :include-meta False :fresh-scope False :package "" :no-lispy False :format True]
|
|
97
99
|
"Translate lispy source string to Python source string"
|
|
98
100
|
(if fresh-scope
|
|
99
101
|
(= scope {"__builtins__" __builtins__
|
|
100
102
|
"__package__" package
|
|
101
103
|
"__macro_namespace" {}})
|
|
102
104
|
(= scope SCOPE))
|
|
103
|
-
(= pysrc (src-to-python src :include-meta include_meta :scope scope))
|
|
105
|
+
(= pysrc (src-to-python src :include-meta include_meta :scope scope :format format))
|
|
104
106
|
(if no_lispy
|
|
105
107
|
(return pysrc))
|
|
106
108
|
(return (+ "import lispy\n\n" pysrc)))
|
|
107
109
|
|
|
108
|
-
(def l2py-f [file-path :include-meta False :no-lispy False]
|
|
110
|
+
(def l2py-f [file-path :include-meta False :no-lispy False :format True]
|
|
109
111
|
"Translate lispy file to Python source string (standalone with sys.path setup)"
|
|
110
112
|
(= script-dir (osp.dirname (osp.abspath file-path)))
|
|
111
113
|
(if (not (in script-dir sys.path))
|
|
@@ -126,7 +128,7 @@
|
|
|
126
128
|
(with [(open file-path "rb") as f]
|
|
127
129
|
(= src (.decode (f.read) "utf-8")))
|
|
128
130
|
(= pkg (detect-package-name :path file-path))
|
|
129
|
-
(return (+ (l2py-s src :include-meta include_meta :fresh-scope True :package pkg :no-lispy no_lispy) "\n")))
|
|
131
|
+
(return (+ (l2py-s src :include-meta include_meta :fresh-scope True :package pkg :no-lispy no_lispy :format format) "\n")))
|
|
130
132
|
|
|
131
133
|
(def l2py []
|
|
132
134
|
"CLI entry point: parse args and translate file"
|
|
@@ -18,9 +18,9 @@ class TestMetaFunctionsSync:
|
|
|
18
18
|
with open(py_path, "r") as f:
|
|
19
19
|
py_contents = f.read()
|
|
20
20
|
|
|
21
|
-
transpiled = l2py_s(lpy_src)
|
|
21
|
+
transpiled = l2py_s(lpy_src, no_lispy=True)
|
|
22
22
|
|
|
23
23
|
assert transpiled == py_contents, (
|
|
24
24
|
"core/meta_functions.py is out of sync with core_meta_functions.lpy. "
|
|
25
|
-
"Run `
|
|
25
|
+
"Run `lpy src/lispy/core_meta_functions.lpy` to regenerate."
|
|
26
26
|
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|