368368// $
369369//
370370// PyArg_ParseTupleAndKeywords() only: Indicates that the remaining
371- // arguments in the Python argument list are keyword-only. Currently,
372- // all keyword-only arguments must also be optional arguments, so |
373- // must always be specified before $ in the format string.
371+ // arguments in the Python argument list are keyword-only.
374372//
375373// New in version 3.3.
376374//
@@ -416,17 +414,13 @@ func ParseTupleAndKeywords(args Tuple, kwargs StringDict, format string, kwlist
416414 if kwlist != nil && len (results ) != len (kwlist ) {
417415 return ExceptionNewf (TypeError , "Internal error: supply the same number of results and kwlist" )
418416 }
419- min , max , name , ops := parseFormat ( format )
420- keywordOnly := false
421- err := checkNumberOfArgs (name , len (args )+ len (kwargs ), len (results ), min , max )
417+ var opsBuf [ 16 ] formatOp
418+ min , name , kwOnly_i , ops := parseFormat ( format , opsBuf [: 0 ])
419+ err := checkNumberOfArgs (name , len (args )+ len (kwargs ), len (results ), min , len ( ops ) )
422420 if err != nil {
423421 return err
424422 }
425423
426- if len (ops ) > 0 && ops [0 ] == "$" {
427- keywordOnly = true
428- ops = ops [1 :]
429- }
430424 // Check all the kwargs are in kwlist
431425 // O(N^2) Slow but kwlist is usually short
432426 for kwargName := range kwargs {
@@ -439,46 +433,60 @@ func ParseTupleAndKeywords(args Tuple, kwargs StringDict, format string, kwlist
439433 found:
440434 }
441435
442- // Create args tuple with all the arguments we have in
443- args = args .Copy ()
444- for i , kw := range kwlist {
445- if value , ok := kwargs [kw ]; ok {
446- if len (args ) > i {
436+ // Walk through all the results we want
437+ for i , op := range ops {
438+
439+ var (
440+ arg Object
441+ kw string
442+ )
443+ if i < len (kwlist ) {
444+ kw = kwlist [i ]
445+ arg = kwargs [kw ]
446+ }
447+
448+ // Consume ordered args first -- they should not require keyword only or also be specified via keyword
449+ if i < len (args ) {
450+ if i >= kwOnly_i {
451+ return ExceptionNewf (TypeError , "%s() specifies argument '%s' that is keyword only" , name , kw )
452+ }
453+ if arg != nil {
447454 return ExceptionNewf (TypeError , "%s() got multiple values for argument '%s'" , name , kw )
448455 }
449- args = append (args , value )
450- } else if keywordOnly {
451- args = append (args , nil )
456+ arg = args [i ]
452457 }
453- }
454- for i , arg := range args {
455- op := ops [i ]
458+
459+ // Unspecified args retain their default value
460+ if arg == nil {
461+ continue
462+ }
463+
456464 result := results [i ]
457- switch op {
458- case "O" :
465+ switch op . code {
466+ case 'O' :
459467 * result = arg
460- case "Z" , "z" :
468+ case 'Z' , 'z' :
461469 if _ , ok := arg .(NoneType ); ok {
462470 * result = arg
463471 break
464472 }
465473 fallthrough
466- case "U" , "s" :
474+ case 'U' , 's' :
467475 if _ , ok := arg .(String ); ! ok {
468476 return ExceptionNewf (TypeError , "%s() argument %d must be str, not %s" , name , i + 1 , arg .Type ().Name )
469477 }
470478 * result = arg
471- case "i" :
479+ case 'i' :
472480 if _ , ok := arg .(Int ); ! ok {
473481 return ExceptionNewf (TypeError , "%s() argument %d must be int, not %s" , name , i + 1 , arg .Type ().Name )
474482 }
475483 * result = arg
476- case "p" :
484+ case 'p' :
477485 if _ , ok := arg .(Bool ); ! ok {
478486 return ExceptionNewf (TypeError , "%s() argument %d must be bool, not %s" , name , i + 1 , arg .Type ().Name )
479487 }
480488 * result = arg
481- case "d" :
489+ case 'd' :
482490 switch x := arg .(type ) {
483491 case Int :
484492 * result = Float (x )
@@ -500,30 +508,42 @@ func ParseTuple(args Tuple, format string, results ...*Object) error {
500508 return ParseTupleAndKeywords (args , nil , format , nil , results ... )
501509}
502510
511+ type formatOp struct {
512+ code byte
513+ modifier byte
514+ }
515+
503516// Parse the format
504- func parseFormat (format string ) (min , max int , name string , ops []string ) {
517+ func parseFormat (format string , in [] formatOp ) (min int , name string , kwOnly_i int , ops []formatOp ) {
505518 name = "function"
506519 min = - 1
507- for format != "" {
508- op := string (format [0 ])
509- format = format [1 :]
510- if len (format ) > 1 && (format [1 ] == '*' || format [1 ] == '#' ) {
511- op += string (format [0 ])
512- format = format [1 :]
520+ kwOnly_i = 0xFFFF
521+ ops = in [:0 ]
522+
523+ N := len (format )
524+ for i := 0 ; i < N ; {
525+ op := formatOp {code : format [i ]}
526+ i ++
527+ if i < N {
528+ if mod := format [i ]; mod == '*' || mod == '#' {
529+ op .modifier = mod
530+ i ++
531+ }
513532 }
514- switch op {
515- case ":" , ";" :
516- name = format
517- format = ""
518- case "|" :
533+ switch op .code {
534+ case ':' , ';' :
535+ name = format [i :]
536+ i = N
537+ case '$' :
538+ kwOnly_i = len (ops )
539+ case '|' :
519540 min = len (ops )
520541 default :
521542 ops = append (ops , op )
522543 }
523544 }
524- max = len (ops )
525545 if min < 0 {
526- min = max
546+ min = len ( ops )
527547 }
528548 return
529549}
0 commit comments