Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1366)

Side by Side Diff: src/pkg/try/try.go

Issue 5246054: code review 5246054: try: delete (Closed)
Patch Set: diff -r c793d12e34c9 https://go.googlecode.com/hg/ Created 13 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pkg/try/Makefile ('k') | src/pkg/try/try_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 []interfa ce{}) {
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 cons truction)
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 poten tial
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.ValueOf(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.ValueOf(fn)
94 typ := rfn.Type()
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.Type, rfn reflect.Va lue, 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.ValueOf(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 typ.Kind() == reflect.Interface {
170 return true
171 }
172 }
173 return false
174 }
OLDNEW
« no previous file with comments | « src/pkg/try/Makefile ('k') | src/pkg/try/try_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b