77import functools
88import hashlib
99import logging
10+ import pickle # nosec B403
1011import re
1112import uuid
1213from collections .abc import Collection , Iterable , Mapping , MutableMapping
9596 ast_ClassDef ,
9697 ast_FunctionDef ,
9798)
98- from basilisp .lang .interfaces import IMeta , IRecord , ISeq , ISeqable , IType
99+ from basilisp .lang .interfaces import IMeta , ISeq
99100from basilisp .lang .runtime import CORE_NS
100101from basilisp .lang .runtime import NS_VAR_NAME as LISP_NS_VAR
101102from basilisp .lang .runtime import BasilispModule , Var
@@ -764,6 +765,7 @@ def _var_ns_as_python_sym(name: str) -> str:
764765_ATTR_CLASS_DECORATOR_NAME = _load_attr (f"{ _ATTR_ALIAS } .define" )
765766_ATTR_FROZEN_DECORATOR_NAME = _load_attr (f"{ _ATTR_ALIAS } .frozen" )
766767_ATTRIB_FIELD_FN_NAME = _load_attr (f"{ _ATTR_ALIAS } .field" )
768+ _BASILISP_LOAD_CONSTANT_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._load_constant" )
767769_COERCE_SEQ_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } .to_seq" )
768770_BASILISP_FN_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._basilisp_fn" )
769771_FN_WITH_ATTRS_FN_NAME = _load_attr (f"{ _RUNTIME_ALIAS } ._with_attrs" )
@@ -3559,9 +3561,24 @@ def _const_val_to_py_ast(
35593561 structures need to call into this function to generate Python AST nodes for
35603562 nested elements. For top-level :const Lisp AST nodes, see
35613563 `_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+ )
35653582
35663583
35673584def _collection_literal_to_py_ast (
@@ -3777,54 +3794,6 @@ def _const_set_to_py_ast(
37773794 )
37783795
37793796
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-
38283797@_const_val_to_py_ast .register (llist .PersistentList )
38293798@_const_val_to_py_ast .register (ISeq )
38303799def _const_seq_to_py_ast (
@@ -3849,25 +3818,6 @@ def _const_seq_to_py_ast(
38493818 )
38503819
38513820
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-
38713821@_const_val_to_py_ast .register (vec .PersistentVector )
38723822def _const_vec_to_py_ast (
38733823 form : vec .PersistentVector , ctx : GeneratorContext
0 commit comments