8000 Implement ParseTupleAndKeywords · go-python/gpython@9022860 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9022860

Browse files
committed
Implement ParseTupleAndKeywords
1 parent c8a6976 commit 9022860

File tree

1 file changed

+102
-38
lines changed

1 file changed

+102
-38
lines changed

py/args.go

Lines changed: 102 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
// Argument parsing for Go functions called by python
2-
3-
package py
4-
5-
import (
6-
"fmt"
7-
)
8-
2+
//
93
// These functions are useful when creating your own extensions
104
// functions and methods. Additional information and examples are
115
// available 10000 in Extending and Embedding the Python Interpreter.
@@ -406,51 +400,121 @@ import (
406400
// to conversion failure in one of the format units, the variables at
407401
// the addresses corresponding to that and the following format units
408402
// are left untouched.
403+
404+
package py
405+
406+
import (
407+
"fmt"
408+
)
409+
410+
// ParseTupleAndKeywords
409411
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+
}
428459
}
429460

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) {
435491
if min == max {
436-
if len(args) != max {
492+
if nargs != max {
437493
// 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))
439495
}
440496
} else {
441-
if len(args) > max {
497+
if nargs > max {
442498
// 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))
444500
}
445-
if len(args) < min {
501+
if nargs < min {
446502
// 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))
448504
}
449505
}
450506

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*")
453509
}
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))
454518

455519
// Copy the results in
456520
for i := range args {

0 commit comments

Comments
 (0)
0