Skip to content

Commit eef6fb0

Browse files
authored
Create Python literals using #py reader tag (#337)
* Create Python literals using #py reader tag * Testing * Fix MyPy error * Some lrepr tests * Support all Python collection literals * Formatting * More tests * More tests
1 parent 0b35671 commit eef6fb0

File tree

13 files changed

+600
-83
lines changed

13 files changed

+600
-83
lines changed

src/basilisp/lang/compiler/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
WARN_ON_SHADOWED_VAR,
2626
WARN_ON_UNUSED_NAMES,
2727
)
28-
from basilisp.lang.typing import LispForm
28+
from basilisp.lang.typing import ReaderForm
2929
from basilisp.lang.util import genname
3030

3131
_DEFAULT_FN = "__lisp_expr__"
@@ -67,7 +67,7 @@ def py_ast_optimizer(self) -> PythonASTOptimizer:
6767

6868

6969
def compile_and_exec_form( # pylint: disable= too-many-arguments
70-
form: LispForm,
70+
form: ReaderForm,
7171
ctx: CompilerContext,
7272
module: types.ModuleType,
7373
wrapped_fn_name: str = _DEFAULT_FN,
@@ -164,7 +164,7 @@ def _bootstrap_module(
164164

165165

166166
def compile_module(
167-
forms: Iterable[LispForm],
167+
forms: Iterable[ReaderForm],
168168
ctx: CompilerContext,
169169
module: types.ModuleType,
170170
collect_bytecode: Optional[BytecodeCollector] = None,

src/basilisp/lang/compiler/generator.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@
7979
Binding,
8080
NodeEnv,
8181
Catch,
82+
PyList,
83+
PySet,
84+
PyTuple,
85+
PyDict,
8286
)
8387
from basilisp.lang.runtime import Var
8488
from basilisp.lang.typing import LispForm
@@ -1752,6 +1756,51 @@ def _vec_to_py_ast(
17521756
)
17531757

17541758

1759+
#####################
1760+
# Python Collections
1761+
#####################
1762+
1763+
1764+
@_with_ast_loc
1765+
def _py_dict_to_py_ast(ctx: GeneratorContext, node: PyDict) -> GeneratedPyAST:
1766+
assert node.op == NodeOp.PY_DICT
1767+
1768+
key_deps, keys = _chain_py_ast(*map(partial(gen_py_ast, ctx), node.keys))
1769+
val_deps, vals = _chain_py_ast(*map(partial(gen_py_ast, ctx), node.vals))
1770+
return GeneratedPyAST(
1771+
node=ast.Dict(keys=list(keys), values=list(vals)),
1772+
dependencies=list(chain(key_deps, val_deps)),
1773+
)
1774+
1775+
1776+
@_with_ast_loc
1777+
def _py_list_to_py_ast(ctx: GeneratorContext, node: PyList) -> GeneratedPyAST:
1778+
assert node.op == NodeOp.PY_LIST
1779+
1780+
elem_deps, elems = _chain_py_ast(*map(partial(gen_py_ast, ctx), node.items))
1781+
return GeneratedPyAST(
1782+
node=ast.List(elts=list(elems), ctx=ast.Load()), dependencies=list(elem_deps)
1783+
)
1784+
1785+
1786+
@_with_ast_loc
1787+
def _py_set_to_py_ast(ctx: GeneratorContext, node: PySet) -> GeneratedPyAST:
1788+
assert node.op == NodeOp.PY_SET
1789+
1790+
elem_deps, elems = _chain_py_ast(*map(partial(gen_py_ast, ctx), node.items))
1791+
return GeneratedPyAST(node=ast.Set(elts=list(elems)), dependencies=list(elem_deps))
1792+
1793+
1794+
@_with_ast_loc
1795+
def _py_tuple_to_py_ast(ctx: GeneratorContext, node: PyTuple) -> GeneratedPyAST:
1796+
assert node.op == NodeOp.PY_TUPLE
1797+
1798+
elem_deps, elems = _chain_py_ast(*map(partial(gen_py_ast, ctx), node.items))
1799+
return GeneratedPyAST(
1800+
node=ast.Tuple(elts=list(elems), ctx=ast.Load()), dependencies=list(elem_deps)
1801+
)
1802+
1803+
17551804
############
17561805
# With Meta
17571806
############
@@ -1871,6 +1920,34 @@ def _uuid_to_py_ast(_: GeneratorContext, form: uuid.UUID) -> ast.AST:
18711920
return ast.Call(func=_NEW_UUID_FN_NAME, args=[ast.Str(str(form))], keywords=[])
18721921

18731922

1923+
def _const_py_dict_to_py_ast(ctx: GeneratorContext, node: dict) -> GeneratedPyAST:
1924+
key_deps, keys = _chain_py_ast(*_collection_literal_to_py_ast(ctx, node.keys()))
1925+
val_deps, vals = _chain_py_ast(*_collection_literal_to_py_ast(ctx, node.values()))
1926+
return GeneratedPyAST(
1927+
node=ast.Dict(keys=list(keys), values=list(vals)),
1928+
dependencies=list(chain(key_deps, val_deps)),
1929+
)
1930+
1931+
1932+
def _const_py_list_to_py_ast(ctx: GeneratorContext, node: list) -> GeneratedPyAST:
1933+
elem_deps, elems = _chain_py_ast(*_collection_literal_to_py_ast(ctx, node))
1934+
return GeneratedPyAST(
1935+
node=ast.List(elts=list(elems), ctx=ast.Load()), dependencies=list(elem_deps)
1936+
)
1937+
1938+
1939+
def _const_py_set_to_py_ast(ctx: GeneratorContext, node: set) -> GeneratedPyAST:
1940+
elem_deps, elems = _chain_py_ast(*_collection_literal_to_py_ast(ctx, node))
1941+
return GeneratedPyAST(node=ast.Set(elts=list(elems)), dependencies=list(elem_deps))
1942+
1943+
1944+
def _const_py_tuple_to_py_ast(ctx: GeneratorContext, node: tuple) -> GeneratedPyAST:
1945+
elem_deps, elems = _chain_py_ast(*_collection_literal_to_py_ast(ctx, node))
1946+
return GeneratedPyAST(
1947+
node=ast.Tuple(elts=list(elems), ctx=ast.Load()), dependencies=list(elem_deps)
1948+
)
1949+
1950+
18741951
def _const_map_to_py_ast(ctx: GeneratorContext, form: lmap.Map) -> GeneratedPyAST:
18751952
key_deps, keys = _chain_py_ast(*_collection_literal_to_py_ast(ctx, form.keys()))
18761953
val_deps, vals = _chain_py_ast(*_collection_literal_to_py_ast(ctx, form.values()))
@@ -1951,17 +2028,21 @@ def _const_vec_to_py_ast(ctx: GeneratorContext, form: vec.Vector) -> GeneratedPy
19512028
complex: _num_to_py_ast,
19522029
datetime: _inst_to_py_ast,
19532030
Decimal: _decimal_to_py_ast,
2031+
dict: _const_py_dict_to_py_ast,
19542032
float: _num_to_py_ast,
19552033
Fraction: _fraction_to_py_ast,
19562034
int: _num_to_py_ast,
19572035
kw.Keyword: _kw_to_py_ast,
2036+
list: _const_py_list_to_py_ast,
19582037
llist.List: _const_seq_to_py_ast,
19592038
lmap.Map: _const_map_to_py_ast,
19602039
lset.Set: _const_set_to_py_ast,
19612040
lseq.Seq: _const_seq_to_py_ast,
19622041
type(re.compile("")): _regex_to_py_ast,
2042+
set: _const_py_set_to_py_ast,
19632043
sym.Symbol: _const_sym_to_py_ast,
19642044
str: _str_to_py_ast,
2045+
tuple: _const_py_tuple_to_py_ast,
19652046
type(None): _name_const_to_py_ast,
19662047
uuid.UUID: _uuid_to_py_ast,
19672048
vec.Vector: _const_vec_to_py_ast,
@@ -2008,6 +2089,10 @@ def _collection_literal_to_py_ast(
20082089
ConstType.STRING: _str_to_py_ast,
20092090
ConstType.NIL: _name_const_to_py_ast,
20102091
ConstType.UUID: _uuid_to_py_ast,
2092+
ConstType.PY_DICT: _const_py_dict_to_py_ast,
2093+
ConstType.PY_LIST: _const_py_list_to_py_ast,
2094+
ConstType.PY_SET: _const_py_set_to_py_ast,
2095+
ConstType.PY_TUPLE: _const_py_tuple_to_py_ast,
20112096
ConstType.VECTOR: _const_vec_to_py_ast,
20122097
}
20132098

@@ -2044,6 +2129,10 @@ def _const_node_to_py_ast(ctx: GeneratorContext, lisp_ast: Const) -> GeneratedPy
20442129
NodeOp.MAP: _map_to_py_ast,
20452130
NodeOp.MAYBE_CLASS: _maybe_class_to_py_ast,
20462131
NodeOp.MAYBE_HOST_FORM: _maybe_host_form_to_py_ast,
2132+
NodeOp.PY_DICT: _py_dict_to_py_ast,
2133+
NodeOp.PY_LIST: _py_list_to_py_ast,
2134+
NodeOp.PY_SET: _py_set_to_py_ast,
2135+
NodeOp.PY_TUPLE: _py_tuple_to_py_ast,
20472136
NodeOp.QUOTE: _quote_to_py_ast,
20482137
NodeOp.RECUR: _recur_to_py_ast,
20492138
NodeOp.SET: _set_to_py_ast,

src/basilisp/lang/compiler/nodes.py

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@
1515
import attr
1616

1717
import basilisp.lang.keyword as kw
18-
import basilisp.lang.list as llist
1918
import basilisp.lang.map as lmap
20-
import basilisp.lang.seq as lseq
2119
import basilisp.lang.set as lset
2220
import basilisp.lang.symbol as sym
2321
import basilisp.lang.vector as vec
2422
from basilisp.lang.runtime import Namespace, Var
25-
from basilisp.lang.typing import LispForm
23+
from basilisp.lang.typing import LispForm, ReaderForm as ReaderLispForm, SpecialForm
2624
from basilisp.lang.util import munge
2725

2826
BODY = kw.keyword("body")
@@ -71,6 +69,10 @@ class NodeOp(Enum):
7169
MAP = kw.keyword("map")
7270
MAYBE_CLASS = kw.keyword("maybe-class")
7371
MAYBE_HOST_FORM = kw.keyword("maybe-host-form")
72+
PY_DICT = kw.keyword("py-dict")
73+
PY_LIST = kw.keyword("py-list")
74+
PY_SET = kw.keyword("py-set")
75+
PY_TUPLE = kw.keyword("py-tuple")
7476
QUOTE = kw.keyword("quote")
7577
RECUR = kw.keyword("recur")
7678
SET = kw.keyword("set")
@@ -204,12 +206,14 @@ class ConstType(Enum):
204206
CLASS = kw.keyword("class")
205207
INST = kw.keyword("inst")
206208
UUID = kw.keyword("uuid")
209+
PY_DICT = kw.keyword("py-dict")
210+
PY_LIST = kw.keyword("py-list")
211+
PY_SET = kw.keyword("py-set")
212+
PY_TUPLE = kw.keyword("py-tuple")
207213
UNKNOWN = kw.keyword("unknown")
208214

209215

210216
NodeMeta = Union[None, "Const", "Map"]
211-
ReaderLispForm = Union[LispForm, lseq.Seq]
212-
SpecialForm = Union[llist.List, lseq.Seq]
213217
LoopID = str
214218

215219

@@ -491,6 +495,51 @@ class MaybeHostForm(Node[sym.Symbol]):
491495
raw_forms: Collection[LispForm] = vec.Vector.empty()
492496

493497

498+
@attr.s(auto_attribs=True, cmp=False, frozen=True, slots=True)
499+
class PyDict(Node[dict]):
500+
form: dict
501+
keys: Iterable[Node]
502+
vals: Iterable[Node]
503+
env: NodeEnv
504+
children: Collection[kw.Keyword] = vec.v(KEYS, VALS)
505+
op: NodeOp = NodeOp.PY_DICT
506+
top_level: bool = False
507+
raw_forms: Collection[LispForm] = vec.Vector.empty()
508+
509+
510+
@attr.s(auto_attribs=True, cmp=False, frozen=True, slots=True)
511+
class PyList(Node[list]):
512+
form: list
513+
items: Iterable[Node]
514+
env: NodeEnv
515+
children: Collection[kw.Keyword] = vec.v(ITEMS)
516+
op: NodeOp = NodeOp.PY_LIST
517+
top_level: bool = False
518+
raw_forms: Collection[LispForm] = vec.Vector.empty()
519+
520+
521+
@attr.s(auto_attribs=True, cmp=False, frozen=True, slots=True)
522+
class PySet(Node[Union[frozenset, set]]):
523+
form: Union[frozenset, set]
524+
items: Iterable[Node]
525+
env: NodeEnv
526+
children: Collection[kw.Keyword] = vec.v(ITEMS)
527+
op: NodeOp = NodeOp.PY_SET
528+
top_level: bool = False
529+
raw_forms: Collection[LispForm] = vec.Vector.empty()
530+
531+
532+
@attr.s(auto_attribs=True, frozen=True, slots=True)
533+
class PyTuple(Node[tuple]):
534+
form: tuple
535+
items: Iterable[Node]
536+
env: NodeEnv
537+
children: Collection[kw.Keyword] = vec.v(ITEMS)
538+
op: NodeOp = NodeOp.PY_TUPLE
539+
top_level: bool = False
540+
raw_forms: Collection[LispForm] = vec.Vector.empty()
541+
542+
494543
@attr.s(auto_attribs=True, frozen=True, slots=True)
495544
class Quote(Node[SpecialForm]):
496545
form: SpecialForm
@@ -617,6 +666,10 @@ class WithMeta(Node[LispForm]):
617666
Map,
618667
MaybeClass,
619668
MaybeHostForm,
669+
PyDict,
670+
PyList,
671+
PySet,
672+
PyTuple,
620673
Quote,
621674
Set,
622675
SetBang,

0 commit comments

Comments
 (0)