7
7
import functools
8
8
import hashlib
9
9
import logging
10
+ import pickle # nosec B403
10
11
import re
11
12
import uuid
12
13
from collections .abc import Collection , Iterable , Mapping , MutableMapping
95
96
ast_ClassDef ,
96
97
ast_FunctionDef ,
97
98
)
98
- from basilisp .lang .interfaces import IMeta , IRecord , ISeq , ISeqable , IType
99
+ from basilisp .lang .interfaces import IMeta , ISeq
99
100
from basilisp .lang .runtime import CORE_NS
100
101
from basilisp .lang .runtime import NS_VAR_NAME as LISP_NS_VAR
101
102
from basilisp .lang .runtime import BasilispModule , Var
@@ -764,6 +765,7 @@ def _var_ns_as_python_sym(name: str) -> str:
764
765
_ATTR_CLASS_DECORATOR_NAME = _load_attr (f"{ _ATTR_ALIAS } .define" )
765
766
_ATTR_FROZEN_DECORATOR_NAME = _load_attr (f"{ _ATTR_ALIAS } .frozen" )
766
767
_ATTRIB_FIELD_FN_NAME = _load_attr (f"{ _ATTR_ALIAS } .field" )
768
+ _BASILISP_LOAD_CONSTANT_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._load_constant" )
767
769
_COERCE_SEQ_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } .to_seq" )
768
770
_BASILISP_FN_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._basilisp_fn" )
769
771
_FN_WITH_ATTRS_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._with_attrs" )
@@ -3559,9 +3561,24 @@ def _const_val_to_py_ast(
3559
3561
structures need to call into this function to generate Python AST nodes for
3560
3562
nested elements. For top-level :const Lisp AST nodes, see
3561
3563
`_const_node_to_py_ast`."""
3562
- raise ctx .GeneratorException (
3563
- f"No constant handler is defined for type { type (form )} "
3564
- )
3564
+ try :
3565
+ serialized = pickle .dumps (form )
3566
+ except (pickle .PicklingError , RecursionError ) as e :
3567
+ # For types without custom "constant" handling code, we defer to pickle
3568
+ # to generate a representation that can be reloaded from the generated
3569
+ # byte code. There are a few cases where that may not be possible for one
3570
+ # reason or another, in which case we'll fail here.
3571
+ raise ctx .GeneratorException (
3572
+ f"Unable to emit bytecode for generating a constant { type (form )} "
3573
+ ) from e
3574
+ else :
3575
+ return GeneratedPyAST (
3576
+ node = ast .Call (
3577
+ func = _BASILISP_LOAD_CONSTANT_NAME ,
3578
+ args = [ast .Constant (value = serialized )],
3579
+ keywords = [],
3580
+ ),
3581
+ )
3565
3582
3566
3583
3567
3584
def _collection_literal_to_py_ast (
@@ -3777,54 +3794,6 @@ def _const_set_to_py_ast(
3777
3794
)
3778
3795
3779
3796
3780
- @_const_val_to_py_ast .register (IRecord )
3781
- def _const_record_to_py_ast (
3782
- form : IRecord , ctx : GeneratorContext
3783
- ) -> GeneratedPyAST [ast .expr ]:
3784
- assert isinstance (form , IRecord ) and isinstance (
3785
- form , ISeqable
3786
- ), "IRecord types should also be ISeq"
3787
-
3788
- tp = type (form )
3789
- assert hasattr (tp , "create" ) and callable (
3790
- tp .create
3791
- ), "IRecord and IType must declare a .create class method"
3792
-
3793
- form_seq = runtime .to_seq (form )
3794
- assert form_seq is not None , "IRecord types must be iterable"
3795
-
3796
- # pylint: disable=no-member
3797
- keys : list [Optional [ast .expr ]] = []
3798
- vals : list [ast .expr ] = []
3799
- vals_deps : list [PyASTNode ] = []
3800
- for k , v in form_seq :
3801
- assert isinstance (k , kw .Keyword ), "Record key in seq must be keyword"
3802
- key_nodes = _kw_to_py_ast (k , ctx )
3803
- keys .append (key_nodes .node )
3804
- assert (
3805
- not key_nodes .dependencies
3806
- ), "Simple AST generators must emit no dependencies"
3807
-
3808
- val_nodes = _const_val_to_py_ast (v , ctx )
3809
- vals .append (val_nodes .node )
3810
- vals_deps .extend (val_nodes .dependencies )
3811
-
3812
- return GeneratedPyAST (
3813
- node = ast .Call (
3814
- func = _load_attr (f"{ tp .__qualname__ } .create" ),
3815
- args = [
3816
- ast .Call (
3817
- func = _NEW_MAP_FN_NAME ,
3818
- args = [ast .Dict (keys = keys , values = vals )],
3819
- keywords = [],
3820
- )
3821
- ],
3822
- keywords = [],
3823
- ),
3824
- dependencies = vals_deps ,
3825
- )
3826
-
3827
-
3828
3797
@_const_val_to_py_ast .register (llist .PersistentList )
3829
3798
@_const_val_to_py_ast .register (ISeq )
3830
3799
def _const_seq_to_py_ast (
@@ -3849,25 +3818,6 @@ def _const_seq_to_py_ast(
3849
3818
)
3850
3819
3851
3820
3852
- @_const_val_to_py_ast .register (IType )
3853
- def _const_type_to_py_ast (
3854
- form : IType , ctx : GeneratorContext
3855
- ) -> GeneratedPyAST [ast .expr ]:
3856
- tp = type (form )
3857
-
3858
- ctor_args = []
3859
- ctor_arg_deps : list [PyASTNode ] = []
3860
- for field in attr .fields (tp ): # type: ignore[arg-type, misc, unused-ignore]
3861
- field_nodes = _const_val_to_py_ast (getattr (form , field .name , None ), ctx )
3862
- ctor_args .append (field_nodes .node )
3863
- ctor_args .extend (field_nodes .dependencies ) # type: ignore[arg-type]
3864
-
3865
- return GeneratedPyAST (
3866
- node = ast .Call (func = _load_attr (tp .__qualname__ ), args = ctor_args , keywords = []),
3867
- dependencies = ctor_arg_deps ,
3868
- )
3869
-
3870
-
3871
3821
@_const_val_to_py_ast .register (vec .PersistentVector )
3872
3822
def _const_vec_to_py_ast (
3873
3823
form : vec .PersistentVector , ctx : GeneratorContext
0 commit comments