OSDN Git Service

Add Go frontend, libgo library, and Go testsuite.
[pf3gnuchains/gcc-fork.git] / libgo / go / try / try.go
1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package try contains the executable part of the gotry command.
6 // It is not intended for general use.
7 package try
8
9 import (
10         "fmt"
11         "io"
12         "os"
13         "reflect"
14         "unicode"
15 )
16
17 var output io.Writer = os.Stdout // redirected when testing
18
19 // Main is called directly from the gotry-generated Go source file to perform
20 // the evaluations.
21 func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) {
22         switch len(args) {
23         case 0:
24                 // Nothing to do.
25         case 1:
26                 // Compiler has already evaluated the expression; just print the result.
27                 printSlice(firstArg, args)
28         default:
29                 // See if methods satisfy the expressions.
30                 tryMethods(pkg, firstArg, args)
31                 // See if functions satisfy the expressions.
32                 for name, fn := range functions {
33                         tryFunction(pkg, name, fn, args)
34                 }
35         }
36 }
37
38 // printSlice prints the zeroth element of the args slice, which should (by construction)
39 // itself be a slice of interface{}.
40 func printSlice(firstArg string, args []interface{}) {
41         // Args should be length 1 and a slice.
42         if len(args) != 1 {
43                 return
44         }
45         arg, ok := args[0].([]interface{})
46         if !ok {
47                 return
48         }
49         fmt.Fprintf(output, "%s = ", firstArg)
50         if len(arg) > 1 {
51                 fmt.Fprint(output, "(")
52         }
53         for i, a := range arg {
54                 if i > 0 {
55                         fmt.Fprint(output, ", ")
56                 }
57                 fmt.Fprintf(output, "%#v", a)
58         }
59         if len(arg) > 1 {
60                 fmt.Fprint(output, ")")
61         }
62         fmt.Fprint(output, "\n")
63 }
64
65 // tryMethods sees if the zeroth arg has methods, and if so treats them as potential
66 // functions to satisfy the remaining arguments.
67 func tryMethods(pkg, firstArg string, args []interface{}) {
68         defer func() { recover() }()
69         // Is the first argument something with methods?
70         v := reflect.NewValue(args[0])
71         typ := v.Type()
72         if typ.NumMethod() == 0 {
73                 return
74         }
75         for i := 0; i < typ.NumMethod(); i++ {
76                 if unicode.IsUpper(int(typ.Method(i).Name[0])) {
77                         tryMethod(pkg, firstArg, typ.Method(i), args)
78                 }
79         }
80 }
81
82 // tryMethod converts a method to a function for tryOneFunction.
83 func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
84         rfn := method.Func
85         typ := method.Type
86         name := method.Name
87         tryOneFunction(pkg, firstArg, name, typ, rfn, args)
88 }
89
90 // tryFunction sees if fn satisfies the arguments.
91 func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
92         defer func() { recover() }()
93         rfn := reflect.NewValue(fn).(*reflect.FuncValue)
94         typ := rfn.Type().(*reflect.FuncType)
95         tryOneFunction(pkg, "", name, typ, rfn, args)
96 }
97
98 // tryOneFunction is the common code for tryMethod and tryFunction.
99 func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) {
100         // Any results?
101         if typ.NumOut() == 0 {
102                 return // Nothing to do.
103         }
104         // Right number of arguments + results?
105         if typ.NumIn()+typ.NumOut() != len(args) {
106                 return
107         }
108         // Right argument and result types?
109         for i, a := range args {
110                 if i < typ.NumIn() {
111                         if !compatible(a, typ.In(i)) {
112                                 return
113                         }
114                 } else {
115                         if !compatible(a, typ.Out(i-typ.NumIn())) {
116                                 return
117                         }
118                 }
119         }
120         // Build the call args.
121         argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
122         for i, a := range args {
123                 argsVal[i] = reflect.NewValue(a)
124         }
125         // Call the function and see if the results are as expected.
126         resultVal := rfn.Call(argsVal[:typ.NumIn()])
127         for i, v := range resultVal {
128                 if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
129                         return
130                 }
131         }
132         // Present the result including a godoc command to get more information.
133         firstIndex := 0
134         if firstArg != "" {
135                 fmt.Fprintf(output, "%s.%s(", firstArg, name)
136                 firstIndex = 1
137         } else {
138                 fmt.Fprintf(output, "%s.%s(", pkg, name)
139         }
140         for i := firstIndex; i < typ.NumIn(); i++ {
141                 if i > firstIndex {
142                         fmt.Fprint(output, ", ")
143                 }
144                 fmt.Fprintf(output, "%#v", args[i])
145         }
146         fmt.Fprint(output, ") = ")
147         if typ.NumOut() > 1 {
148                 fmt.Fprint(output, "(")
149         }
150         for i := 0; i < typ.NumOut(); i++ {
151                 if i > 0 {
152                         fmt.Fprint(output, ", ")
153                 }
154                 fmt.Fprintf(output, "%#v", resultVal[i].Interface())
155         }
156         if typ.NumOut() > 1 {
157                 fmt.Fprint(output, ")")
158         }
159         fmt.Fprintf(output, "  // godoc %s %s\n", pkg, name)
160 }
161
162 // compatible reports whether the argument is compatible with the type.
163 func compatible(arg interface{}, typ reflect.Type) bool {
164         if reflect.Typeof(arg) == typ {
165                 return true
166         }
167         if arg == nil {
168                 // nil is OK if the type is an interface.
169                 if _, ok := typ.(*reflect.InterfaceType); ok {
170                         return true
171                 }
172         }
173         return false
174 }