11from __future__ import annotations
22
33from dataclasses import dataclass
4- from typing import TYPE_CHECKING , NamedTuple
4+ from typing import TYPE_CHECKING
55
66from pyk .kast .inner import KApply
77from pyk .kast .prelude .bytes import bytesToken
88from pyk .kast .prelude .kint import intToken
99
10- from .alloc import Allocation , AllocInfo , Memory , ProvenanceMap
11- from .ty import ArrayT , Bool , EnumT , Int , IntTy , Uint
12- from .value import AggregateValue , BoolValue , IntValue , RangeValue , Value
10+ from .alloc import Allocation , AllocInfo , Memory , ProvenanceEntry , ProvenanceMap
11+ from .ty import ArrayT , Bool , EnumT , Int , IntTy , PtrT , RefT , Uint
12+ from .value import (
13+ NO_METADATA ,
14+ AggregateValue ,
15+ AllocRefValue ,
16+ BoolValue ,
17+ DynamicSize ,
18+ IntValue ,
19+ RangeValue ,
20+ StaticSize ,
21+ Value ,
22+ )
1323
1424if TYPE_CHECKING :
1525 from collections .abc import Mapping
1626
1727 from pyk .kast import KInner
1828
19- from .alloc import AllocId
2029 from .ty import Ty , TypeMetadata , UintTy
30+ from .value import Metadata
2131
2232
2333@dataclass
@@ -47,11 +57,6 @@ def to_kast(self) -> KInner:
4757 )
4858
4959
50- class ProvenanceMapEntry (NamedTuple ):
51- offset : int
52- alloc_id : AllocId
53-
54-
5560def decode_alloc_or_unable (alloc_info : AllocInfo , types : Mapping [Ty , TypeMetadata ]) -> Value :
5661 match alloc_info :
5762 case AllocInfo (
@@ -66,16 +71,52 @@ def decode_alloc_or_unable(alloc_info: AllocInfo, types: Mapping[Ty, TypeMetadat
6671 ),
6772 ):
6873 data = bytes (n or 0 for n in bytez )
74+ type_info = types [ty ]
75+
76+ match ptrs :
77+ case []:
78+ return decode_value_or_unable (data = data , type_info = type_info , types = types )
79+
80+ case [ProvenanceEntry (0 , alloc_id )]:
81+ if (pointee_ty := _pointee_ty (type_info )) is not None : # ensures this is a reference type
82+ pointee_type_info = types [pointee_ty ]
83+ metadata = _metadata (pointee_type_info )
6984
70- if not ptrs : # TODO generalize to lists with at most one entry
71- type_info = types [ty ]
72- return decode_value_or_unable (data = data , type_info = type_info , types = types )
85+ if len (data ) == 8 :
86+ # single slim pointer (assumes usize == u64)
87+ return AllocRefValue (alloc_id = alloc_id , metadata = metadata )
88+
89+ if len (data ) == 16 and metadata == DynamicSize (1 ):
90+ # sufficient data to decode dynamic size (assumes usize == u64)
91+ # expect fat pointer
92+ return AllocRefValue (
93+ alloc_id = alloc_id ,
94+ metadata = DynamicSize (int .from_bytes (data [8 :16 ], byteorder = 'little' , signed = False )),
95+ )
7396
7497 return UnableToDecodeAlloc (data = data , ty = ty )
7598 case _:
7699 raise AssertionError ('Unhandled case' )
77100
78101
102+ def _pointee_ty (type_info : TypeMetadata ) -> Ty | None :
103+ match type_info :
104+ case PtrT (ty ) | RefT (ty ):
105+ return ty
106+ case _:
107+ return None
108+
109+
110+ def _metadata (type_info : TypeMetadata ) -> Metadata :
111+ match type_info :
112+ case ArrayT (length = None ):
113+ return DynamicSize (1 ) # 1 is a placeholder, the actual size is inferred from the slice data
114+ case ArrayT (length = int () as length ):
115+ return StaticSize (length )
116+ case _:
117+ return NO_METADATA
118+
119+
79120def decode_value_or_unable (data : bytes , type_info : TypeMetadata , types : Mapping [Ty , TypeMetadata ]) -> Value :
80121 try :
81122 return decode_value (data = data , type_info = type_info , types = types )
0 commit comments