@@ -85,8 +85,11 @@ mod missing_patterns;
8585pub mod printer;
8686
8787use crate :: {
88- ast:: { self , AssignName , Endianness , TypedClause , TypedPattern , TypedPatternBitArraySegment } ,
89- strings:: convert_string_escape_chars,
88+ ast:: {
89+ self , AssignName , BitArrayOption , Endianness , TypedClause , TypedPattern ,
90+ TypedPatternBitArraySegment ,
91+ } ,
92+ strings:: { convert_string_escape_chars, length_utf16, length_utf32} ,
9093 type_:: {
9194 Environment , Type , TypeValueConstructor , TypeValueConstructorField , TypeVar ,
9295 TypeVariantConstructors , collapse_links, error:: UnreachablePatternReason ,
@@ -424,7 +427,9 @@ impl Body {
424427 let value = match value {
425428 BitArrayMatchedValue :: LiteralFloat ( value) => BoundValue :: LiteralFloat ( value. clone ( ) ) ,
426429 BitArrayMatchedValue :: LiteralInt ( value) => BoundValue :: LiteralInt ( value. clone ( ) ) ,
427- BitArrayMatchedValue :: LiteralString ( value) => BoundValue :: LiteralString ( value. clone ( ) ) ,
430+ BitArrayMatchedValue :: LiteralString { value, .. } => {
431+ BoundValue :: LiteralString ( value. clone ( ) )
432+ }
428433 BitArrayMatchedValue :: Variable ( _)
429434 | BitArrayMatchedValue :: Discard ( _)
430435 | BitArrayMatchedValue :: Assign { .. } => {
@@ -1003,7 +1008,10 @@ pub struct MatchTest {
10031008pub enum BitArrayMatchedValue {
10041009 LiteralFloat ( EcoString ) ,
10051010 LiteralInt ( BigInt ) ,
1006- LiteralString ( EcoString ) ,
1011+ LiteralString {
1012+ value : EcoString ,
1013+ encoding : StringEncoding ,
1014+ } ,
10071015 Variable ( EcoString ) ,
10081016 Discard ( EcoString ) ,
10091017 Assign {
@@ -1012,13 +1020,20 @@ pub enum BitArrayMatchedValue {
10121020 } ,
10131021}
10141022
1023+ #[ derive( Clone , Copy , Eq , PartialEq , Debug ) ]
1024+ pub enum StringEncoding {
1025+ Utf8 ,
1026+ Utf16 ,
1027+ Utf32 ,
1028+ }
1029+
10151030impl BitArrayMatchedValue {
10161031 pub fn is_discard ( & self ) -> bool {
10171032 match self {
10181033 BitArrayMatchedValue :: Discard ( _) => true ,
10191034 BitArrayMatchedValue :: LiteralFloat ( _)
10201035 | BitArrayMatchedValue :: LiteralInt ( _)
1021- | BitArrayMatchedValue :: LiteralString ( _ )
1036+ | BitArrayMatchedValue :: LiteralString { .. }
10221037 | BitArrayMatchedValue :: Variable ( _)
10231038 | BitArrayMatchedValue :: Assign { .. } => false ,
10241039 }
@@ -2816,7 +2831,7 @@ impl CaseToCompile {
28162831
28172832 // Each segment is also turned into a match test, checking the
28182833 // selected bits match with the pattern's value.
2819- let value = segment_matched_value ( & segment. value ) ;
2834+ let value = segment_matched_value ( & segment. value , & segment . options ) ;
28202835
28212836 let type_ = match & segment. type_ {
28222837 type_ if type_. is_int ( ) => ReadType :: Int ,
@@ -2841,7 +2856,7 @@ impl CaseToCompile {
28412856 match & value {
28422857 BitArrayMatchedValue :: LiteralFloat ( _)
28432858 | BitArrayMatchedValue :: LiteralInt ( _)
2844- | BitArrayMatchedValue :: LiteralString ( _ )
2859+ | BitArrayMatchedValue :: LiteralString { .. }
28452860 | BitArrayMatchedValue :: Discard ( _) => { }
28462861 BitArrayMatchedValue :: Variable ( name)
28472862 | BitArrayMatchedValue :: Assign { name, .. } => {
@@ -2857,16 +2872,42 @@ impl CaseToCompile {
28572872 }
28582873}
28592874
2860- fn segment_matched_value ( pattern : & TypedPattern ) -> BitArrayMatchedValue {
2875+ fn segment_matched_value (
2876+ pattern : & TypedPattern ,
2877+ options : & [ BitArrayOption < TypedPattern > ] ,
2878+ ) -> BitArrayMatchedValue {
28612879 match pattern {
28622880 ast:: Pattern :: Int { int_value, .. } => BitArrayMatchedValue :: LiteralInt ( int_value. clone ( ) ) ,
28632881 ast:: Pattern :: Float { value, .. } => BitArrayMatchedValue :: LiteralFloat ( value. clone ( ) ) ,
2864- ast:: Pattern :: String { value, .. } => BitArrayMatchedValue :: LiteralString ( value. clone ( ) ) ,
2882+ ast:: Pattern :: String { value, .. }
2883+ if options
2884+ . iter ( )
2885+ . any ( |x| matches ! ( x, BitArrayOption :: Utf16 { .. } ) ) =>
2886+ {
2887+ BitArrayMatchedValue :: LiteralString {
2888+ value : value. clone ( ) ,
2889+ encoding : StringEncoding :: Utf16 ,
2890+ }
2891+ }
2892+ ast:: Pattern :: String { value, .. }
2893+ if options
2894+ . iter ( )
2895+ . any ( |x| matches ! ( x, BitArrayOption :: Utf32 { .. } ) ) =>
2896+ {
2897+ BitArrayMatchedValue :: LiteralString {
2898+ value : value. clone ( ) ,
2899+ encoding : StringEncoding :: Utf32 ,
2900+ }
2901+ }
2902+ ast:: Pattern :: String { value, .. } => BitArrayMatchedValue :: LiteralString {
2903+ value : value. clone ( ) ,
2904+ encoding : StringEncoding :: Utf8 ,
2905+ } ,
28652906 ast:: Pattern :: Variable { name, .. } => BitArrayMatchedValue :: Variable ( name. clone ( ) ) ,
28662907 ast:: Pattern :: Discard { name, .. } => BitArrayMatchedValue :: Discard ( name. clone ( ) ) ,
28672908 ast:: Pattern :: Assign { name, pattern, .. } => BitArrayMatchedValue :: Assign {
28682909 name : name. clone ( ) ,
2869- value : Box :: new ( segment_matched_value ( pattern) ) ,
2910+ value : Box :: new ( segment_matched_value ( pattern, options ) ) ,
28702911 } ,
28712912 x => panic ! ( "unexpected segment value pattern {:?}" , x) ,
28722913 }
@@ -2906,10 +2947,17 @@ fn segment_size(
29062947 // segments, and 64 for anything else.
29072948 None if segment. type_ . is_int ( ) => ReadSize :: ConstantBits ( 8 . into ( ) ) ,
29082949 None => match segment. value . as_ref ( ) {
2909- ast:: Pattern :: String { .. }
2910- if segment. has_utf16_option ( ) || segment. has_utf32_option ( ) =>
2911- {
2912- panic ! ( "non utf8 string in bit array pattern on js target" )
2950+ ast:: Pattern :: String { value, .. } if segment. has_utf16_option ( ) => {
2951+ ReadSize :: ConstantBits (
2952+ // Each utf16 code unit is 16 bits
2953+ length_utf16 ( & convert_string_escape_chars ( value) ) * BigInt :: from ( 16 ) ,
2954+ )
2955+ }
2956+ ast:: Pattern :: String { value, .. } if segment. has_utf32_option ( ) => {
2957+ // Each utf32 codepoint is 32 bits
2958+ ReadSize :: ConstantBits (
2959+ length_utf32 ( & convert_string_escape_chars ( value) ) * BigInt :: from ( 32 ) ,
2960+ )
29132961 }
29142962 // If the segment is a literal string then it has an automatic size
29152963 // given by its number of bytes.
0 commit comments