@@ -9,6 +9,48 @@ use core::cell::RefCell;
99use alloc:: { string:: { String , ToString } , vec:: Vec , vec, rc:: Rc } ;
1010use crate :: modules:: fx:: FxHashSet as HashSet ;
1111
12+ fn i64_to_radix ( n : i64 , radix : u32 , prefix : & str ) -> String {
13+ if n == 0 {
14+ let mut s = String :: with_capacity ( prefix. len ( ) + 1 ) ;
15+ s. push_str ( prefix) ; s. push ( '0' ) ; return s;
16+ }
17+ let neg = n < 0 ;
18+ let mut abs = ( n as i128 ) . unsigned_abs ( ) ;
19+ let mut buf = [ 0u8 ; 64 ] ;
20+ let mut i = buf. len ( ) ;
21+ while abs > 0 {
22+ i -= 1 ;
23+ let d = ( abs % radix as u128 ) as u8 ;
24+ buf[ i] = if d < 10 { b'0' + d } else { b'a' + d - 10 } ;
25+ abs /= radix as u128 ;
26+ }
27+ let mut s = String :: with_capacity ( prefix. len ( ) + buf. len ( ) - i + 1 ) ;
28+ if neg { s. push ( '-' ) ; }
29+ s. push_str ( prefix) ;
30+ s. push_str ( unsafe { core:: str:: from_utf8_unchecked ( & buf[ i..] ) } ) ;
31+ s
32+ }
33+
34+ fn bigint_to_radix ( b : & BigInt , radix : u32 , prefix : & str ) -> String {
35+ let mut out = String :: new ( ) ;
36+ if b. neg { out. push ( '-' ) ; }
37+ out. push_str ( prefix) ;
38+ if b. is_zero ( ) { out. push ( '0' ) ; return out; }
39+
40+ let radix_big = BigInt :: from_i64 ( radix as i64 ) ;
41+ let mut work = b. abs ( ) ;
42+ let mut digits = Vec :: < u8 > :: new ( ) ;
43+ while !work. is_zero ( ) {
44+ let ( q, r) = work. divmod ( & radix_big) . unwrap ( ) ;
45+ let d = r. to_i64_checked ( ) . unwrap ( ) as u8 ;
46+ digits. push ( if d < 10 { b'0' + d } else { b'a' + d - 10 } ) ;
47+ work = q;
48+ }
49+ digits. reverse ( ) ;
50+ out. push_str ( unsafe { core:: str:: from_utf8_unchecked ( & digits) } ) ;
51+ out
52+ }
53+
1254fn normalize_index ( i : i64 , len : usize ) -> usize {
1355 ( if i < 0 { len as i64 + i } else { i } ) as usize
1456}
@@ -596,4 +638,207 @@ impl<'a> VM<'a> {
596638 }
597639 Ok ( ( ) )
598640 }
641+
642+ // ─── Logical reductions ──────────────────────────────────────────
643+
644+ pub fn call_all ( & mut self , op : u16 ) -> Result < ( ) , VmErr > {
645+ if op != 1 { return Err ( cold_type ( "all() takes exactly 1 argument" ) ) ; }
646+ let o = self . pop ( ) ?;
647+ let items = self . extract_iter ( o, true ) ?;
648+ for v in items {
649+ if !self . truthy ( v) {
650+ self . push ( Val :: bool ( false ) ) ;
651+ return Ok ( ( ) ) ;
652+ }
653+ }
654+ self . push ( Val :: bool ( true ) ) ;
655+ Ok ( ( ) )
656+ }
657+
658+ pub fn call_any ( & mut self , op : u16 ) -> Result < ( ) , VmErr > {
659+ if op != 1 { return Err ( cold_type ( "any() takes exactly 1 argument" ) ) ; }
660+ let o = self . pop ( ) ?;
661+ let items = self . extract_iter ( o, true ) ?;
662+ for v in items {
663+ if self . truthy ( v) {
664+ self . push ( Val :: bool ( true ) ) ;
665+ return Ok ( ( ) ) ;
666+ }
667+ }
668+ self . push ( Val :: bool ( false ) ) ;
669+ Ok ( ( ) )
670+ }
671+
672+ // ─── Number formatting ───────────────────────────────────────────
673+
674+ pub fn call_bin ( & mut self ) -> Result < ( ) , VmErr > {
675+ let o = self . pop ( ) ?;
676+ let s = self . int_to_radix_string ( o, 2 , "0b" ) ?;
677+ let v = self . heap . alloc ( HeapObj :: Str ( s) ) ?;
678+ self . push ( v) ; Ok ( ( ) )
679+ }
680+ pub fn call_oct ( & mut self ) -> Result < ( ) , VmErr > {
681+ let o = self . pop ( ) ?;
682+ let s = self . int_to_radix_string ( o, 8 , "0o" ) ?;
683+ let v = self . heap . alloc ( HeapObj :: Str ( s) ) ?;
684+ self . push ( v) ; Ok ( ( ) )
685+ }
686+ pub fn call_hex ( & mut self ) -> Result < ( ) , VmErr > {
687+ let o = self . pop ( ) ?;
688+ let s = self . int_to_radix_string ( o, 16 , "0x" ) ?;
689+ let v = self . heap . alloc ( HeapObj :: Str ( s) ) ?;
690+ self . push ( v) ; Ok ( ( ) )
691+ }
692+
693+ /// Converts int/BigInt to "<prefix><digits>" with optional sign.
694+ fn int_to_radix_string ( & self , v : Val , radix : u32 , prefix : & str ) -> Result < String , VmErr > {
695+ if v. is_int ( ) {
696+ return Ok ( i64_to_radix ( v. as_int ( ) , radix, prefix) ) ;
697+ }
698+ if v. is_heap ( )
699+ && let HeapObj :: BigInt ( b) = self . heap . get ( v) {
700+ return Ok ( bigint_to_radix ( b, radix, prefix) ) ;
701+ }
702+ Err ( cold_type ( "integer required" ) )
703+ }
704+
705+ // ─── Arithmetic ──────────────────────────────────────────────────
706+
707+ pub fn call_divmod ( & mut self ) -> Result < ( ) , VmErr > {
708+ let b = self . pop ( ) ?;
709+ let a = self . pop ( ) ?;
710+ let ( Some ( ba) , Some ( bb) ) = ( self . to_bigint ( a) , self . to_bigint ( b) )
711+ else { return Err ( cold_type ( "divmod() requires integer operands" ) ) ; } ;
712+ let ( q, r) = ba. divmod ( & bb) . ok_or ( VmErr :: ZeroDiv ) ?;
713+ let qv = self . bigint_to_val ( q) ?;
714+ let rv = self . bigint_to_val ( r) ?;
715+ let val = self . heap . alloc ( HeapObj :: Tuple ( vec ! [ qv, rv] ) ) ?;
716+ self . push ( val) ; Ok ( ( ) )
717+ }
718+
719+ pub fn call_pow ( & mut self , op : u16 ) -> Result < ( ) , VmErr > {
720+ let args = self . pop_n ( op as usize ) ?;
721+ match args. len ( ) {
722+ 2 => {
723+ let r = self . pow_2arg ( args[ 0 ] , args[ 1 ] ) ?;
724+ self . push ( r) ;
725+ Ok ( ( ) )
726+ }
727+ 3 => {
728+ // Modular exponentiation: (a ** b) % c
729+ let ( Some ( base) , Some ( modulus) ) =
730+ ( self . to_bigint ( args[ 0 ] ) , self . to_bigint ( args[ 2 ] ) )
731+ else { return Err ( cold_type ( "pow() with 3 args requires integers" ) ) ; } ;
732+ if !args[ 1 ] . is_int ( ) {
733+ return Err ( cold_type ( "pow() with 3 args requires integer exponent" ) ) ;
734+ }
735+ let mut e = args[ 1 ] . as_int ( ) ;
736+ if e < 0 { return Err ( cold_value ( "pow() exponent must be non-negative" ) ) ; }
737+ if modulus. is_zero ( ) { return Err ( VmErr :: ZeroDiv ) ; }
738+
739+ let mut result = BigInt :: from_i64 ( 1 ) ;
740+ let ( _, mut base) = base. divmod ( & modulus) . unwrap ( ) ;
741+ while e > 0 {
742+ if e & 1 == 1 {
743+ let ( _, r) = result. mul ( & base) . divmod ( & modulus) . unwrap ( ) ;
744+ result = r;
745+ }
746+ let ( _, b2) = base. mul ( & base) . divmod ( & modulus) . unwrap ( ) ;
747+ base = b2;
748+ e >>= 1 ;
749+ }
750+ let r = self . bigint_to_val ( result) ?;
751+ self . push ( r) ;
752+ Ok ( ( ) )
753+ }
754+ _ => Err ( cold_type ( "pow() takes 2 or 3 arguments" ) ) ,
755+ }
756+ }
757+
758+ fn pow_2arg ( & mut self , a : Val , b : Val ) -> Result < Val , VmErr > {
759+ if let Some ( ba) = self . to_bigint ( a) && b. is_int ( ) {
760+ let exp = b. as_int ( ) ;
761+ if exp >= 0 {
762+ if exp > u32:: MAX as i64 {
763+ return Err ( cold_value ( "pow() exponent too large" ) ) ;
764+ }
765+ return self . bigint_to_val ( ba. pow_u32 ( exp as u32 ) ) ;
766+ }
767+ return Ok ( Val :: float ( fpowi ( ba. to_f64 ( ) , exp as i32 ) ) ) ;
768+ }
769+ let to_f = |v : Val | -> Result < f64 , VmErr > {
770+ if v. is_int ( ) { Ok ( v. as_int ( ) as f64 ) }
771+ else if v. is_float ( ) { Ok ( v. as_float ( ) ) }
772+ else { Err ( cold_type ( "pow() requires numeric operands" ) ) }
773+ } ;
774+ Ok ( Val :: float ( fpowf ( to_f ( a) ?, to_f ( b) ?) ) )
775+ }
776+
777+ // ─── Introspection ───────────────────────────────────────────────
778+
779+ pub fn call_repr ( & mut self ) -> Result < ( ) , VmErr > {
780+ let o = self . pop ( ) ?;
781+ let s = self . repr ( o) ;
782+ let v = self . heap . alloc ( HeapObj :: Str ( s) ) ?;
783+ self . push ( v) ; Ok ( ( ) )
784+ }
785+
786+ pub fn call_callable ( & mut self ) -> Result < ( ) , VmErr > {
787+ let o = self . pop ( ) ?;
788+ let result = if o. is_heap ( ) {
789+ matches ! ( self . heap. get( o) ,
790+ HeapObj :: Func ( ..) | HeapObj :: BoundMethod ( ..) | HeapObj :: Type ( _) )
791+ } else { false } ;
792+ self . push ( Val :: bool ( result) ) ;
793+ Ok ( ( ) )
794+ }
795+
796+ pub fn call_id ( & mut self ) -> Result < ( ) , VmErr > {
797+ let o = self . pop ( ) ?;
798+ // Use the NaN-boxed bit pattern as identity. Truncate to fit INT_MAX.
799+ let id = ( ( o. 0 as i64 ) . abs ( ) ) & Val :: INT_MAX ;
800+ self . push ( Val :: int ( id) ) ;
801+ Ok ( ( ) )
802+ }
803+
804+ pub fn call_hash ( & mut self ) -> Result < ( ) , VmErr > {
805+ use core:: hash:: { Hash , Hasher } ;
806+ let o = self . pop ( ) ?;
807+ let mut h = crate :: modules:: fx:: FxHasher :: default ( ) ;
808+ if o. is_int ( ) { o. as_int ( ) . hash ( & mut h) ; }
809+ else if o. is_float ( ) { o. as_float ( ) . to_bits ( ) . hash ( & mut h) ; }
810+ else if o. is_bool ( ) { o. as_bool ( ) . hash ( & mut h) ; }
811+ else if o. is_none ( ) { 0u64 . hash ( & mut h) ; }
812+ else if o. is_heap ( ) {
813+ match self . heap . get ( o) {
814+ HeapObj :: Str ( s) => s. hash ( & mut h) ,
815+ HeapObj :: BigInt ( b) => { b. neg . hash ( & mut h) ; b. limbs . hash ( & mut h) ; }
816+ HeapObj :: Tuple ( items) => {
817+ for v in items { v. 0 . hash ( & mut h) ; }
818+ }
819+ HeapObj :: List ( _) | HeapObj :: Dict ( _) | HeapObj :: Set ( _) => {
820+ return Err ( cold_type ( "unhashable type" ) ) ;
821+ }
822+ _ => o. 0 . hash ( & mut h) ,
823+ }
824+ }
825+ self . push ( Val :: int ( h. finish ( ) as i64 & Val :: INT_MAX ) ) ;
826+ Ok ( ( ) )
827+ }
828+
829+ // ─── Sequence ops ────────────────────────────────────────────────
830+
831+ pub fn call_reversed ( & mut self ) -> Result < ( ) , VmErr > {
832+ let o = self . pop ( ) ?;
833+ if !o. is_heap ( ) { return Err ( cold_type ( "reversed() requires a sequence" ) ) ; }
834+ let mut items = if let HeapObj :: Str ( s) = self . heap . get ( o) {
835+ let s = s. clone ( ) ;
836+ self . str_to_char_vals ( & s) ?
837+ } else {
838+ self . extract_iter ( o, true ) ?
839+ } ;
840+ items. reverse ( ) ;
841+ let v = self . heap . alloc ( HeapObj :: List ( Rc :: new ( RefCell :: new ( items) ) ) ) ?;
842+ self . push ( v) ; Ok ( ( ) )
843+ }
599844}
0 commit comments