@@ -200,23 +200,89 @@ func (e *CallMatcherExecutor) parseKeywordArguments(args []core.Argument) map[st
200200 return kwargs
201201}
202202
203- // matchesArguments checks if CallSite arguments satisfy all constraints.
203+ // matchesArguments checks both positional and keyword argument constraints.
204204//
205205// Algorithm:
206206// 1. If no constraints, return true (backward compatibility)
207- // 2. Parse keyword arguments from CallSite
208- // 3. Check each constraint against actual values
207+ // 2. Check positional arguments first
208+ // 3. Check keyword arguments
209209// 4. Return true only if all constraints satisfied
210210//
211- // Performance: O(K) where K = number of keyword constraints (~1-3 typically) .
211+ // Performance: O(P + K) where P=positional constraints, K= keyword constraints.
212212func (e * CallMatcherExecutor ) matchesArguments (cs * core.CallSite ) bool {
213213 // No constraints = always match (backward compatibility)
214- if len (e .IR .KeywordArgs ) == 0 {
214+ if len (e .IR .PositionalArgs ) == 0 && len ( e . IR . KeywordArgs ) == 0 {
215215 return true
216216 }
217217
218+ // Check positional arguments first
219+ if ! e .matchesPositionalArguments (cs .Arguments ) {
220+ return false
221+ }
222+
223+ // Check keyword arguments
224+ if ! e .matchesKeywordArguments (cs .Arguments ) {
225+ return false
226+ }
227+
228+ return true // All constraints satisfied!
229+ }
230+
231+ // matchesPositionalArguments checks positional argument constraints.
232+ //
233+ // Algorithm:
234+ // 1. If no positional constraints, return true
235+ // 2. For each position constraint:
236+ // a. Convert position string to int
237+ // b. Check if position exists in arguments
238+ // c. Extract and match argument value
239+ //
240+ // Performance: O(P) where P = number of positional constraints.
241+ func (e * CallMatcherExecutor ) matchesPositionalArguments (args []core.Argument ) bool {
242+ if len (e .IR .PositionalArgs ) == 0 {
243+ return true // No positional constraints
244+ }
245+
246+ for posStr , constraint := range e .IR .PositionalArgs {
247+ // Convert position string to int
248+ pos , err := strconv .Atoi (posStr )
249+ if err != nil {
250+ // Invalid position string - should not happen with valid IR
251+ return false
252+ }
253+
254+ // Check if position exists in arguments
255+ if pos >= len (args ) {
256+ return false // Argument at position doesn't exist
257+ }
258+
259+ // Get actual argument value
260+ actualValue := args [pos ].Value
261+
262+ // Match against constraint
263+ if ! e .matchesArgumentValue (actualValue , constraint ) {
264+ return false
265+ }
266+ }
267+
268+ return true
269+ }
270+
271+ // matchesKeywordArguments checks keyword argument constraints (refactored from PR #2).
272+ //
273+ // Algorithm:
274+ // 1. If no keyword constraints, return true
275+ // 2. Parse keyword arguments from CallSite
276+ // 3. Check each constraint against actual values
277+ //
278+ // Performance: O(K) where K = number of keyword constraints.
279+ func (e * CallMatcherExecutor ) matchesKeywordArguments (args []core.Argument ) bool {
280+ if len (e .IR .KeywordArgs ) == 0 {
281+ return true // No keyword constraints
282+ }
283+
218284 // Parse keyword arguments from CallSite
219- keywordArgs := e .parseKeywordArguments (cs . Arguments )
285+ keywordArgs := e .parseKeywordArguments (args )
220286
221287 // Check each keyword argument constraint
222288 for name , constraint := range e .IR .KeywordArgs {
0 commit comments