@@ -249,6 +249,28 @@ impl TypeAlias {
249249
250250impl_eq_hash ! ( TypeAlias ; name, ty) ;
251251
252+ #[ derive( Clone , Copy , Debug , Eq , PartialEq , Hash ) ]
253+ #[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
254+ pub enum UIntBound {
255+ Min ,
256+ Max ,
257+ }
258+
259+ impl UIntBound {
260+ pub const fn as_str ( self ) -> & ' static str {
261+ match self {
262+ Self :: Min => "MIN" ,
263+ Self :: Max => "MAX" ,
264+ }
265+ }
266+ }
267+
268+ #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
269+ #[ cfg_attr( feature = "arbitrary" , derive( arbitrary:: Arbitrary ) ) ]
270+ pub enum TypeBound {
271+ UInt ( UIntType , UIntBound ) ,
272+ }
273+
252274/// An expression is something that returns a value.
253275#[ derive( Clone , Debug ) ]
254276pub struct Expression {
@@ -339,6 +361,8 @@ pub enum SingleExpressionInner {
339361 Binary ( Binary ) ,
340362 /// Hexadecimal string literal.
341363 Hexadecimal ( Hexadecimal ) ,
364+ /// Constants of a type (e.g. MAX, MIN)
365+ TypeBound ( TypeBound ) ,
342366 /// Witness value.
343367 Witness ( WitnessName ) ,
344368 /// Parameter value.
@@ -633,9 +657,8 @@ impl TreeLike for ExprTree<'_> {
633657 | S :: Decimal ( _)
634658 | S :: Hexadecimal ( _)
635659 | S :: Variable ( _)
636- | S :: Witness ( _)
637- | S :: Parameter ( _)
638- | S :: Option ( None ) => Tree :: Nullary ,
660+ | S :: TypeBound ( _) => Tree :: Nullary ,
661+ S :: Witness ( _) | S :: Parameter ( _) | S :: Option ( None ) => Tree :: Nullary ,
639662 S :: Option ( Some ( l) )
640663 | S :: Either ( Either :: Left ( l) )
641664 | S :: Either ( Either :: Right ( l) )
@@ -684,6 +707,9 @@ impl fmt::Display for ExprTree<'_> {
684707 S :: Decimal ( decimal) => write ! ( f, "{decimal}" ) ?,
685708 S :: Hexadecimal ( hexadecimal) => write ! ( f, "0x{hexadecimal}" ) ?,
686709 S :: Variable ( name) => write ! ( f, "{name}" ) ?,
710+ S :: TypeBound ( TypeBound :: UInt ( ty, bound) ) => {
711+ write ! ( f, "{ty}::{}" , bound. as_str( ) ) ?
712+ }
687713 S :: Witness ( name) => write ! ( f, "witness::{name}" ) ?,
688714 S :: Parameter ( name) => write ! ( f, "param::{name}" ) ?,
689715 S :: Option ( None ) => write ! ( f, "None" ) ?,
@@ -1606,6 +1632,34 @@ impl SingleExpression {
16061632
16071633 let match_expr = Match :: parser ( expr. clone ( ) ) . map ( SingleExpressionInner :: Match ) ;
16081634
1635+ let type_bound = Identifier :: parser ( )
1636+ . then_ignore ( just ( Token :: DoubleColon ) )
1637+ . then ( Identifier :: parser ( ) )
1638+ . try_map (
1639+ |( lhs, rhs) , span| match UIntType :: from_str ( lhs. as_inner ( ) ) {
1640+ Ok ( ty) => Ok ( ( ty, rhs) ) ,
1641+ // this is a fall through, this error is not emitted
1642+ Err ( _) => Err ( Error :: Grammar ( "not a type bound" . into ( ) ) . with_span ( span) ) ,
1643+ } ,
1644+ )
1645+ . validate ( |( ty, rhs) , e, emit| {
1646+ let bound = match rhs. as_inner ( ) {
1647+ "MIN" => UIntBound :: Min ,
1648+ "MAX" => UIntBound :: Max ,
1649+ _ => {
1650+ // Send the error through here
1651+ emit. emit (
1652+ Error :: Grammar (
1653+ "Expected `MIN` or `MAX` after unsigned integer type" . into ( ) ,
1654+ )
1655+ . with_span ( e. span ( ) ) ,
1656+ ) ;
1657+ UIntBound :: Min
1658+ }
1659+ } ;
1660+ SingleExpressionInner :: TypeBound ( TypeBound :: UInt ( ty, bound) )
1661+ } ) ;
1662+
16091663 let variable = Identifier :: parser ( ) . map ( SingleExpressionInner :: Variable ) ;
16101664
16111665 // Expression delimeted by parentheses
@@ -1616,7 +1670,7 @@ impl SingleExpression {
16161670
16171671 choice ( (
16181672 left, right, some, none, boolean, match_expr, expression, list, array, tuple, call,
1619- literal, variable,
1673+ literal, type_bound , variable,
16201674 ) )
16211675 . map_with ( |inner, e| Self {
16221676 inner,
@@ -2193,7 +2247,10 @@ mod test {
21932247 let parse_program = Program :: parse_from_str_with_errors ( input, & mut error_handler) ;
21942248
21952249 assert ! ( parse_program. is_none( ) ) ;
2196- assert ! ( ErrorCollector :: to_string( & error_handler) . contains( "Expected '::', found ':'" ) ) ;
2250+ let errors = ErrorCollector :: to_string ( & error_handler) ;
2251+
2252+ assert ! ( parse_program. is_none( ) ) ;
2253+ assert ! ( errors. contains( "::" ) , "{errors}" ) ;
21972254 }
21982255
21992256 #[ test]
@@ -2203,6 +2260,119 @@ mod test {
22032260 let parse_program = Program :: parse_from_str_with_errors ( input, & mut error_handler) ;
22042261
22052262 assert ! ( parse_program. is_none( ) ) ;
2206- assert ! ( ErrorCollector :: to_string( & error_handler) . contains( "Expected ';', found '::'" ) ) ;
2263+ let errors = ErrorCollector :: to_string ( & error_handler) ;
2264+
2265+ assert ! ( parse_program. is_none( ) ) ;
2266+ assert ! ( errors. contains( "::" ) , "{errors}" ) ;
2267+ }
2268+
2269+ #[ test]
2270+ fn invalid_input_falls_through_type_bound_on_try_match ( ) {
2271+ let input = "fn main() { let pk: Pubkey = witnes::PK; }" ;
2272+ let mut error_handler = ErrorCollector :: new ( Arc :: from ( input) ) ;
2273+ let parse_program = Program :: parse_from_str_with_errors ( input, & mut error_handler) ;
2274+
2275+ assert ! ( parse_program. is_none( ) ) ;
2276+
2277+ let error_str = ErrorCollector :: to_string ( & error_handler) ;
2278+
2279+ assert ! (
2280+ error_str. contains( "Expected ';', found '::'" ) ,
2281+ "{}" ,
2282+ error_str
2283+ ) ;
2284+
2285+ assert ! (
2286+ !error_str. contains( "Expected unsigned integer type before `::`" ) ,
2287+ "{}" ,
2288+ error_str
2289+ ) ;
2290+
2291+ assert ! (
2292+ !error_str. contains( "Expected `MIN` or `MAX` after unsigned integer type" ) ,
2293+ "{}" ,
2294+ error_str
2295+ ) ;
2296+ }
2297+
2298+ #[ test]
2299+ fn valid_input_falls_through_type_bound_when_not_match ( ) {
2300+ let input = "fn main() { let pk: Pubkey = Witness::PK; }" ;
2301+ let mut error_handler = ErrorCollector :: new ( Arc :: from ( input) ) ;
2302+ let parse_program = Program :: parse_from_str_with_errors ( input, & mut error_handler) ;
2303+
2304+ assert ! ( parse_program. is_none( ) ) ;
2305+
2306+ let error_str = ErrorCollector :: to_string ( & error_handler) ;
2307+
2308+ assert ! (
2309+ error_str. contains( "Expected ';', found '::'" ) ,
2310+ "{}" ,
2311+ error_str
2312+ ) ;
2313+
2314+ assert ! (
2315+ !error_str. contains( "Expected unsigned integer type before `::`" ) ,
2316+ "{}" ,
2317+ error_str
2318+ ) ;
2319+
2320+ assert ! (
2321+ !error_str. contains( "Expected `MIN` or `MAX` after unsigned integer type" ) ,
2322+ "{}" ,
2323+ error_str
2324+ ) ;
2325+ }
2326+
2327+ #[ test]
2328+ fn parses_u8_min_max_invalid_reports_error ( ) {
2329+ let input = "fn main() { let a: u8 = u8::MI; let b: u8 = u8::MA; }" ;
2330+ let mut error_handler = ErrorCollector :: new ( Arc :: from ( input) ) ;
2331+ let parse_program = Program :: parse_from_str_with_errors ( input, & mut error_handler) ;
2332+ let error_str = ErrorCollector :: to_string ( & error_handler) ;
2333+
2334+ assert ! ( parse_program. is_none( ) ) ;
2335+
2336+ assert ! (
2337+ error_str. contains( "Expected `MIN` or `MAX` after unsigned integer type" ) ,
2338+ "{}" ,
2339+ error_str
2340+ ) ;
2341+ }
2342+
2343+ #[ test]
2344+ fn parses_u8_min_max ( ) {
2345+ let src = "fn main() { let a: u8 = u8::MIN; let b: u8 = u8::MAX; }" ;
2346+ let program = Program :: parse_from_str ( src) . expect ( "should parse" ) ;
2347+ let rendered = program. to_string ( ) ;
2348+ assert ! ( rendered. contains( "u8::MIN" ) ) ;
2349+ assert ! ( rendered. contains( "u8::MAX" ) ) ;
2350+ }
2351+
2352+ #[ test]
2353+ fn parses_all_uint_min_max ( ) {
2354+ let types = [ "u1" , "u2" , "u4" , "u8" , "u16" , "u32" , "u64" , "u128" , "u256" ] ;
2355+
2356+ for ty in types {
2357+ let src = format ! (
2358+ "fn main() {{ let a: {t} = {t}::MIN; let b: {t} = {t}::MAX; }}" ,
2359+ t = ty
2360+ ) ;
2361+
2362+ let program = Program :: parse_from_str ( & src)
2363+ . unwrap_or_else ( |e| panic ! ( "failed to parse for {ty}: {e:?}" ) ) ;
2364+
2365+ let rendered = program. to_string ( ) ;
2366+
2367+ assert ! (
2368+ rendered. contains( & format!( "{ty}::MIN" ) ) ,
2369+ "missing MIN for {ty}"
2370+ ) ;
2371+
2372+ assert ! (
2373+ rendered. contains( & format!( "{ty}::MAX" ) ) ,
2374+ "missing MAX for {ty}"
2375+ ) ;
2376+ }
22072377 }
22082378}
0 commit comments