1- // vm/handlers/attr.rs
2-
31use super :: * ;
42use crate :: modules:: vm:: types:: BuiltinMethodId ;
53
4+ type AttrRow = ( & ' static str , & ' static str , BuiltinMethodId ) ;
5+
6+ // Table of built-in methods organized by (type, attribute_name). It must be kept in lexicographical order to allow binary search.
7+ static ATTR_TABLE : & [ AttrRow ] = & [
8+ ( "dict" , "get" , BuiltinMethodId :: DictGet ) ,
9+ ( "dict" , "items" , BuiltinMethodId :: DictItems ) ,
10+ ( "dict" , "keys" , BuiltinMethodId :: DictKeys ) ,
11+ ( "dict" , "pop" , BuiltinMethodId :: DictPop ) ,
12+ ( "dict" , "setdefault" , BuiltinMethodId :: DictSetDefault ) ,
13+ ( "dict" , "update" , BuiltinMethodId :: DictUpdate ) ,
14+ ( "dict" , "values" , BuiltinMethodId :: DictValues ) ,
15+ ( "list" , "append" , BuiltinMethodId :: ListAppend ) ,
16+ ( "list" , "clear" , BuiltinMethodId :: ListClear ) ,
17+ ( "list" , "copy" , BuiltinMethodId :: ListCopy ) ,
18+ ( "list" , "count" , BuiltinMethodId :: ListCount ) ,
19+ ( "list" , "extend" , BuiltinMethodId :: ListExtend ) ,
20+ ( "list" , "index" , BuiltinMethodId :: ListIndex ) ,
21+ ( "list" , "insert" , BuiltinMethodId :: ListInsert ) ,
22+ ( "list" , "pop" , BuiltinMethodId :: ListPop ) ,
23+ ( "list" , "remove" , BuiltinMethodId :: ListRemove ) ,
24+ ( "list" , "reverse" , BuiltinMethodId :: ListReverse ) ,
25+ ( "list" , "sort" , BuiltinMethodId :: ListSort ) ,
26+ ( "str" , "capitalize" , BuiltinMethodId :: StrCapitalize ) ,
27+ ( "str" , "center" , BuiltinMethodId :: StrCenter ) ,
28+ ( "str" , "count" , BuiltinMethodId :: StrCount ) ,
29+ ( "str" , "endswith" , BuiltinMethodId :: StrEndswith ) ,
30+ ( "str" , "find" , BuiltinMethodId :: StrFind ) ,
31+ ( "str" , "isalnum" , BuiltinMethodId :: StrIsAlnum ) ,
32+ ( "str" , "isalpha" , BuiltinMethodId :: StrIsAlpha ) ,
33+ ( "str" , "isdigit" , BuiltinMethodId :: StrIsDigit ) ,
34+ ( "str" , "join" , BuiltinMethodId :: StrJoin ) ,
35+ ( "str" , "lower" , BuiltinMethodId :: StrLower ) ,
36+ ( "str" , "lstrip" , BuiltinMethodId :: StrLstrip ) ,
37+ ( "str" , "replace" , BuiltinMethodId :: StrReplace ) ,
38+ ( "str" , "rstrip" , BuiltinMethodId :: StrRstrip ) ,
39+ ( "str" , "split" , BuiltinMethodId :: StrSplit ) ,
40+ ( "str" , "startswith" , BuiltinMethodId :: StrStartswith ) ,
41+ ( "str" , "strip" , BuiltinMethodId :: StrStrip ) ,
42+ ( "str" , "title" , BuiltinMethodId :: StrTitle ) ,
43+ ( "str" , "upper" , BuiltinMethodId :: StrUpper ) ,
44+ ( "str" , "zfill" , BuiltinMethodId :: StrZfill ) ,
45+ ] ;
46+
47+ #[ inline]
48+ fn lookup_attr ( ty : & str , attr : & str ) -> Option < BuiltinMethodId > {
49+ ATTR_TABLE . binary_search_by ( |& ( t, a, _) | { t. cmp ( ty) . then_with ( || a. cmp ( attr) ) } )
50+ . ok ( )
51+ . map ( |i| ATTR_TABLE [ i] . 2 )
52+ }
53+
654impl < ' a > VM < ' a > {
7- /// Resolves `obj.name` for builtin types. Pops `obj`, pushes a bound
8- /// method or returns Err if the attribute is unknown for the type.
955 pub ( crate ) fn handle_load_attr ( & mut self , name_idx : u16 , chunk : & SSAChunk ) -> Result < ( ) , VmErr > {
10- let name = chunk. names . get ( name_idx as usize )
11- . ok_or ( VmErr :: Runtime ( "LoadAttr: bad name index" ) ) ? ;
56+ let name = chunk. names . get ( name_idx as usize ) . ok_or ( VmErr :: Runtime ( "LoadAttr: bad name index" ) ) ? ;
57+
1258 let obj = self . pop ( ) ?;
59+ let ty = self . type_name ( obj) ;
1360
14- let method_id = match ( self . type_name ( obj) , name. as_str ( ) ) {
15- ( "list" , "append" ) => BuiltinMethodId :: ListAppend ,
16- ( "dict" , "keys" ) => BuiltinMethodId :: DictKeys ,
17- ( "dict" , "values" ) => BuiltinMethodId :: DictValues ,
18- ( "dict" , "items" ) => BuiltinMethodId :: DictItems ,
19- ( "str" , "upper" ) => BuiltinMethodId :: StrUpper ,
20- ( "str" , "lower" ) => BuiltinMethodId :: StrLower ,
21- ( "str" , "strip" ) => BuiltinMethodId :: StrStrip ,
22- ( "str" , "split" ) => BuiltinMethodId :: StrSplit ,
23- ( "str" , "join" ) => BuiltinMethodId :: StrJoin ,
24- ( "str" , "replace" ) => BuiltinMethodId :: StrReplace ,
25- ( "str" , "startswith" ) => BuiltinMethodId :: StrStartswith ,
26- ( "str" , "endswith" ) => BuiltinMethodId :: StrEndswith ,
27- ( "str" , "find" ) => BuiltinMethodId :: StrFind ,
28- ( "str" , "count" ) => BuiltinMethodId :: StrCount ,
29- ( "list" , "sort" ) => BuiltinMethodId :: ListSort ,
30- ( "list" , "reverse" ) => BuiltinMethodId :: ListReverse ,
31- ( "list" , "pop" ) => BuiltinMethodId :: ListPop ,
32- ( "list" , "insert" ) => BuiltinMethodId :: ListInsert ,
33- ( "list" , "remove" ) => BuiltinMethodId :: ListRemove ,
34- ( "list" , "index" ) => BuiltinMethodId :: ListIndex ,
35- ( "list" , "count" ) => BuiltinMethodId :: ListCount ,
36- ( "dict" , "get" ) => BuiltinMethodId :: DictGet ,
37- ( "dict" , "update" ) => BuiltinMethodId :: DictUpdate ,
38- ( "dict" , "pop" ) => BuiltinMethodId :: DictPop ,
39- ( "dict" , "setdefault" ) => BuiltinMethodId :: DictSetDefault ,
40- ( "str" , "lstrip" ) => BuiltinMethodId :: StrLstrip ,
41- ( "str" , "rstrip" ) => BuiltinMethodId :: StrRstrip ,
42- ( "str" , "isdigit" ) => BuiltinMethodId :: StrIsDigit ,
43- ( "str" , "isalpha" ) => BuiltinMethodId :: StrIsAlpha ,
44- ( "str" , "isalnum" ) => BuiltinMethodId :: StrIsAlnum ,
45- ( "str" , "capitalize" ) => BuiltinMethodId :: StrCapitalize ,
46- ( "str" , "title" ) => BuiltinMethodId :: StrTitle ,
47- ( "str" , "center" ) => BuiltinMethodId :: StrCenter ,
48- ( "str" , "zfill" ) => BuiltinMethodId :: StrZfill ,
49- ( "list" , "extend" ) => BuiltinMethodId :: ListExtend ,
50- ( "list" , "clear" ) => BuiltinMethodId :: ListClear ,
51- ( "list" , "copy" ) => BuiltinMethodId :: ListCopy ,
52- ( ty, attr) => {
53- return Err ( attr_not_found ( ty, attr) ) ;
54- }
55- } ;
61+ // Binary search using O(log n)
62+ let method_id = lookup_attr ( ty, name. as_str ( ) ) . ok_or_else ( || attr_not_found ( ty, name. as_str ( ) ) ) ?;
5663
5764 let bound = self . heap . alloc ( HeapObj :: BoundMethod ( obj, method_id) ) ?;
5865 self . push ( bound) ;
66+
5967 Ok ( ( ) )
6068 }
6169}
6270
6371#[ cold]
6472fn attr_not_found ( ty : & str , attr : & str ) -> VmErr {
65- // Static message keeps VmErr::Type's &'static str contract.
66- let _ = ( ty, attr) ; // params kept for future expansion
73+ let _ = ( ty, attr) ;
6774 VmErr :: Type ( "'object' has no attribute" )
6875}
0 commit comments