@@ -20,7 +20,7 @@ open LeanPython.Stdlib.Hmac
2020open LeanPython.Stdlib.Secrets
2121open LeanPython.Stdlib.Sys
2222open LeanPython.Stdlib.Os
23- open LeanPython.Stdlib.Time (timeTime timeMonotonic timeSleep)
23+ open LeanPython.Stdlib.Time (timeTime timeMonotonic timePerfCounter timeSleep)
2424open LeanPython.Stdlib.Datetime
2525open LeanPython.Stdlib.Pathlib
2626open LeanPython.Stdlib.Logging
@@ -138,7 +138,7 @@ private def knownDictMethods : List String :=
138138 ["get" , "keys" , "values" , "items" , "pop" , "update" , "clear" , "copy" , "setdefault" ]
139139
140140private def knownSetMethods : List String :=
141- ["add" , "remove" , "discard" , "clear" , "copy" , "union" , "intersection" ,
141+ ["add" , "remove" , "discard" , "clear" , "copy" , "update" , " union" , "intersection" ,
142142 "difference" , "symmetric_difference" , "issubset" , "issuperset" , "isdisjoint" ]
143143
144144private def knownIntMethods : List String :=
@@ -759,6 +759,16 @@ partial def callValueDispatch (callee : Value) (args : List Value)
759759 match name with
760760 | "map" => builtinMap args
761761 | "filter" => builtinFilter args
762+ | "min" => do
763+ let keyKw := kwargs.find? (fun (k, _) => k == "key" )
764+ match keyKw with
765+ | some (_, keyFn) => builtinMinWithKey args keyFn
766+ | none => callBuiltin name args kwargs
767+ | "max" => do
768+ let keyKw := kwargs.find? (fun (k, _) => k == "key" )
769+ match keyKw with
770+ | some (_, keyFn) => builtinMaxWithKey args keyFn
771+ | none => callBuiltin name args kwargs
762772 | "functools.reduce" => builtinFunctoolsReduce args
763773 | "itertools.accumulate" => builtinItertoolsAccumulate args kwargs
764774 | "collections.defaultdict" => do
@@ -3135,9 +3145,10 @@ partial def getBuiltinModule (name : String) : InterpM (Option Value) := do
31353145 some <$> mkMod ns
31363146 | "time" =>
31373147 let mut ns : Std.HashMap String Value := {}
3138- ns := ns.insert "time" (.builtin "time.time" )
3139- ns := ns.insert "monotonic" (.builtin "time.monotonic" )
3140- ns := ns.insert "sleep" (.builtin "time.sleep" )
3148+ ns := ns.insert "time" (.builtin "time.time" )
3149+ ns := ns.insert "monotonic" (.builtin "time.monotonic" )
3150+ ns := ns.insert "perf_counter" (.builtin "time.perf_counter" )
3151+ ns := ns.insert "sleep" (.builtin "time.sleep" )
31413152 some <$> mkMod ns
31423153 | "datetime" =>
31433154 let mut ns : Std.HashMap String Value := {}
@@ -4182,6 +4193,42 @@ partial def builtinFilter (args : List Value) : InterpM Value := do
41824193 allocList result
41834194 | _ => throwTypeError "filter() requires exactly two arguments"
41844195
4196+ -- ============================================================
4197+ -- min/max with key= (need callValueDispatch, so must be in mutual block)
4198+ -- ============================================================
4199+
4200+ partial def builtinMinWithKey (args : List Value) (keyFn : Value) : InterpM Value := do
4201+ let items : List Value ← match args with
4202+ | [v] => do let arr ← iterValuesExt v; pure arr.toList
4203+ | xs => pure xs
4204+ match items with
4205+ | [] => throwValueError "min() arg is an empty sequence"
4206+ | first :: rest => do
4207+ let mut best := first
4208+ let mut bestKey ← callValueDispatch keyFn [first] []
4209+ for v in rest do
4210+ let vKey ← callValueDispatch keyFn [v] []
4211+ if ← evalCmpOp .lt vKey bestKey then
4212+ best := v
4213+ bestKey := vKey
4214+ return best
4215+
4216+ partial def builtinMaxWithKey (args : List Value) (keyFn : Value) : InterpM Value := do
4217+ let items : List Value ← match args with
4218+ | [v] => do let arr ← iterValuesExt v; pure arr.toList
4219+ | xs => pure xs
4220+ match items with
4221+ | [] => throwValueError "max() arg is an empty sequence"
4222+ | first :: rest => do
4223+ let mut best := first
4224+ let mut bestKey ← callValueDispatch keyFn [first] []
4225+ for v in rest do
4226+ let vKey ← callValueDispatch keyFn [v] []
4227+ if ← evalCmpOp .gt vKey bestKey then
4228+ best := v
4229+ bestKey := vKey
4230+ return best
4231+
41854232-- ============================================================
41864233-- Enum support: check if any base class is an Enum
41874234-- ============================================================
@@ -4891,6 +4938,18 @@ partial def callSetMethod (ref : HeapRef) (method : String) (args : List Value)
48914938 if !found then result := result.push elem
48924939 allocSet result
48934940 | _ => throwTypeError "union() takes exactly one argument"
4941+ | "update" =>
4942+ match args with
4943+ | [other] => do
4944+ let mut arr ← heapGetSet ref
4945+ let b ← iterValuesExt other
4946+ for elem in b do
4947+ let mut found := false
4948+ for existing in arr do
4949+ if ← valueEq existing elem then found := true ; break
4950+ if !found then arr := arr.push elem
4951+ heapSetSet ref arr; return .none
4952+ | _ => throwTypeError "update() takes exactly one argument"
48944953 | "intersection" =>
48954954 match args with
48964955 | [other] => do
0 commit comments