lispython 0.1.0__tar.gz → 0.2.0__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.2.0/LICENSE.md +21 -0
- lispython-0.2.0/PKG-INFO +69 -0
- lispython-0.2.0/README.md +54 -0
- lispython-0.2.0/pyproject.toml +36 -0
- lispython-0.2.0/src/lispy/__init__.py +4 -0
- lispython-0.2.0/src/lispy/core/compiler/__init__.py +2 -0
- lispython-0.2.0/src/lispy/core/compiler/expr.py +489 -0
- lispython-0.2.0/src/lispy/core/compiler/literal.py +24 -0
- lispython-0.2.0/src/lispy/core/compiler/stmt.py +511 -0
- lispython-0.2.0/src/lispy/core/compiler/utils.py +45 -0
- lispython-0.2.0/src/lispy/core/importer.py +57 -0
- lispython-0.2.0/src/lispy/core/macro.py +92 -0
- lispython-0.2.0/src/lispy/core/meta_functions.py +107 -0
- lispython-0.2.0/src/lispy/core/nodes.py +473 -0
- lispython-0.2.0/src/lispy/core/parser.py +285 -0
- lispython-0.2.0/src/lispy/core/utils.py +32 -0
- lispython-0.2.0/src/lispy/core_meta_functions.lpy +45 -0
- lispython-0.2.0/src/lispy/macros/__init__.py +2 -0
- lispython-0.2.0/src/lispy/macros/init.lpy +1 -0
- lispython-0.2.0/src/lispy/macros/sugar.lpy +38 -0
- lispython-0.2.0/src/lispy/tools.lpy +143 -0
- lispython-0.1.0/PKG-INFO +0 -13
- lispython-0.1.0/README.md +0 -1
- lispython-0.1.0/pyproject.toml +0 -17
- lispython-0.1.0/src/lispy/__init__.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jethack
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lispython-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: lispython
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Lisp-like Syntax for Python with Lisp-like Macros
|
|
5
|
+
Home-page: https://jethack23.github.io/lispython
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: Jethack
|
|
8
|
+
Author-email: jethack23@gmail.com
|
|
9
|
+
Requires-Python: >=3.11,<3.12
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Project-URL: Repository, https://github.com/jethack23/lispython
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# LisPython
|
|
17
|
+
[](https://badge.fury.io/py/lispython)
|
|
18
|
+
|
|
19
|
+
# Documentation
|
|
20
|
+
You can find the documentation at [https://jethack23.github.io/lispython/](https://jethack23.github.io/lispython/).
|
|
21
|
+
|
|
22
|
+
# Installation
|
|
23
|
+
## Manual Installation (for development)
|
|
24
|
+
```bash
|
|
25
|
+
poetry install --no-root # for dependency
|
|
26
|
+
pip install -e . # for development
|
|
27
|
+
```
|
|
28
|
+
## Using pip
|
|
29
|
+
```bash
|
|
30
|
+
pip install lispython
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
# How to Run lispy code
|
|
34
|
+
## Run from source
|
|
35
|
+
```bash
|
|
36
|
+
lpy {filename}.lpy
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Run REPL
|
|
40
|
+
```bash
|
|
41
|
+
lpy
|
|
42
|
+
#or
|
|
43
|
+
lpy -t #if you want to print python translation.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Run translation
|
|
47
|
+
```bash
|
|
48
|
+
l2py {filename}.lpy
|
|
49
|
+
```
|
|
50
|
+
It just displays translation. (don't run it)
|
|
51
|
+
|
|
52
|
+
## Run Tests
|
|
53
|
+
```bash
|
|
54
|
+
# in project root directory
|
|
55
|
+
python -m unittest
|
|
56
|
+
#or
|
|
57
|
+
lpy -m unittest
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Todo
|
|
62
|
+
## Environment
|
|
63
|
+
- [ ] Test on more python versions
|
|
64
|
+
- [ ] Some IDE plugins like hy-mode and jedhy for better editing experience.
|
|
65
|
+
## Macro System
|
|
66
|
+
- [ ] `as->` macro for syntactic sugar
|
|
67
|
+
- [ ] `gensym` for avoiding name collision
|
|
68
|
+
## Python AST
|
|
69
|
+
- [ ] `type_comment` never considered. Later, it should be covered
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# LisPython
|
|
2
|
+
[](https://badge.fury.io/py/lispython)
|
|
3
|
+
|
|
4
|
+
# Documentation
|
|
5
|
+
You can find the documentation at [https://jethack23.github.io/lispython/](https://jethack23.github.io/lispython/).
|
|
6
|
+
|
|
7
|
+
# Installation
|
|
8
|
+
## Manual Installation (for development)
|
|
9
|
+
```bash
|
|
10
|
+
poetry install --no-root # for dependency
|
|
11
|
+
pip install -e . # for development
|
|
12
|
+
```
|
|
13
|
+
## Using pip
|
|
14
|
+
```bash
|
|
15
|
+
pip install lispython
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
# How to Run lispy code
|
|
19
|
+
## Run from source
|
|
20
|
+
```bash
|
|
21
|
+
lpy {filename}.lpy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Run REPL
|
|
25
|
+
```bash
|
|
26
|
+
lpy
|
|
27
|
+
#or
|
|
28
|
+
lpy -t #if you want to print python translation.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Run translation
|
|
32
|
+
```bash
|
|
33
|
+
l2py {filename}.lpy
|
|
34
|
+
```
|
|
35
|
+
It just displays translation. (don't run it)
|
|
36
|
+
|
|
37
|
+
## Run Tests
|
|
38
|
+
```bash
|
|
39
|
+
# in project root directory
|
|
40
|
+
python -m unittest
|
|
41
|
+
#or
|
|
42
|
+
lpy -m unittest
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Todo
|
|
47
|
+
## Environment
|
|
48
|
+
- [ ] Test on more python versions
|
|
49
|
+
- [ ] Some IDE plugins like hy-mode and jedhy for better editing experience.
|
|
50
|
+
## Macro System
|
|
51
|
+
- [ ] `as->` macro for syntactic sugar
|
|
52
|
+
- [ ] `gensym` for avoiding name collision
|
|
53
|
+
## Python AST
|
|
54
|
+
- [ ] `type_comment` never considered. Later, it should be covered
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "lispython"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "Lisp-like Syntax for Python with Lisp-like Macros"
|
|
5
|
+
authors = ["Jethack <jethack23@gmail.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
homepage = "https://jethack23.github.io/lispython"
|
|
9
|
+
repository = "https://github.com/jethack23/lispython"
|
|
10
|
+
packages = [
|
|
11
|
+
{include = "lispy", from = "src"}
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[tool.poetry.dependencies]
|
|
15
|
+
python = "~3.11"
|
|
16
|
+
|
|
17
|
+
[tool.poetry.scripts]
|
|
18
|
+
lpy = "lispy:run"
|
|
19
|
+
l2py = "lispy:l2py"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
[tool.poetry.group.dev.dependencies]
|
|
23
|
+
pre-commit = "^3.6.0"
|
|
24
|
+
black = "^23.12.1"
|
|
25
|
+
isort = "^5.13.2"
|
|
26
|
+
toml = "^0.10.2"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
[tool.poetry.group.docs.dependencies]
|
|
30
|
+
mkdocs-material = "^9.6.14"
|
|
31
|
+
mkdocs-macros-plugin = "^1.3.7"
|
|
32
|
+
mike = "^2.1.3"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["poetry-core"]
|
|
36
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from collections import deque
|
|
3
|
+
from functools import reduce
|
|
4
|
+
|
|
5
|
+
from lispy.core.compiler.literal import *
|
|
6
|
+
from lispy.core.compiler.utils import *
|
|
7
|
+
from lispy.core.utils import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def tuple_p(sexp):
|
|
11
|
+
return str(sexp.op) == ","
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def tuple_compile(sexp, ctx):
|
|
15
|
+
[op, *args] = sexp.list
|
|
16
|
+
return ast.Tuple(
|
|
17
|
+
elts=list(map(lambda x: expr_compile(x, ctx), args)),
|
|
18
|
+
ctx=ctx(),
|
|
19
|
+
**sexp.position_info
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def starred_compile(sexp, ctx):
|
|
24
|
+
return ast.Starred(
|
|
25
|
+
value=expr_compile(sexp.value, ctx), ctx=ctx(), **sexp.position_info
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def unaryop_p(sexp):
|
|
30
|
+
return str(sexp.op) in unaryop_dict and len(sexp) == 2
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def unaryop_compile(sexp):
|
|
34
|
+
[op, operand] = sexp.list
|
|
35
|
+
return ast.UnaryOp(
|
|
36
|
+
unaryop_dict[str(op)](), expr_compile(operand), **sexp.position_info
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def binop_p(sexp):
|
|
41
|
+
return str(sexp.op) in binop_dict and len(sexp) > 2
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def binop_compile(sexp):
|
|
45
|
+
[op, *args] = sexp.list
|
|
46
|
+
return reduce(
|
|
47
|
+
lambda x, y: ast.BinOp(x, binop_dict[str(op)](), y, **sexp.position_info),
|
|
48
|
+
map(expr_compile, args),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def boolop_p(sexp):
|
|
53
|
+
return str(sexp.op) in boolop_dict
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def boolop_compile(sexp):
|
|
57
|
+
[op, *args] = sexp.list
|
|
58
|
+
return ast.BoolOp(
|
|
59
|
+
boolop_dict[op.name](), list(map(expr_compile, args)), **sexp.position_info
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def compare_p(sexp):
|
|
64
|
+
return str(sexp.op) in compare_dict
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def compare_compile(sexp):
|
|
68
|
+
[op, *args] = sexp.list
|
|
69
|
+
[left, *comparators] = map(expr_compile, args)
|
|
70
|
+
return ast.Compare(
|
|
71
|
+
left=left,
|
|
72
|
+
ops=[compare_dict[str(op)]() for i in range(len(comparators))],
|
|
73
|
+
comparators=comparators,
|
|
74
|
+
**sexp.position_info
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def call_args_parse(given):
|
|
79
|
+
q = deque(given)
|
|
80
|
+
args = []
|
|
81
|
+
keywords = []
|
|
82
|
+
while q:
|
|
83
|
+
arg = q.popleft()
|
|
84
|
+
keywords.append(
|
|
85
|
+
ast.keyword(
|
|
86
|
+
arg=arg.name, value=expr_compile(q.popleft()), **arg.position_info
|
|
87
|
+
)
|
|
88
|
+
) if keyword_arg_p(arg) else keywords.append(
|
|
89
|
+
ast.keyword(value=expr_compile(arg.value), **arg.position_info)
|
|
90
|
+
) if doublestarred_p(
|
|
91
|
+
arg
|
|
92
|
+
) else args.append(
|
|
93
|
+
expr_compile(arg)
|
|
94
|
+
)
|
|
95
|
+
return [args, keywords]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def call_compile(sexp):
|
|
99
|
+
[op, *operands] = sexp.list
|
|
100
|
+
op = expr_compile(op)
|
|
101
|
+
[args, keywords] = call_args_parse(operands)
|
|
102
|
+
return ast.Call(func=op, args=args, keywords=keywords, **sexp.position_info)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def ifexp_p(sexp):
|
|
106
|
+
return str(sexp.op) == "ife"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def ifexp_compile(sexp):
|
|
110
|
+
[_, test, body, orelse] = sexp.list
|
|
111
|
+
return ast.IfExp(
|
|
112
|
+
test=expr_compile(test),
|
|
113
|
+
body=expr_compile(body),
|
|
114
|
+
orelse=expr_compile(orelse),
|
|
115
|
+
**sexp.position_info
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def attribute_p(sexp):
|
|
120
|
+
return str(sexp.op) == "."
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def attribute_compile(sexp, ctx):
|
|
124
|
+
[_, value, *attrs] = sexp.list
|
|
125
|
+
rst = expr_compile(value, ast.Load)
|
|
126
|
+
position_info = {**sexp.position_info}
|
|
127
|
+
for attr in attrs:
|
|
128
|
+
position_info["end_lineno"] = attr.position_info["end_lineno"]
|
|
129
|
+
position_info["end_col_offset"] = attr.position_info["end_col_offset"]
|
|
130
|
+
rst = ast.Attribute(value=rst, attr=str(attr), ctx=ast.Load(), **position_info)
|
|
131
|
+
rst.ctx = ctx()
|
|
132
|
+
return rst
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def methodcall_p(sexp):
|
|
136
|
+
return str(sexp.op).startswith(".")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def methodcall_compile(sexp):
|
|
140
|
+
[method, instance, *operands] = sexp.list
|
|
141
|
+
[args, keywords] = call_args_parse(operands)
|
|
142
|
+
func = ast.Attribute(
|
|
143
|
+
value=expr_compile(instance),
|
|
144
|
+
attr=method.name[slice(1, None)],
|
|
145
|
+
ctx=ast.Load(),
|
|
146
|
+
**merge_position_infos(method.position_info, instance.position_info)
|
|
147
|
+
)
|
|
148
|
+
return ast.Call(func=func, args=args, keywords=keywords, **sexp.position_info)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def namedexpr_p(sexp):
|
|
152
|
+
return str(sexp.op) == ":="
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def namedexpr_compile(sexp):
|
|
156
|
+
[_, target, value] = sexp.list
|
|
157
|
+
return ast.NamedExpr(
|
|
158
|
+
target=expr_compile(target, ctx=ast.Store),
|
|
159
|
+
value=expr_compile(value),
|
|
160
|
+
**sexp.position_info
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def subscript_p(sexp):
|
|
165
|
+
return str(sexp.op) == "sub"
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def subscript_compile(sexp, ctx):
|
|
169
|
+
[op, value, *slices] = sexp.list
|
|
170
|
+
op_pos = op.position_info
|
|
171
|
+
rst = reduce(
|
|
172
|
+
lambda rst, slice: ast.Subscript(
|
|
173
|
+
value=rst,
|
|
174
|
+
slice=expr_compile(slice),
|
|
175
|
+
ctx=ast.Load(),
|
|
176
|
+
**merge_position_infos(op_pos, slice.position_info)
|
|
177
|
+
),
|
|
178
|
+
slices,
|
|
179
|
+
expr_compile(value),
|
|
180
|
+
)
|
|
181
|
+
rst.ctx = ctx()
|
|
182
|
+
return rst
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def parse_comprehensions(generator_body):
|
|
186
|
+
q = deque(generator_body)
|
|
187
|
+
rst = []
|
|
188
|
+
while q:
|
|
189
|
+
is_async = 0 if q.popleft() == "for" else 1
|
|
190
|
+
target = expr_compile(q.popleft(), ctx=ast.Store)
|
|
191
|
+
if q[0] == "in":
|
|
192
|
+
q.popleft()
|
|
193
|
+
iter = expr_compile(q.popleft())
|
|
194
|
+
comprehension = ast.comprehension(is_async=is_async, target=target, iter=iter)
|
|
195
|
+
ifs = []
|
|
196
|
+
while q and (not str(q[0]) in ["for", "async-for"]):
|
|
197
|
+
ifs.append(q.popleft())
|
|
198
|
+
comprehension.ifs = list(map(expr_compile, ifs[slice(1, None, 2)]))
|
|
199
|
+
rst.append(comprehension)
|
|
200
|
+
return rst
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def gen_exp_compile(sexp):
|
|
204
|
+
[elt, *generator_body] = sexp
|
|
205
|
+
return ast.GeneratorExp(
|
|
206
|
+
elt=expr_compile(elt),
|
|
207
|
+
generators=parse_comprehensions(generator_body),
|
|
208
|
+
**sexp.position_info
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def def_args_parse(sexp):
|
|
213
|
+
q = deque(sexp.list)
|
|
214
|
+
rst = ast.arguments(posonlyargs=[], **sexp.position_info)
|
|
215
|
+
args = []
|
|
216
|
+
defaults = []
|
|
217
|
+
kwonlyargs = []
|
|
218
|
+
kw_defaults = []
|
|
219
|
+
|
|
220
|
+
# before starred
|
|
221
|
+
while q and (not str(q[0]).startswith("*")):
|
|
222
|
+
arg = q.popleft()
|
|
223
|
+
if arg == "/":
|
|
224
|
+
rst.posonlyargs = args
|
|
225
|
+
args = []
|
|
226
|
+
else:
|
|
227
|
+
ast_arg = ast.arg(arg=arg.name, **arg.position_info)
|
|
228
|
+
if q and isinstance(q[0], Annotation):
|
|
229
|
+
ast_arg.annotation = expr_compile(q.popleft())
|
|
230
|
+
args.append(ast_arg)
|
|
231
|
+
if keyword_arg_p(arg):
|
|
232
|
+
defaults.append(expr_compile(q.popleft()))
|
|
233
|
+
rst.args = args
|
|
234
|
+
rst.defaults = defaults
|
|
235
|
+
|
|
236
|
+
# starred
|
|
237
|
+
if q and isinstance(q[0], Starred):
|
|
238
|
+
arg = q.popleft()
|
|
239
|
+
ast_arg = ast.arg(arg=arg.value.name, **arg.position_info)
|
|
240
|
+
if q and isinstance(q[0], Annotation):
|
|
241
|
+
ast_arg.annotation = expr_compile(q.popleft())
|
|
242
|
+
rst.vararg = ast_arg
|
|
243
|
+
if q and q[0] == "*":
|
|
244
|
+
q.popleft()
|
|
245
|
+
|
|
246
|
+
# before doublestarred
|
|
247
|
+
while q and (not isinstance(q[0], DoubleStarred)):
|
|
248
|
+
arg = q.popleft()
|
|
249
|
+
ast_arg = ast.arg(arg=arg.name, **arg.position_info)
|
|
250
|
+
if q and isinstance(q[0], Annotation):
|
|
251
|
+
ast_arg.annotation = expr_compile(q.popleft())
|
|
252
|
+
kwonlyargs.append(ast_arg)
|
|
253
|
+
kw_defaults.append(expr_compile(q.popleft()) if keyword_arg_p(arg) else None)
|
|
254
|
+
rst.kwonlyargs = kwonlyargs
|
|
255
|
+
rst.kw_defaults = kw_defaults
|
|
256
|
+
|
|
257
|
+
# doublestarred
|
|
258
|
+
if q:
|
|
259
|
+
arg = q.popleft()
|
|
260
|
+
ast_arg = ast.arg(arg=arg.value.name, **arg.position_info)
|
|
261
|
+
if q and isinstance(q[0], Annotation):
|
|
262
|
+
ast_arg.annotation = expr_compile(q.popleft())
|
|
263
|
+
rst.kwarg = ast_arg
|
|
264
|
+
return rst
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def lambda_p(sexp):
|
|
268
|
+
return str(sexp.op) == "lambda"
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def lambda_compile(sexp):
|
|
272
|
+
[_, args, body] = sexp.list
|
|
273
|
+
return ast.Lambda(
|
|
274
|
+
args=def_args_parse(args), body=expr_compile(body), **sexp.position_info
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def yield_compile(sexp):
|
|
279
|
+
val_dict = {"value": expr_compile(sexp[1])} if len(sexp) > 1 else {}
|
|
280
|
+
return ast.Yield(**val_dict, **sexp.position_info)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def yield_from_compile(sexp):
|
|
284
|
+
value = sexp[1]
|
|
285
|
+
return ast.YieldFrom(value=expr_compile(value), **sexp.position_info)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def await_compile(sexp):
|
|
289
|
+
[_, value] = sexp.list
|
|
290
|
+
return ast.Await(value=expr_compile(value), **sexp.position_info)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def f_str_value_compile(sexp):
|
|
294
|
+
format_spec_dict = (
|
|
295
|
+
{}
|
|
296
|
+
if sexp.format_spec is None
|
|
297
|
+
else {
|
|
298
|
+
"format_spec": ast.JoinedStr(
|
|
299
|
+
values=[ast.Constant(value=sexp.format_spec, **sexp.position_info)],
|
|
300
|
+
**sexp.position_info
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
return ast.FormattedValue(
|
|
305
|
+
value=expr_compile(sexp.value),
|
|
306
|
+
conversion=sexp.conversion,
|
|
307
|
+
**format_spec_dict,
|
|
308
|
+
**sexp.position_info
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def f_string_compile(sexp):
|
|
313
|
+
values = sexp.operands
|
|
314
|
+
compiled = []
|
|
315
|
+
for [i, v] in enumerate(values):
|
|
316
|
+
compiled.append(f_str_value_compile(v)) if i % 2 else compiled.append(
|
|
317
|
+
string_compile(v)
|
|
318
|
+
)
|
|
319
|
+
return ast.JoinedStr(values=compiled, **sexp.position_info)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def paren_compiler(sexp, ctx):
|
|
323
|
+
return (
|
|
324
|
+
tuple_compile(sexp, ctx)
|
|
325
|
+
if tuple_p(sexp)
|
|
326
|
+
else unaryop_compile(sexp)
|
|
327
|
+
if unaryop_p(sexp)
|
|
328
|
+
else binop_compile(sexp)
|
|
329
|
+
if binop_p(sexp)
|
|
330
|
+
else boolop_compile(sexp)
|
|
331
|
+
if boolop_p(sexp)
|
|
332
|
+
else compare_compile(sexp)
|
|
333
|
+
if compare_p(sexp)
|
|
334
|
+
else ifexp_compile(sexp)
|
|
335
|
+
if ifexp_p(sexp)
|
|
336
|
+
else attribute_compile(sexp, ctx)
|
|
337
|
+
if attribute_p(sexp)
|
|
338
|
+
else methodcall_compile(sexp)
|
|
339
|
+
if methodcall_p(sexp)
|
|
340
|
+
else namedexpr_compile(sexp)
|
|
341
|
+
if namedexpr_p(sexp)
|
|
342
|
+
else subscript_compile(sexp, ctx)
|
|
343
|
+
if subscript_p(sexp)
|
|
344
|
+
else gen_exp_compile(sexp)
|
|
345
|
+
if len(sexp) > 1 and str(sexp[1]) in ["for", "async-for"]
|
|
346
|
+
else lambda_compile(sexp)
|
|
347
|
+
if lambda_p(sexp)
|
|
348
|
+
else yield_compile(sexp)
|
|
349
|
+
if sexp.op == "yield"
|
|
350
|
+
else yield_from_compile(sexp)
|
|
351
|
+
if sexp.op == "yield-from"
|
|
352
|
+
else await_compile(sexp)
|
|
353
|
+
if sexp.op == "await"
|
|
354
|
+
else f_string_compile(sexp)
|
|
355
|
+
if sexp.op == "f-string"
|
|
356
|
+
else call_compile(sexp)
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def slice_compile(sexp):
|
|
361
|
+
[_, *args] = sexp.list
|
|
362
|
+
args = deque(args)
|
|
363
|
+
args_dict = {}
|
|
364
|
+
if args:
|
|
365
|
+
lower = args.popleft()
|
|
366
|
+
if lower != "None" and lower != "_":
|
|
367
|
+
args_dict["lower"] = expr_compile(lower)
|
|
368
|
+
if args:
|
|
369
|
+
upper = args.popleft()
|
|
370
|
+
if upper != "None" and upper != "_":
|
|
371
|
+
args_dict["upper"] = expr_compile(upper)
|
|
372
|
+
if args:
|
|
373
|
+
step = args.popleft()
|
|
374
|
+
if step != "None" and step != "_":
|
|
375
|
+
args_dict["step"] = expr_compile(step)
|
|
376
|
+
return ast.Slice(**args_dict, **sexp.position_info)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def list_comp_compile(sexp):
|
|
380
|
+
[elt, *generator_body] = sexp
|
|
381
|
+
return ast.ListComp(
|
|
382
|
+
elt=expr_compile(elt),
|
|
383
|
+
generators=parse_comprehensions(generator_body),
|
|
384
|
+
**sexp.position_info
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def list_compile(sexp, ctx):
|
|
389
|
+
args = sexp.list
|
|
390
|
+
return ast.List(
|
|
391
|
+
elts=list(map(lambda x: expr_compile(x, ctx), args)),
|
|
392
|
+
ctx=ctx(),
|
|
393
|
+
**sexp.position_info
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def bracket_compiler(sexp, ctx):
|
|
398
|
+
return (
|
|
399
|
+
list_compile(sexp, ctx)
|
|
400
|
+
if len(sexp) < 1
|
|
401
|
+
else slice_compile(sexp)
|
|
402
|
+
if str(sexp.op) == ":"
|
|
403
|
+
else list_comp_compile(sexp)
|
|
404
|
+
if len(sexp) > 1 and str(sexp[1]) in ["for", "async-for"]
|
|
405
|
+
else list_compile(sexp, ctx)
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def set_compile(sexp):
|
|
410
|
+
[op, *args] = sexp.list
|
|
411
|
+
return ast.Set(elts=list(map(expr_compile, args)), **sexp.position_info)
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def dict_compile(sexp):
|
|
415
|
+
elts = reduce(
|
|
416
|
+
lambda x, y: x
|
|
417
|
+
+ ([None, expr_compile(y.value)] if doublestarred_p(y) else [expr_compile(y)]),
|
|
418
|
+
sexp,
|
|
419
|
+
[],
|
|
420
|
+
)
|
|
421
|
+
keys = elts[slice(None, None, 2)]
|
|
422
|
+
values = elts[slice(1, None, 2)]
|
|
423
|
+
return ast.Dict(keys=keys, values=values, **sexp.position_info)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def dict_comp_compile(sexp):
|
|
427
|
+
[key, value, *generator_body] = sexp
|
|
428
|
+
return ast.DictComp(
|
|
429
|
+
key=expr_compile(key),
|
|
430
|
+
value=expr_compile(value),
|
|
431
|
+
generators=parse_comprehensions(generator_body),
|
|
432
|
+
**sexp.position_info
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def set_comp_compile(sexp):
|
|
437
|
+
[elt, *generator_body] = sexp.operands
|
|
438
|
+
return ast.SetComp(
|
|
439
|
+
elt=expr_compile(elt),
|
|
440
|
+
generators=parse_comprehensions(generator_body),
|
|
441
|
+
**sexp.position_info
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def brace_compiler(sexp):
|
|
446
|
+
return (
|
|
447
|
+
dict_compile(sexp)
|
|
448
|
+
if len(sexp) < 1
|
|
449
|
+
else (set_comp_compile if str(sexp.op) == "," else dict_comp_compile)(sexp)
|
|
450
|
+
if len(sexp) > 2 and str(sexp[2]) in ["for", "async-for"]
|
|
451
|
+
else set_compile(sexp)
|
|
452
|
+
if str(sexp.op) == ","
|
|
453
|
+
else dict_compile(sexp)
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def metaindicator_p(sexp):
|
|
458
|
+
return isinstance(sexp, MetaIndicator)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def metaindicator_compile(sexp):
|
|
462
|
+
if isinstance(sexp, Quote):
|
|
463
|
+
return expr_compile(
|
|
464
|
+
sexp.value.generator_expression(isinstance(sexp, QuasiQuote))
|
|
465
|
+
)
|
|
466
|
+
else:
|
|
467
|
+
raise ValueError("'unquote' is not allowed here")
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def expr_compile(sexp, ctx=ast.Load):
|
|
471
|
+
return (
|
|
472
|
+
paren_compiler(sexp, ctx)
|
|
473
|
+
if paren_p(sexp)
|
|
474
|
+
else bracket_compiler(sexp, ctx)
|
|
475
|
+
if bracket_p(sexp)
|
|
476
|
+
else brace_compiler(sexp)
|
|
477
|
+
if brace_p(sexp)
|
|
478
|
+
else expr_compile(sexp.value)
|
|
479
|
+
if isinstance(sexp, Annotation)
|
|
480
|
+
else starred_compile(sexp, ctx)
|
|
481
|
+
if starred_p(sexp)
|
|
482
|
+
else constant_compile(sexp)
|
|
483
|
+
if constant_p(sexp)
|
|
484
|
+
else string_compile(sexp)
|
|
485
|
+
if string_p(sexp)
|
|
486
|
+
else metaindicator_compile(sexp)
|
|
487
|
+
if metaindicator_p(sexp)
|
|
488
|
+
else name_compile(sexp, ctx)
|
|
489
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def constant_compile(constant):
|
|
5
|
+
return ast.Constant(value=eval(constant.value), **constant.position_info)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def string_compile(string):
|
|
9
|
+
return ast.Constant(
|
|
10
|
+
value=eval(string.value.replace("\r\n", "\\n").replace("\n", "\\n")),
|
|
11
|
+
**string.position_info
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def name_compile(symbol, ctx):
|
|
16
|
+
[name, *attrs] = symbol.name.replace("-", "_").split(".")
|
|
17
|
+
position_info = {**symbol.position_info}
|
|
18
|
+
position_info["end_col_offset"] = position_info["col_offset"] + len(name)
|
|
19
|
+
rst = ast.Name(id=name, ctx=ast.Load(), **position_info)
|
|
20
|
+
for attr in attrs:
|
|
21
|
+
position_info["end_col_offset"] += 1 + len(attr)
|
|
22
|
+
rst = ast.Attribute(value=rst, attr=attr, ctx=ast.Load(), **position_info)
|
|
23
|
+
rst.ctx = ctx()
|
|
24
|
+
return rst
|