From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libgo/go/try/try.go | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 libgo/go/try/try.go (limited to 'libgo/go/try/try.go') diff --git a/libgo/go/try/try.go b/libgo/go/try/try.go new file mode 100644 index 000000000..af31d0d2c --- /dev/null +++ b/libgo/go/try/try.go @@ -0,0 +1,174 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package try contains the executable part of the gotry command. +// It is not intended for general use. +package try + +import ( + "fmt" + "io" + "os" + "reflect" + "unicode" +) + +var output io.Writer = os.Stdout // redirected when testing + +// Main is called directly from the gotry-generated Go source file to perform +// the evaluations. +func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) { + switch len(args) { + case 0: + // Nothing to do. + case 1: + // Compiler has already evaluated the expression; just print the result. + printSlice(firstArg, args) + default: + // See if methods satisfy the expressions. + tryMethods(pkg, firstArg, args) + // See if functions satisfy the expressions. + for name, fn := range functions { + tryFunction(pkg, name, fn, args) + } + } +} + +// printSlice prints the zeroth element of the args slice, which should (by construction) +// itself be a slice of interface{}. +func printSlice(firstArg string, args []interface{}) { + // Args should be length 1 and a slice. + if len(args) != 1 { + return + } + arg, ok := args[0].([]interface{}) + if !ok { + return + } + fmt.Fprintf(output, "%s = ", firstArg) + if len(arg) > 1 { + fmt.Fprint(output, "(") + } + for i, a := range arg { + if i > 0 { + fmt.Fprint(output, ", ") + } + fmt.Fprintf(output, "%#v", a) + } + if len(arg) > 1 { + fmt.Fprint(output, ")") + } + fmt.Fprint(output, "\n") +} + +// tryMethods sees if the zeroth arg has methods, and if so treats them as potential +// functions to satisfy the remaining arguments. +func tryMethods(pkg, firstArg string, args []interface{}) { + defer func() { recover() }() + // Is the first argument something with methods? + v := reflect.NewValue(args[0]) + typ := v.Type() + if typ.NumMethod() == 0 { + return + } + for i := 0; i < typ.NumMethod(); i++ { + if unicode.IsUpper(int(typ.Method(i).Name[0])) { + tryMethod(pkg, firstArg, typ.Method(i), args) + } + } +} + +// tryMethod converts a method to a function for tryOneFunction. +func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) { + rfn := method.Func + typ := method.Type + name := method.Name + tryOneFunction(pkg, firstArg, name, typ, rfn, args) +} + +// tryFunction sees if fn satisfies the arguments. +func tryFunction(pkg, name string, fn interface{}, args []interface{}) { + defer func() { recover() }() + rfn := reflect.NewValue(fn).(*reflect.FuncValue) + typ := rfn.Type().(*reflect.FuncType) + tryOneFunction(pkg, "", name, typ, rfn, args) +} + +// tryOneFunction is the common code for tryMethod and tryFunction. +func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) { + // Any results? + if typ.NumOut() == 0 { + return // Nothing to do. + } + // Right number of arguments + results? + if typ.NumIn()+typ.NumOut() != len(args) { + return + } + // Right argument and result types? + for i, a := range args { + if i < typ.NumIn() { + if !compatible(a, typ.In(i)) { + return + } + } else { + if !compatible(a, typ.Out(i-typ.NumIn())) { + return + } + } + } + // Build the call args. + argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut()) + for i, a := range args { + argsVal[i] = reflect.NewValue(a) + } + // Call the function and see if the results are as expected. + resultVal := rfn.Call(argsVal[:typ.NumIn()]) + for i, v := range resultVal { + if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) { + return + } + } + // Present the result including a godoc command to get more information. + firstIndex := 0 + if firstArg != "" { + fmt.Fprintf(output, "%s.%s(", firstArg, name) + firstIndex = 1 + } else { + fmt.Fprintf(output, "%s.%s(", pkg, name) + } + for i := firstIndex; i < typ.NumIn(); i++ { + if i > firstIndex { + fmt.Fprint(output, ", ") + } + fmt.Fprintf(output, "%#v", args[i]) + } + fmt.Fprint(output, ") = ") + if typ.NumOut() > 1 { + fmt.Fprint(output, "(") + } + for i := 0; i < typ.NumOut(); i++ { + if i > 0 { + fmt.Fprint(output, ", ") + } + fmt.Fprintf(output, "%#v", resultVal[i].Interface()) + } + if typ.NumOut() > 1 { + fmt.Fprint(output, ")") + } + fmt.Fprintf(output, " // godoc %s %s\n", pkg, name) +} + +// compatible reports whether the argument is compatible with the type. +func compatible(arg interface{}, typ reflect.Type) bool { + if reflect.Typeof(arg) == typ { + return true + } + if arg == nil { + // nil is OK if the type is an interface. + if _, ok := typ.(*reflect.InterfaceType); ok { + return true + } + } + return false +} -- cgit v1.2.3