@@ -253,6 +253,8 @@ def read_var(self, first_char: str) -> Token:
253253 while self .has_input () and is_identifier_char (c := self .peek_char ()):
254254 self .read_char ()
255255 buf += c
256+ if buf == "guard" :
257+ return self .make_token (Operator , "guard" )
256258 return self .make_token (Name , buf )
257259
258260 def read_bytes (self ) -> Token :
@@ -303,6 +305,7 @@ def xp(n: float) -> Prec:
303305 "::" : lp (2000 ),
304306 "@" : rp (1001 ),
305307 "" : rp (1000 ),
308+ "guard" : rp (5.5 ),
306309 ">>" : lp (14 ),
307310 "<<" : lp (14 ),
308311 "^" : rp (13 ),
@@ -342,7 +345,7 @@ def xp(n: float) -> Prec:
342345HIGHEST_PREC : float = max (max (p .pl , p .pr ) for p in PS .values ())
343346
344347
345- OPER_CHARS = set ("" .join (PS .keys ()))
348+ OPER_CHARS = set ("" .join (PS .keys ())) - set ( "guard" )
346349assert " " not in OPER_CHARS
347350
348351
@@ -493,6 +496,8 @@ def parse(tokens: typing.List[Token], p: float = 0) -> "Object":
493496 elif op == Operator ("@" ):
494497 # TODO: revisit whether to use @ or . for field access
495498 l = Access (l , parse (tokens , pr ))
499+ elif op == Operator ("guard" ):
500+ l = Guard (l , parse (tokens , pr ))
496501 else :
497502 assert not isinstance (op , Juxt )
498503 assert isinstance (op , Operator )
@@ -868,6 +873,12 @@ def __str__(self) -> str:
868873 return f"EnvObject(keys={ self .env .keys ()} )"
869874
870875
876+ @dataclass (eq = True , frozen = True , unsafe_hash = True )
877+ class Guard (Object ):
878+ pattern : Object
879+ cond : Object
880+
881+
871882@dataclass (eq = True , frozen = True , unsafe_hash = True )
872883class MatchCase (Object ):
873884 pattern : Object
@@ -2327,6 +2338,18 @@ def test_parse_record_with_trailing_comma_raises_parse_error(self) -> None:
23272338 def test_parse_symbol_returns_symbol (self ) -> None :
23282339 self .assertEqual (parse ([SymbolToken ("abc" )]), Symbol ("abc" ))
23292340
2341+ def test_parse_guard (self ) -> None :
2342+ self .assertEqual (
2343+ parse (tokenize ("| x guard y -> x" )),
2344+ MatchFunction ([MatchCase (Guard (Var ("x" ), Var ("y" )), Var ("x" ))]),
2345+ )
2346+
2347+ def test_parse_guard_exp (self ) -> None :
2348+ self .assertEqual (
2349+ parse (tokenize ("| x guard x==1 -> x" )),
2350+ MatchFunction ([MatchCase (Guard (Var ("x" ), Binop (BinopKind .EQUAL , Var ("x" ), Int (1 ))), Var ("x" ))]),
2351+ )
2352+
23302353
23312354class MatchTests (unittest .TestCase ):
23322355 def test_match_with_equal_ints_returns_empty_dict (self ) -> None :
0 commit comments