22// comparison key derived from user identity.
33#pragma warning disable CA1308
44
5+ using System . Collections . Concurrent ;
56using System . Globalization ;
67using System . Numerics ;
78using System . Text ;
@@ -12,6 +13,147 @@ namespace DotPython.Runtime.Managed.Execution;
1213/// <summary>Built-in type objects usable as constructors and isinstance class info.</summary>
1314internal static class PythonBuiltinTypes
1415{
16+ private static readonly ConcurrentDictionary < string , PythonBuiltinTypeValue > OpaqueTypes = new (
17+ StringComparer . Ordinal
18+ ) ;
19+ private static readonly ConcurrentDictionary < string , PythonBuiltinTypeValue > ConstructorTypes =
20+ new ( StringComparer . Ordinal ) ;
21+ private static readonly ConcurrentDictionary < string , PythonExceptionTypeValue > ExceptionTypes =
22+ new ( StringComparer . Ordinal ) ;
23+
24+ internal static readonly PythonBuiltinTypeValue Type = new (
25+ "type" ,
26+ ( arguments , span ) => UserObjectProtocols . Dispatcher ! . ConstructType ( arguments , span )
27+ ) ;
28+
29+ internal static PythonBuiltinTypeValue GetConstructorType (
30+ PythonBuiltinFunctionValue function
31+ ) =>
32+ ConstructorTypes . GetOrAdd (
33+ function . Name ,
34+ static ( name , hasKeywords ) =>
35+ new PythonBuiltinTypeValue (
36+ name ,
37+ ( arguments , span ) =>
38+ UserObjectProtocols
39+ . Dispatcher ! . GetBuiltinConstructor ( name )
40+ . Invoke ( arguments , span ) ,
41+ hasKeywords
42+ ? ( arguments , names , values , span ) =>
43+ UserObjectProtocols
44+ . Dispatcher ! . GetBuiltinConstructor ( name )
45+ . InvokeWithKeywords ! ( arguments , names , values , span )
46+ : null
47+ ) ,
48+ function . InvokeWithKeywords is not null
49+ ) ;
50+
51+ internal static PythonExceptionTypeValue GetExceptionType ( string name ) =>
52+ ExceptionTypes . GetOrAdd ( name , static key => new PythonExceptionTypeValue ( key ) ) ;
53+
54+ internal static PythonTupleValue GetBases ( PythonValue type ) =>
55+ type switch
56+ {
57+ PythonBuiltinTypeValue builtin
58+ when ReferenceEquals ( builtin , PythonBuiltinFunctions . Object ) => new ( [ ] ) ,
59+ PythonBuiltinTypeValue builtin when ReferenceEquals ( builtin , Bool ) => new ( [ Int ] ) ,
60+ PythonBuiltinTypeValue => new ( [ PythonBuiltinFunctions . Object ] ) ,
61+ PythonManagedTypeValue managed
62+ when ReferenceEquals ( managed , PythonBuiltinFunctions . ObjectType ) => new ( [ ] ) ,
63+ PythonManagedTypeValue { DeclaredBases : { Count : > 0 } declared } => new ( [ .. declared ] ) ,
64+ PythonManagedTypeValue { Bases . Count : > 0 } managed => new ( [ .. managed . Bases ] ) ,
65+ PythonManagedTypeValue { ExceptionBaseName : { } baseName } => new ( [
66+ GetExceptionType ( baseName ) ,
67+ ] ) ,
68+ PythonManagedTypeValue => new ( [ PythonBuiltinFunctions . Object ] ) ,
69+ PythonExceptionTypeValue exception
70+ when PythonVirtualMachine . GetBuiltinExceptionBase ( exception . Name ) is { } baseName =>
71+ new ( [ GetExceptionType ( baseName ) ] ) ,
72+ PythonExceptionTypeValue => new ( [ PythonBuiltinFunctions . Object ] ) ,
73+ _ => throw new ArgumentException ( "Expected a Python type." , nameof ( type ) ) ,
74+ } ;
75+
76+ internal static PythonTupleValue GetMro ( PythonValue type )
77+ {
78+ if (
79+ type is PythonManagedTypeValue managed
80+ && ! ReferenceEquals ( managed , PythonBuiltinFunctions . ObjectType )
81+ )
82+ {
83+ var entries = managed . Mro . Cast < PythonValue > ( ) . ToList ( ) ;
84+ var oldest = managed . Mro [ ^ 1 ] ;
85+ if ( oldest . ExceptionBaseName is { } exceptionBase )
86+ {
87+ entries . AddRange ( GetMro ( GetExceptionType ( exceptionBase ) ) . Elements ) ;
88+ }
89+ else
90+ {
91+ entries . Add ( PythonBuiltinFunctions . Object ) ;
92+ }
93+ return new ( [ .. entries ] ) ;
94+ }
95+ if ( ReferenceEquals ( type , PythonBuiltinFunctions . ObjectType ) )
96+ {
97+ type = PythonBuiltinFunctions . Object ;
98+ }
99+ var bases = GetBases ( type ) . Elements ;
100+ return bases . Length == 0 ? new ( [ type] ) : new ( [ type, .. GetMro ( bases [ 0 ] ) . Elements ] ) ;
101+ }
102+
103+ internal static PythonValue GetRuntimeType ( PythonValue value ) =>
104+ value switch
105+ {
106+ PythonBuiltinTypeValue or PythonManagedTypeValue or PythonExceptionTypeValue => Type ,
107+ PythonTruthValue => Bool ,
108+ PythonWholeNumberValue => Int ,
109+ PythonFloatingPointValue => Float ,
110+ PythonComplexValue => PythonBuiltinFunctions . Complex ,
111+ PythonTextValue => Str ,
112+ PythonByteSequenceValue => Bytes ,
113+ PythonTemplateValue => PythonStandardModules . TemplateType ,
114+ PythonInterpolationValue => PythonStandardModules . InterpolationType ,
115+ PythonListValue => List ,
116+ PythonTupleValue => Tuple ,
117+ PythonDictionaryValue => Dict ,
118+ PythonMappingProxyValue => PythonMappingProxies . Type ,
119+ PythonSetValue { IsFrozen : true } => Frozenset ,
120+ PythonSetValue => Set ,
121+ PythonManagedObjectValue instance
122+ when ReferenceEquals ( instance . Type , PythonBuiltinFunctions . ObjectType ) =>
123+ PythonBuiltinFunctions . Object ,
124+ PythonManagedObjectValue instance => instance . Type ,
125+ PythonExceptionValue { ManagedType : { } managedType } => managedType ,
126+ PythonExceptionValue exception => GetExceptionType ( exception . TypeName ) ,
127+ _ => ConstructorTypes . TryGetValue ( GetRuntimeTypeName ( value ) , out var constructorType )
128+ ? constructorType
129+ : CreateOpaque ( GetRuntimeTypeName ( value ) ) ,
130+ } ;
131+
132+ internal static string GetRuntimeTypeName ( PythonValue value ) =>
133+ value switch
134+ {
135+ PythonBuiltinTypeValue => "type" ,
136+ PythonSuperProxyValue => "super" ,
137+ PythonIteratorValue { Iterable : PythonEnumerateSourceValue } => "enumerate" ,
138+ PythonIteratorValue { Iterable : PythonZipSourceValue } => "zip" ,
139+ PythonIteratorValue { Iterable : PythonMapSourceValue } => "map" ,
140+ PythonIteratorValue { Iterable : PythonFilterSourceValue } => "filter" ,
141+ PythonIteratorValue { Iterable : PythonListValue } => "list_iterator" ,
142+ PythonIteratorValue { Iterable : PythonTupleValue } => "tuple_iterator" ,
143+ PythonIteratorValue { Iterable : PythonTextValue text }
144+ when text . Value . All ( character => character <= 127 ) => "str_ascii_iterator" ,
145+ PythonIteratorValue { Iterable : PythonTextValue } => "str_iterator" ,
146+ PythonIteratorValue { Iterable : PythonRangeValue } => "range_iterator" ,
147+ PythonIteratorValue { Iterable : PythonDictionaryValue } => "dict_keyiterator" ,
148+ PythonIteratorValue { Iterable : PythonDictionaryViewValue { Kind : "dict_keys" } } =>
149+ "dict_keyiterator" ,
150+ PythonIteratorValue { Iterable : PythonDictionaryViewValue { Kind : "dict_values" } } =>
151+ "dict_valueiterator" ,
152+ PythonIteratorValue { Iterable : PythonDictionaryViewValue { Kind : "dict_items" } } =>
153+ "dict_itemiterator" ,
154+ _ => ManagedObjectProtocols . GetTypeName ( value ) ,
155+ } ;
156+
15157 internal static readonly PythonBuiltinTypeValue Bool = new ( "bool" , ConstructBool ) ;
16158 internal static readonly PythonBuiltinTypeValue Bytes = new (
17159 "bytes" ,
@@ -62,14 +204,18 @@ [new PythonTextValue(string.Empty), null, null],
62204 [ Bool , Bytes , Dict , Float , Frozenset , Int , List , Set , Str , Tuple ] ;
63205
64206 internal static PythonBuiltinTypeValue CreateOpaque ( string name ) =>
65- new (
207+ OpaqueTypes . GetOrAdd (
66208 name ,
67- ( _ , span ) =>
68- throw ManagedObjectProtocols . Fault (
69- "DPY4009" ,
70- $ "The type '{ name } ' is not constructible in this runtime slice.",
71- span ,
72- "TypeError"
209+ static key =>
210+ new (
211+ key ,
212+ ( _ , span ) =>
213+ throw ManagedObjectProtocols . Fault (
214+ "DPY4009" ,
215+ $ "The type '{ key } ' is not constructible in this runtime slice.",
216+ span ,
217+ "TypeError"
218+ )
73219 )
74220 ) ;
75221
@@ -90,6 +236,10 @@ internal static bool IsInstance(PythonValue value, PythonBuiltinTypeValue type)
90236 "Template" => value is PythonTemplateValue ,
91237 "Interpolation" => value is PythonInterpolationValue ,
92238 "object" => true ,
239+ "type" => value
240+ is PythonBuiltinTypeValue
241+ or PythonManagedTypeValue
242+ or PythonExceptionTypeValue ,
93243 _ => false ,
94244 } ;
95245
0 commit comments