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.
@@ -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.
@@ -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
+ [![PyPI version](https://badge.fury.io/py/lispython.svg)](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
+ [![PyPI version](https://badge.fury.io/py/lispython.svg)](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,4 @@
1
+ import sys
2
+
3
+ import lispy.core.importer
4
+ from lispy.tools import run, l2py
@@ -0,0 +1,2 @@
1
+ from lispy.core.compiler.expr import *
2
+ from lispy.core.compiler.stmt import *
@@ -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