|
1 | 1 | // Argument parsing for Go functions called by python
|
2 |
| - |
3 |
| -package py |
4 |
| - |
5 |
| -import ( |
6 |
| - "fmt" |
7 |
| -) |
8 |
| - |
| 2 | +// |
9 | 3 | // These functions are useful when creating your own extensions
|
10 | 4 | // functions and methods. Additional information and examples are
|
11 | 5 | // available
10000
in Extending and Embedding the Python Interpreter.
|
@@ -406,51 +400,121 @@ import (
|
406 | 400 | // to conversion failure in one of the format units, the variables at
|
407 | 401 | // the addresses corresponding to that and the following format units
|
408 | 402 | // are left untouched.
|
| 403 | + |
| 404 | +package py |
| 405 | + |
| 406 | +import ( |
| 407 | + "fmt" |
| 408 | +) |
| 409 | + |
| 410 | +// ParseTupleAndKeywords |
409 | 411 | func ParseTupleAndKeywords(args Tuple, kwargs StringDict, format string, kwlist []string, results ...*Object) {
|
410 |
| - // name := "function" |
411 |
| - // for format != "" { |
412 |
| - // op = format[0] |
413 |
| - // format = format[1:] |
414 |
| - // if len(format) > 1 && (format[1] == '*' || format[1] == '#') { |
415 |
| - // op += format[0] |
416 |
| - // format = format[1:] |
417 |
| - // } |
418 |
| - // switch format { |
419 |
| - // case "O": |
420 |
| - // case "|": |
421 |
| - // case ":": |
422 |
| - // name = format |
423 |
| - // format = "" |
424 |
| - // default: |
425 |
| - // panic(fmt.Sprintf("Unknown/Unimplemented format character %q in ParseTupleAndKeywords", op)) |
426 |
| - // } |
427 |
| - // } |
| 412 | + if len(results) != len(kwlist) { |
| 413 | + panic("Internal error: supply the same number of results and kwlist") |
| 414 | + } |
| 415 | + min, max, name, ops := parseFormat(format) |
| 416 | + checkNumberOfArgs(name, len(args)+len(kwargs), min, max, len(results)) |
| 417 | + |
| 418 | + // Check all the kwargs are in kwlist |
| 419 | + // O(N^2) Slow but kwlist is usually short |
| 420 | + for kwargName := range kwargs { |
| 421 | + for _, kw := range kwlist { |
| 422 | + if kw == kwargName { |
| 423 | + goto found |
| 424 | + } |
| 425 | + } |
| 426 | + panic(fmt.Sprintf("TypeError: %s() got an unexpected keyword argument '%s'", name, kwargName)) |
| 427 | + found: |
| 428 | + } |
| 429 | + |
| 430 | + // Create args tuple with all the arguments we have in |
| 431 | + args = args.Copy() |
| 432 | + for i, kw := range kwlist { |
| 433 | + if value, ok := kwargs[kw]; ok { |
| 434 | + if len(args) >= i { |
| 435 | + // FIXME type error |
| 436 | + panic(fmt.Sprintf("TypeError: %s() got multiple values for argument '%s'", name, kw)) |
| 437 | + } |
| 438 | + args = append(args, value) |
| 439 | + } |
| 440 | + |
| 441 | + } |
| 442 | + |
| 443 | + for i, arg := range args { |
| 444 | + op := ops[i] |
| 445 | + result := results[i] |
| 446 | + switch op { |
| 447 | + case "O": |
| 448 | + *result = arg |
| 449 | + case "U": |
| 450 | + if _, ok := arg.(String); !ok { |
| 451 | + // FIXME type error |
| 452 | + panic(fmt.Sprintf("TypeError: %s() argument %d must be str, not %s", name, i+1, arg.Type().Name)) |
| 453 | + } |
| 454 | + *result = arg |
| 455 | + default: |
| 456 | + panic(fmt.Sprintf("Unknown/Unimplemented format character %q in ParseTupleAndKeywords called from %s", op, name)) |
| 457 | + } |
| 458 | + } |
428 | 459 | }
|
429 | 460 |
|
430 |
| -// Unpack the args tuple into the results |
431 |
| -// |
432 |
| -// Up to the caller to set default values |
433 |
| -func UnpackTuple(args Tuple, name string, min int, max int, results ...*Object) { |
434 |
| - // Check number of arguments |
| 461 | +// Parse the format |
| 462 | +func parseFormat(format string) (min, max int, name string, ops []string) { |
| 463 | + name = "function" |
| 464 | + min = -1 |
| 465 | + for format != "" { |
| 466 | + op := string(format[0]) |
| 467 | + format = format[1:] |
| 468 | + if len(format) > 1 && (format[1] == '*' || format[1] == '#') { |
| 469 | + op += string(format[0]) |
| 470 | + format = format[1:] |
| 471 | + } |
| 472 | + switch op { |
| 473 | + case ":", ";": |
| 474 | + name = format |
| 475 | + format = "" |
| 476 | + case "|": |
| 477 | + min = len(ops) |
| 478 | + default: |
| 479 | + ops = append(ops, op) |
| 480 | + } |
| 481 | + } |
| 482 | + max = len(ops) |
| 483 | + if min < 0 { |
| 484 | + min = max |
| 485 | + } |
| 486 | + return |
| 487 | +} |
| 488 | + |
| 489 | +// Checks the number of args passed in |
| 490 | +func checkNumberOfArgs(name string, nargs, nresults, min, max int) { |
435 | 491 | if min == max {
|
436 |
| - if len(args) != max { |
| 492 | + if nargs != max { |
437 | 493 | // FIXME type error
|
438 |
| - panic(fmt.Sprintf("TypeError: %s() takes exactly %d arguments (%d given)", name, max, len(args))) |
| 494 | + panic(fmt.Sprintf("TypeError: %s() takes exactly %d arguments (%d given)", name, max, nargs)) |
439 | 495 | }
|
440 | 496 | } else {
|
441 |
| - if len(args) > max { |
| 497 | + if nargs > max { |
442 | 498 | // FIXME type error
|
443 |
| - panic(fmt.Sprintf("TypeError: %s() takes at most %d arguments (%d given)", name, max, len(args))) |
| 499 | + panic(fmt.Sprintf("TypeError: %s() takes at most %d arguments (%d given)", name, max, nargs)) |
444 | 500 | }
|
445 |
| - if len(args) < min { |
| 501 | + if nargs < min { |
446 | 502 | // FIXME type error
|
447 |
| - panic(fmt.Sprintf("TypeError: %s() takes at least %d arguments (%d given)", name, min, len(args))) |
| 503 | + panic(fmt.Sprintf("TypeError: %s() takes at least %d arguments (%d given)", name, min, nargs)) |
448 | 504 | }
|
449 | 505 | }
|
450 | 506 |
|
451 |
| - if len(args) > len(results) { |
452 |
| - panic("UnpackTuple needs more space") |
| 507 | + if nargs > nresults { |
| 508 | + panic("Internal error: not enough arguments supplied to Unpack*/Parse*") |
453 | 509 | }
|
| 510 | +} |
| 511 | + |
| 512 | +// Unpack the args tuple into the results |
| 513 | +// |
| 514 | +// Up to the caller to set default values |
| 515 | +func UnpackTuple(args Tuple, name string, min int, max int, results ...*Object) { |
| 516 | + // Check number of arguments |
| 517 | + checkNumberOfArgs(name, len(args), min, max, len(results)) |
454 | 518 |
|
455 | 519 | // Copy the results in
|
456 | 520 | for i := range args {
|
|
0 commit comments