@@ -670,147 +670,179 @@ export function bitwise_shift_right(x, y) {
670
670
}
671
671
672
672
export function inspect ( v ) {
673
- const t = typeof v ;
674
- if ( v === true ) return "True" ;
675
- if ( v === false ) return "False" ;
676
- if ( v === null ) return "//js(null)" ;
677
- if ( v === undefined ) return "Nil" ;
678
- if ( t === "string" ) return inspectString ( v ) ;
679
- if ( t === "bigint" || Number . isInteger ( v ) ) return v . toString ( ) ;
680
- if ( t === "number" ) return float_to_string ( v ) ;
681
- if ( v instanceof UtfCodepoint ) return inspectUtfCodepoint ( v ) ;
682
- if ( v instanceof BitArray ) return `<<${ bit_array_inspect ( v , "" ) } >>` ;
683
- if ( v instanceof RegExp ) return `//js(${ v } )` ;
684
- if ( v instanceof Date ) return `//js(Date("${ v . toISOString ( ) } "))` ;
685
- if ( v instanceof globalThis . Error ) return `//js(${ v . toString ( ) } )` ;
686
- if ( v instanceof Function ) {
687
- const args = [ ] ;
688
- for ( const i of Array ( v . length ) . keys ( ) )
689
- args . push ( String . fromCharCode ( i + 97 ) ) ;
690
- return `//fn(${ args . join ( ", " ) } ) { ... }` ;
691
- }
673
+ return new Inspector ( ) . inspect ( v ) ;
674
+ }
675
+
676
+ class Inspector {
677
+ #references = new Set ( ) ;
678
+
679
+ inspect ( v ) {
680
+ const t = typeof v ;
681
+ if ( v === true ) return "True" ;
682
+ if ( v === false ) return "False" ;
683
+ if ( v === null ) return "//js(null)" ;
684
+ if ( v === undefined ) return "Nil" ;
685
+ if ( t === "string" ) return this . #string( v ) ;
686
+ if ( t === "bigint" || Number . isInteger ( v ) ) return v . toString ( ) ;
687
+ if ( t === "number" ) return float_to_string ( v ) ;
688
+ if ( v instanceof UtfCodepoint ) return this . #utfCodepoint( v ) ;
689
+ if ( v instanceof BitArray ) return this . #bit_array( v ) ;
690
+ if ( v instanceof RegExp ) return `//js(${ v } )` ;
691
+ if ( v instanceof Date ) return `//js(Date("${ v . toISOString ( ) } "))` ;
692
+ if ( v instanceof globalThis . Error ) return `//js(${ v . toString ( ) } )` ;
693
+ if ( v instanceof Function ) {
694
+ const args = [ ] ;
695
+ for ( const i of Array ( v . length ) . keys ( ) )
696
+ args . push ( String . fromCharCode ( i + 97 ) ) ;
697
+ return `//fn(${ args . join ( ", " ) } ) { ... }` ;
698
+ }
692
699
693
- try {
694
- if ( Array . isArray ( v ) ) return `#(${ v . map ( inspect ) . join ( ", " ) } )` ;
695
- if ( v instanceof List ) return inspectList ( v ) ;
696
- if ( v instanceof CustomType ) return inspectCustomType ( v ) ;
697
- if ( v instanceof Dict ) return inspectDict ( v ) ;
698
- if ( v instanceof Set ) return `//js(Set(${ [ ...v ] . map ( inspect ) . join ( ", " ) } ))` ;
699
- return inspectObject ( v ) ;
700
- } catch ( e ) {
701
- if ( e instanceof RangeError ) return "//js(circular)" ;
702
- throw e ;
700
+ if ( this . #references. size === this . #references. add ( v ) . size ) {
701
+ return "//js(circular reference)" ;
702
+ }
703
+
704
+ if ( Array . isArray ( v ) )
705
+ return `#(${ v . map ( ( v ) => this . inspect ( v ) ) . join ( ", " ) } )` ;
706
+ if ( v instanceof List ) return this . #list( v ) ;
707
+ if ( v instanceof CustomType ) return this . #customType( v ) ;
708
+ if ( v instanceof Dict ) return this . #dict( v ) ;
709
+ if ( v instanceof Set )
710
+ return `//js(Set(${ [ ...v ] . map ( ( v ) => this . inspect ( v ) ) . join ( ", " ) } ))` ;
711
+ return this . #object( v ) ;
703
712
}
704
- }
705
713
706
- function inspectString ( str ) {
707
- let new_str = '"' ;
708
- for ( let i = 0 ; i < str . length ; i ++ ) {
709
- const char = str [ i ] ;
710
- switch ( char ) {
711
- case "\n" :
712
- new_str += "\\n" ;
713
- break ;
714
- case "\r" :
715
- new_str += "\\r" ;
716
- break ;
717
- case "\t" :
718
- new_str += "\\t" ;
719
- break ;
720
- case "\f" :
721
- new_str += "\\f" ;
722
- break ;
723
- case "\\" :
724
- new_str += "\\\\" ;
725
- break ;
726
- case '"' :
727
- new_str += '\\"' ;
728
- break ;
729
- default :
730
- if ( char < " " || ( char > "~" && char < "\u{00A0}" ) ) {
731
- new_str +=
732
- "\\u{" +
733
- char . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) . padStart ( 4 , "0" ) +
734
- "}" ;
735
- } else {
736
- new_str += char ;
737
- }
714
+ #object( v ) {
715
+ const name = Object . getPrototypeOf ( v ) ?. constructor ?. name || "Object" ;
716
+ const props = [ ] ;
717
+ for ( const k of Object . keys ( v ) ) {
718
+ props . push ( `${ this . inspect ( k ) } : ${ this . inspect ( v [ k ] ) } ` ) ;
738
719
}
720
+ const body = props . length ? " " + props . join ( ", " ) + " " : "" ;
721
+ const head = name === "Object" ? "" : name + " " ;
722
+ return `//js(${ head } {${ body } })` ;
739
723
}
740
- new_str += '"' ;
741
- return new_str ;
742
- }
743
-
744
- function inspectDict ( map ) {
745
- let body = "dict.from_list([" ;
746
- let first = true ;
747
- map . forEach ( ( value , key ) => {
748
- if ( ! first ) body = body + ", " ;
749
- body = body + "#(" + inspect ( key ) + ", " + inspect ( value ) + ")" ;
750
- first = false ;
751
- } ) ;
752
- return body + "])" ;
753
- }
754
-
755
- function inspectObject ( v ) {
756
- const name = Object . getPrototypeOf ( v ) ?. constructor ?. name || "Object" ;
757
- const props = [ ] ;
758
- for ( const k of Object . keys ( v ) ) {
759
- props . push ( `${ inspect ( k ) } : ${ inspect ( v [ k ] ) } ` ) ;
724
+
725
+ #dict( map ) {
726
+ let body = "dict.from_list([" ;
727
+ let first = true ;
728
+ map . forEach ( ( value , key ) => {
729
+ if ( ! first ) body = body + ", " ;
730
+ body = body + "#(" + this . inspect ( key ) + ", " + this . inspect ( value ) + ")" ;
731
+ first = false ;
732
+ } ) ;
733
+ return body + "])" ;
760
734
}
761
- const body = props . length ? " " + props . join ( ", " ) + " " : "" ;
762
- const head = name === "Object" ? "" : name + " " ;
763
- return `//js(${ head } {${ body } })` ;
764
- }
765
-
766
- function inspectCustomType ( record ) {
767
- const props = Object . keys ( record )
768
- . map ( ( label ) => {
769
- const value = inspect ( record [ label ] ) ;
770
- return isNaN ( parseInt ( label ) ) ? `${ label } : ${ value } ` : value ;
771
- } )
772
- . join ( ", " ) ;
773
- return props
774
- ? `${ record . constructor . name } (${ props } )`
775
- : record . constructor . name ;
776
- }
777
-
778
- export function inspectList ( list ) {
779
- if ( list instanceof Empty ) {
780
- return "[]" ;
735
+
736
+ #customType( record ) {
737
+ const props = Object . keys ( record )
738
+ . map ( ( label ) => {
739
+ const value = this . inspect ( record [ label ] ) ;
740
+ return isNaN ( parseInt ( label ) ) ? `${ label } : ${ value } ` : value ;
741
+ } )
742
+ . join ( ", " ) ;
743
+ return props
744
+ ? `${ record . constructor . name } (${ props } )`
745
+ : record . constructor . name ;
781
746
}
782
747
783
- let char_out = 'charlist.from_string("' ;
784
- let list_out = "[" ;
748
+ #list( list ) {
749
+ if ( list instanceof Empty ) {
750
+ return "[]" ;
751
+ }
785
752
786
- let current = list ;
787
- while ( current instanceof NonEmpty ) {
788
- let element = current . head ;
789
- current = current . tail ;
753
+ let char_out = 'charlist.from_string("' ;
754
+ let list_out = "[" ;
790
755
791
- if ( list_out !== "[" ) {
792
- list_out += ", " ;
756
+ let current = list ;
757
+ while ( current instanceof NonEmpty ) {
758
+ let element = current . head ;
759
+ current = current . tail ;
760
+
761
+ if ( list_out !== "[" ) {
762
+ list_out += ", " ;
763
+ }
764
+ list_out += this . inspect ( element ) ;
765
+
766
+ if ( char_out ) {
767
+ if ( Number . isInteger ( element ) && element >= 32 && element <= 126 ) {
768
+ char_out += String . fromCharCode ( element ) ;
769
+ } else {
770
+ char_out = null ;
771
+ }
772
+ }
793
773
}
794
- list_out += inspect ( element ) ;
795
774
796
775
if ( char_out ) {
797
- if ( Number . isInteger ( element ) && element >= 32 && element <= 126 ) {
798
- char_out += String . fromCharCode ( element ) ;
799
- } else {
800
- char_out = null ;
776
+ return char_out + '")' ;
777
+ } else {
778
+ return list_out + "]" ;
779
+ }
780
+ }
781
+
782
+ #string( str ) {
783
+ let new_str = '"' ;
784
+ for ( let i = 0 ; i < str . length ; i ++ ) {
785
+ const char = str [ i ] ;
786
+ switch ( char ) {
787
+ case "\n" :
788
+ new_str += "\\n" ;
789
+ break ;
790
+ case "\r" :
791
+ new_str += "\\r" ;
792
+ break ;
793
+ case "\t" :
794
+ new_str += "\\t" ;
795
+ break ;
796
+ case "\f" :
797
+ new_str += "\\f" ;
798
+ break ;
799
+ case "\\" :
800
+ new_str += "\\\\" ;
801
+ break ;
802
+ case '"' :
803
+ new_str += '\\"' ;
804
+ break ;
805
+ default :
806
+ if ( char < " " || ( char > "~" && char < "\u{00A0}" ) ) {
807
+ new_str +=
808
+ "\\u{" +
809
+ char . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) . padStart ( 4 , "0" ) +
810
+ "}" ;
811
+ } else {
812
+ new_str += char ;
813
+ }
801
814
}
802
815
}
816
+ new_str += '"' ;
817
+ return new_str ;
803
818
}
804
819
805
- if ( char_out ) {
806
- return char_out + '")' ;
807
- } else {
808
- return list_out + "]" ;
820
+ #utfCodepoint( codepoint ) {
821
+ return `//utfcodepoint(${ String . fromCodePoint ( codepoint . value ) } )` ;
809
822
}
810
- }
811
823
812
- export function inspectUtfCodepoint ( codepoint ) {
813
- return `//utfcodepoint(${ String . fromCodePoint ( codepoint . value ) } )` ;
824
+ #bit_array( bits ) {
825
+ let acc = "<<" ;
826
+ if ( bits . bitSize === 0 ) {
827
+ return acc ;
828
+ }
829
+
830
+ for ( let i = 0 ; i < bits . byteSize - 1 ; i ++ ) {
831
+ acc += bits . byteAt ( i ) . toString ( ) ;
832
+ acc += ", " ;
833
+ }
834
+
835
+ if ( bits . byteSize * 8 === bits . bitSize ) {
836
+ acc += bits . byteAt ( bits . byteSize - 1 ) . toString ( ) ;
837
+ } else {
838
+ const trailingBitsCount = bits . bitSize % 8 ;
839
+ acc += bits . byteAt ( bits . byteSize - 1 ) >> ( 8 - trailingBitsCount ) ;
840
+ acc += `:size(${ trailingBitsCount } )` ;
841
+ }
842
+
843
+ acc += ">>" ;
844
+ return acc ;
845
+ }
814
846
}
815
847
816
848
export function base16_encode ( bit_array ) {
@@ -843,27 +875,6 @@ export function base16_decode(string) {
843
875
return new Ok ( new BitArray ( bytes ) ) ;
844
876
}
845
877
846
- export function bit_array_inspect ( bits , acc ) {
847
- if ( bits . bitSize === 0 ) {
848
- return acc ;
849
- }
850
-
851
- for ( let i = 0 ; i < bits . byteSize - 1 ; i ++ ) {
852
- acc += bits . byteAt ( i ) . toString ( ) ;
853
- acc += ", " ;
854
- }
855
-
856
- if ( bits . byteSize * 8 === bits . bitSize ) {
857
- acc += bits . byteAt ( bits . byteSize - 1 ) . toString ( ) ;
858
- } else {
859
- const trailingBitsCount = bits . bitSize % 8 ;
860
- acc += bits . byteAt ( bits . byteSize - 1 ) >> ( 8 - trailingBitsCount ) ;
861
- acc += `:size(${ trailingBitsCount } )` ;
862
- }
863
-
864
- return acc ;
865
- }
866
-
867
878
export function bit_array_to_int_and_size ( bits ) {
868
879
const trailingBitsCount = bits . bitSize % 8 ;
869
880
const unusedBitsCount = trailingBitsCount === 0 ? 0 : 8 - trailingBitsCount ;
0 commit comments