├── LICENSE ├── README.md ├── degen ├── api.go ├── conversions.go ├── degen.go └── inst.go ├── examples ├── chanutils │ ├── chanutils.go │ └── out.go ├── list │ ├── list.go │ └── out.go ├── mathutils │ ├── mathutils.go │ └── out.go ├── priorityqueue │ ├── out.go │ └── priorityqueue.go ├── sliceutils │ ├── out.go │ └── sliceutils.go └── syncmap │ ├── out.go │ └── syncmap.go ├── go.mod ├── go ├── ast │ ├── ast.go │ ├── commentmap.go │ ├── filter.go │ ├── import.go │ ├── print.go │ ├── resolve.go │ ├── scope.go │ └── walk.go ├── build │ ├── build.go │ ├── doc.go │ ├── read.go │ ├── syslist.go │ └── zcgo.go ├── constant │ └── value.go ├── doc │ ├── Makefile │ ├── comment.go │ ├── doc.go │ ├── example.go │ ├── exports.go │ ├── filter.go │ ├── headscan.go │ ├── reader.go │ └── synopsis.go ├── format │ ├── format.go │ └── internal.go ├── importer │ └── importer.go ├── internal │ ├── gccgoimporter │ │ ├── ar.go │ │ ├── gccgoinstallation.go │ │ ├── gccgoinstallation_test.go │ │ ├── importer.go │ │ ├── importer_test.go │ │ ├── parser.go │ │ ├── parser_test.go │ │ └── testdata │ │ │ ├── aliases.go │ │ │ ├── aliases.gox │ │ │ ├── complexnums.go │ │ │ ├── complexnums.gox │ │ │ ├── conversions.go │ │ │ ├── conversions.gox │ │ │ ├── escapeinfo.go │ │ │ ├── escapeinfo.gox │ │ │ ├── imports.go │ │ │ ├── imports.gox │ │ │ ├── issue27856.go │ │ │ ├── issue27856.gox │ │ │ ├── issue29198.go │ │ │ ├── issue29198.gox │ │ │ ├── libimportsar.a │ │ │ ├── nointerface.go │ │ │ ├── nointerface.gox │ │ │ ├── pointer.go │ │ │ ├── pointer.gox │ │ │ ├── time.gox │ │ │ ├── unicode.gox │ │ │ └── v1reflect.gox │ ├── gcimporter │ │ ├── bimport.go │ │ ├── exportdata.go │ │ ├── gcimporter.go │ │ ├── gcimporter_test.go │ │ ├── iimport.go │ │ └── testdata │ │ │ ├── a.go │ │ │ ├── b.go │ │ │ ├── exports.go │ │ │ ├── issue15920.go │ │ │ ├── issue20046.go │ │ │ ├── issue25301.go │ │ │ ├── issue25596.go │ │ │ ├── p.go │ │ │ └── versions │ │ │ ├── test.go │ │ │ ├── test_go1.11_0i.a │ │ │ ├── test_go1.11_6b.a │ │ │ ├── test_go1.11_999b.a │ │ │ ├── test_go1.11_999i.a │ │ │ ├── test_go1.7_0.a │ │ │ ├── test_go1.7_1.a │ │ │ ├── test_go1.8_4.a │ │ │ └── test_go1.8_5.a │ ├── srcimporter │ │ ├── srcimporter.go │ │ ├── srcimporter_test.go │ │ └── testdata │ │ │ ├── issue20855 │ │ │ └── issue20855.go │ │ │ ├── issue23092 │ │ │ └── issue23092.go │ │ │ └── issue24392 │ │ │ └── issue24392.go │ └── xcoff │ │ ├── ar.go │ │ ├── ar_test.go │ │ ├── file.go │ │ ├── file_test.go │ │ ├── testdata │ │ ├── bigar-empty │ │ ├── bigar-ppc64 │ │ ├── gcc-ppc32-aix-dwarf2-exec │ │ ├── gcc-ppc64-aix-dwarf2-exec │ │ ├── hello.c │ │ ├── printbye.c │ │ └── printhello.c │ │ └── xcoff.go ├── parser │ ├── interface.go │ └── parser.go ├── printer │ ├── nodes.go │ └── printer.go ├── scanner │ ├── errors.go │ └── scanner.go ├── token │ ├── position.go │ ├── serialize.go │ └── token.go └── types │ ├── api.go │ ├── assignments.go │ ├── builtins.go │ ├── call.go │ ├── check.go │ ├── conversions.go │ ├── decl.go │ ├── errors.go │ ├── eval.go │ ├── expr.go │ ├── exprstring.go │ ├── gotype.go │ ├── initorder.go │ ├── labels.go │ ├── lookup.go │ ├── methodset.go │ ├── object.go │ ├── objset.go │ ├── operand.go │ ├── ordering.go │ ├── package.go │ ├── predicates.go │ ├── resolver.go │ ├── return.go │ ├── scope.go │ ├── selection.go │ ├── sizes.go │ ├── stmt.go │ ├── type.go │ ├── typestring.go │ ├── typexpr.go │ └── universe.go └── main.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Michal Štrba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /degen/api.go: -------------------------------------------------------------------------------- 1 | package degen 2 | 3 | import ( 4 | "fmt" 5 | "github.com/faiface/generics/go/ast" 6 | "github.com/faiface/generics/go/importer" 7 | "github.com/faiface/generics/go/token" 8 | "github.com/faiface/generics/go/types" 9 | ) 10 | 11 | func Degen(fset *token.FileSet, input *ast.File, debug bool) (output *ast.File, changed bool) { 12 | typesCfg := &types.Config{ 13 | Importer: importer.Default(), 14 | } 15 | info := &types.Info{ 16 | Types: make(map[ast.Expr]types.TypeAndValue), 17 | Defs: make(map[*ast.Ident]types.Object), 18 | Uses: make(map[*ast.Ident]types.Object), 19 | GenericCalls: make(map[*ast.CallExpr]*types.GenericCall), 20 | GenericInstances: make(map[*ast.CallExpr]*types.GenericInstance), 21 | } 22 | _, err := typesCfg.Check("", fset, []*ast.File{input}, info) 23 | if err != nil && debug { 24 | fmt.Println(err) 25 | } 26 | 27 | output = &ast.File{ 28 | Name: input.Name, 29 | Imports: input.Imports, 30 | } 31 | 32 | cfg := &config{ 33 | info: info, 34 | instantiated: make(map[string]bool), 35 | input: input, 36 | output: output, 37 | } 38 | 39 | for _, decl := range input.Decls { 40 | switch decl := decl.(type) { 41 | case *ast.FuncDecl: 42 | if decl.Recv.NumFields() == 0 { 43 | cfg.instantiated[decl.Name.Name] = true 44 | } 45 | case *ast.GenDecl: 46 | for _, spec := range decl.Specs { 47 | switch spec := spec.(type) { 48 | case *ast.TypeSpec: 49 | cfg.instantiated[spec.Name.Name] = true 50 | } 51 | } 52 | } 53 | } 54 | 55 | for _, decl := range input.Decls { 56 | switch decl := decl.(type) { 57 | case *ast.FuncDecl: 58 | if len(decl.TypeParams) > 0 { 59 | output.Decls = append(output.Decls, decl) 60 | continue 61 | } 62 | changed = degenFuncDecl(cfg, decl) || changed 63 | 64 | case *ast.GenDecl: 65 | if decl.Tok != token.TYPE { 66 | output.Decls = append(output.Decls, decl) 67 | continue 68 | } 69 | 70 | for _, spec := range decl.Specs { 71 | spec := spec.(*ast.TypeSpec) 72 | 73 | if len(spec.Params) > 0 { 74 | output.Decls = append(output.Decls, decl) 75 | continue 76 | } 77 | 78 | changed = degenTypeSpec(cfg, spec) || changed 79 | } 80 | 81 | default: 82 | output.Decls = append(output.Decls, decl) 83 | } 84 | } 85 | 86 | return output, changed 87 | } 88 | 89 | type config struct { 90 | info *types.Info 91 | instantiated map[string]bool 92 | input *ast.File 93 | output *ast.File 94 | } 95 | -------------------------------------------------------------------------------- /degen/conversions.go: -------------------------------------------------------------------------------- 1 | package degen 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "github.com/faiface/generics/go/ast" 7 | "github.com/faiface/generics/go/token" 8 | "github.com/faiface/generics/go/types" 9 | ) 10 | 11 | func tupleToFieldList(t *types.Tuple) *ast.FieldList { 12 | var fields ast.FieldList 13 | for i := 0; i < t.Len(); i++ { 14 | v := t.At(i) 15 | field := &ast.Field{ 16 | Type: typeToExpr(v.Type()), 17 | } 18 | if v.Name() != "" { 19 | field.Names = []*ast.Ident{{Name: v.Name()}} 20 | } 21 | fields.List = append(fields.List, field) 22 | } 23 | return &fields 24 | } 25 | 26 | func typeToExpr(t types.Type) ast.Expr { 27 | switch t := t.(type) { 28 | case nil: 29 | return &ast.BadExpr{} 30 | 31 | case *types.Basic: 32 | return &ast.Ident{ 33 | Name: t.Name(), 34 | } 35 | 36 | case *types.Array: 37 | return &ast.ArrayType{ 38 | Len: &ast.BasicLit{ 39 | Kind: token.INT, 40 | Value: fmt.Sprint(t.Len()), 41 | }, 42 | Elt: typeToExpr(t.Elem()), 43 | } 44 | 45 | case *types.Slice: 46 | return &ast.ArrayType{ 47 | Elt: typeToExpr(t.Elem()), 48 | } 49 | 50 | case *types.Struct: 51 | var fields ast.FieldList 52 | for i := 0; i < t.NumFields(); i++ { 53 | v := t.Field(i) 54 | field := &ast.Field{ 55 | Type: typeToExpr(v.Type()), 56 | } 57 | if v.Name() != "" { 58 | field.Names = []*ast.Ident{{Name: v.Name()}} 59 | } 60 | fields.List = append(fields.List, field) 61 | } 62 | return &ast.StructType{ 63 | Fields: &fields, 64 | } 65 | 66 | case *types.Pointer: 67 | return &ast.StarExpr{ 68 | X: typeToExpr(t.Elem()), 69 | } 70 | 71 | case *types.Tuple: 72 | return &ast.BadExpr{} 73 | 74 | case *types.Signature: 75 | if len(t.TypeParams()) > 0 { 76 | return &ast.BadExpr{} 77 | } 78 | return &ast.FuncType{ 79 | Params: tupleToFieldList(t.Params()), 80 | Results: tupleToFieldList(t.Results()), 81 | } 82 | 83 | case *types.Interface: 84 | var methods ast.FieldList 85 | for i := 0; i < t.NumMethods(); i++ { 86 | meth := t.Method(i) 87 | methods.List = append(methods.List, &ast.Field{ 88 | Names: []*ast.Ident{{Name: meth.Name()}}, 89 | Type: typeToExpr(meth.Type()), 90 | }) 91 | } 92 | return &ast.InterfaceType{ 93 | Methods: &methods, 94 | } 95 | 96 | case *types.Map: 97 | return &ast.MapType{ 98 | Key: typeToExpr(t.Key()), 99 | Value: typeToExpr(t.Elem()), 100 | } 101 | 102 | case *types.Chan: 103 | dir := map[types.ChanDir]ast.ChanDir{ 104 | types.SendRecv: ast.SEND | ast.RECV, 105 | types.SendOnly: ast.SEND, 106 | types.RecvOnly: ast.RECV, 107 | } 108 | return &ast.ChanType{ 109 | Dir: dir[t.Dir()], 110 | Value: typeToExpr(t.Elem()), 111 | } 112 | 113 | case *types.Named: 114 | return &ast.Ident{ 115 | Name: t.Obj().Name(), 116 | } 117 | 118 | case *types.TypeParam: 119 | return &ast.BadExpr{} 120 | 121 | default: 122 | return &ast.BadExpr{} 123 | } 124 | } 125 | 126 | func writeType(w io.Writer, t types.Type) { 127 | switch t := t.(type) { 128 | case nil: 129 | fmt.Fprintf(w, "bad") 130 | 131 | case *types.Basic: 132 | fmt.Fprintf(w, "%s", t.Name()) 133 | 134 | case *types.Array: 135 | fmt.Fprintf(w, "array_%d_", t.Len()) 136 | writeType(w, t.Elem()) 137 | 138 | case *types.Slice: 139 | fmt.Fprintf(w, "slice_") 140 | writeType(w, t.Elem()) 141 | 142 | case *types.Struct: 143 | fmt.Fprint(w, "struct_") 144 | for i := 0; i < t.NumFields(); i++ { 145 | field := t.Field(i) 146 | fmt.Fprintf(w, "%s_", field.Name()) 147 | writeType(w, field.Type()) 148 | fmt.Fprintf(w, "_") 149 | } 150 | fmt.Fprintf(w, "end") 151 | 152 | case *types.Pointer: 153 | fmt.Fprintf(w, "ptr_") 154 | writeType(w, t.Elem()) 155 | 156 | case *types.Tuple: 157 | fmt.Fprintf(w, "bad") 158 | 159 | case *types.Signature: 160 | if len(t.TypeParams()) > 0 { 161 | fmt.Fprintf(w, "bad") 162 | return 163 | } 164 | fmt.Fprint(w, "func_") 165 | for i := 0; i < t.Params().Len(); i++ { 166 | param := t.Params().At(i) 167 | writeType(w, param.Type()) 168 | fmt.Fprintf(w, "_") 169 | } 170 | fmt.Fprint(w, "to_") 171 | for i := 0; i < t.Results().Len(); i++ { 172 | result := t.Results().At(i) 173 | writeType(w, result.Type()) 174 | fmt.Fprintf(w, "_") 175 | } 176 | fmt.Fprintf(w, "end") 177 | 178 | case *types.Interface: 179 | fmt.Fprintf(w, "interface_") 180 | for i := 0; i < t.NumMethods(); i++ { 181 | meth := t.Method(i) 182 | fmt.Fprintf(w, "%s_", meth.Name()) 183 | writeType(w, meth.Type()) 184 | fmt.Fprintf(w, "_") 185 | } 186 | fmt.Fprintf(w, "end") 187 | 188 | case *types.Map: 189 | fmt.Fprintf(w, "map_") 190 | writeType(w, t.Key()) 191 | fmt.Fprintf(w, "_") 192 | writeType(w, t.Elem()) 193 | 194 | case *types.Chan: 195 | dir := map[types.ChanDir]string{ 196 | types.SendRecv: "both", 197 | types.SendOnly: "send", 198 | types.RecvOnly: "recv", 199 | } 200 | fmt.Fprintf(w, "chan_%s_", dir[t.Dir()]) 201 | writeType(w, t.Elem()) 202 | 203 | case *types.Named: 204 | fmt.Fprintf(w, "%s", t.Obj().Name()) 205 | 206 | case *types.TypeParam: 207 | fmt.Fprintf(w, "bad") 208 | 209 | default: 210 | fmt.Fprintf(w, "bad") 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /examples/chanutils/chanutils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Elems returns a channel that streams all the supplied elements one by one. 6 | func Elems(a ...type T) <-chan T { 7 | ch := make(chan T) 8 | go func() { 9 | for _, x := range a { 10 | ch <- x 11 | } 12 | close(ch) 13 | }() 14 | return ch 15 | } 16 | 17 | // Pipe redirects all the data from one channel to another one. 18 | func Pipe(from <-chan type T, to chan<- T) { 19 | for x := range from { 20 | to <- x 21 | } 22 | close(to) 23 | } 24 | 25 | // Map transforms a channel of type T into a channel of type U by transforming each of the 26 | // values sent on the channel using the supplied function. 27 | func Map(in <-chan type T, f func(T) type U) <-chan U { 28 | out := make(chan U) 29 | go func() { 30 | for x := range in { 31 | out <- f(x) 32 | } 33 | close(out) 34 | }() 35 | return out 36 | } 37 | 38 | // Merge merges all the supplied channels into a single channel. Any value sent by any of 39 | // the original channels will appear on the merged channel. The returned channel gets closed when 40 | // all of the supplied channels get closed. 41 | func Merge(chans ...<-chan type T) <-chan T { 42 | merged := make(chan T) 43 | done := make(chan bool) 44 | 45 | for _, ch := range chans { 46 | ch := ch 47 | go func() { 48 | for x := range ch { 49 | merged <- x 50 | } 51 | done <- true 52 | }() 53 | } 54 | 55 | go func() { 56 | for range chans { 57 | <-done 58 | } 59 | close(merged) 60 | }() 61 | 62 | return merged 63 | } 64 | 65 | func main() { 66 | letters := Elems("A", "B", "C", "D", "E") 67 | numbers := Elems(1, 2, 3, 4, 5) 68 | 69 | everything := Merge(letters, Map(numbers, func(x int) string { 70 | return fmt.Sprint(x) 71 | })) 72 | 73 | for s := range everything { 74 | fmt.Println(s) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /examples/chanutils/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Elems_string(a ...string) <-chan string { 6 | ch := make(chan string) 7 | go func() { 8 | for _, x := range a { 9 | ch <- x 10 | } 11 | 12 | close(ch) 13 | }() 14 | return ch 15 | } 16 | 17 | func Elems_int(a ...int) <-chan int { 18 | ch := make(chan int) 19 | go func() { 20 | for _, x := range a { 21 | ch <- x 22 | } 23 | 24 | close(ch) 25 | }() 26 | return ch 27 | } 28 | 29 | func Map_int_string(in <-chan int, f func(int) string) <-chan string { 30 | out := make(chan string) 31 | go func() { 32 | for x := range in { 33 | out <- f(x) 34 | } 35 | 36 | close(out) 37 | }() 38 | return out 39 | } 40 | 41 | func Merge_string(chans ...<-chan string) <-chan string { 42 | merged := make(chan string) 43 | done := make(chan bool) 44 | for _, ch := range chans { 45 | ch := ch 46 | go func() { 47 | for x := range ch { 48 | merged <- x 49 | } 50 | 51 | done <- true 52 | }() 53 | } 54 | go func() { 55 | for range chans { 56 | <-done 57 | } 58 | 59 | close(merged) 60 | }() 61 | return merged 62 | } 63 | func main() { 64 | letters := Elems_string("A", "B", "C", "D", "E") 65 | numbers := Elems_int(1, 2, 3, 4, 5) 66 | 67 | everything := Merge_string(letters, Map_int_string(numbers, func(x int) string { return fmt.Sprint(x) })) 68 | for s := range everything { 69 | fmt.Println(s) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /examples/list/list.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | // List is a generic singly-linked list. Just like in LISP. 9 | type List(type T) struct { 10 | First T 11 | Rest *List(T) 12 | } 13 | 14 | // Empty returns an empty list of type T. 15 | func Empty(type T) *List(T) { 16 | return nil 17 | } 18 | 19 | // Prepend returns a new list with x prepended before l. 20 | func (l *List(type T)) Prepend(x T) *List(T) { 21 | return &List(T){ 22 | First: x, 23 | Rest: l, 24 | } 25 | } 26 | 27 | // Elems constructs a linked list containing the given elements. 28 | func Elems(xs ...type T) *List(T) { 29 | list := Empty(T) 30 | for i := len(xs)-1; i >= 0; i-- { 31 | list = list.Prepend(xs[i]) 32 | } 33 | return list 34 | } 35 | 36 | // Empty returns whether l is an empty list. 37 | func (l *List(type T)) Empty() bool { 38 | return l == nil 39 | } 40 | 41 | // Slice collects all elements from the list into a slice. 42 | func (l *List(type T)) Slice() []T { 43 | var elems []T 44 | for !l.Empty() { 45 | elems = append(elems, l.First) 46 | l = l.Rest 47 | } 48 | return elems 49 | } 50 | 51 | // Map returns a new list where each element from the original list is transformed by f. 52 | func Map(l *List(type T), f func(T) type U) *List(U) { 53 | if l.Empty() { 54 | return Empty(U) 55 | } 56 | return Map(l.Rest, f).Prepend(f(l.First)) 57 | } 58 | 59 | func main() { 60 | list1 := Elems(1.0, 4.0, 9.0, 16.0) 61 | list2 := Map(list1, math.Sqrt) 62 | fmt.Println(list2.Slice()) 63 | } 64 | -------------------------------------------------------------------------------- /examples/list/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | ) 7 | 8 | type List_float64 struct { 9 | First float64 10 | Rest *List_float64 11 | } 12 | 13 | func (l *List_float64) Prepend(x float64) *List_float64 { 14 | return &List_float64{First: x, 15 | Rest: l} 16 | } 17 | func (l *List_float64) Empty() bool { 18 | return l == nil 19 | } 20 | func (l *List_float64) Slice() []float64 { 21 | var elems []float64 22 | for !l.Empty() { 23 | elems = append(elems, l.First) 24 | l = l.Rest 25 | } 26 | return elems 27 | } 28 | func Empty_float64() *List_float64 { 29 | return nil 30 | } 31 | 32 | func Elems_float64(xs ...float64) *List_float64 { 33 | list := Empty_float64() 34 | for i := len(xs) - 1; i >= 0; i-- { 35 | list = list.Prepend(xs[i]) 36 | } 37 | return list 38 | } 39 | 40 | func Map_float64_float64(l *List_float64, f func(float64) float64) *List_float64 { 41 | if l.Empty() { 42 | return Empty_float64() 43 | } 44 | return Map_float64_float64(l.Rest, f).Prepend(f(l.First)) 45 | } 46 | func main() { 47 | list1 := Elems_float64(1.0, 4.0, 9.0, 16.0) 48 | list2 := Map_float64_float64(list1, math.Sqrt) 49 | fmt.Println(list2.Slice()) 50 | } 51 | -------------------------------------------------------------------------------- /examples/mathutils/mathutils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Min returns the smaller one of the two. 6 | func Min(x, y type T ord) T { 7 | if x < y { 8 | return x 9 | } 10 | return y 11 | } 12 | 13 | // Max returns the bigger one of the two. 14 | func Max(x, y type T ord) T { 15 | if x > y { 16 | return x 17 | } 18 | return y 19 | } 20 | 21 | // Sum returns the sum of the numbers. 22 | func Sum(nums ...type T num) T { 23 | result := T(0) 24 | for _, x := range nums { 25 | result += x 26 | } 27 | return result 28 | } 29 | 30 | // Product returns the product of the numbers. 31 | func Product(nums ...type T num) T { 32 | result := T(1) 33 | for _, x := range nums { 34 | result *= x 35 | } 36 | return result 37 | } 38 | 39 | func main() { 40 | fmt.Println(Min(7, 9)) 41 | fmt.Println(Min(int32(10), 93)) 42 | fmt.Println(Max(3.14, 31.4)) 43 | fmt.Println(Max("A", "B")) 44 | 45 | fmt.Println(Sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 46 | fmt.Println(Product(1, 2, 3, 4, 5)) 47 | 48 | bytes := ([]byte)("Hello, world!") 49 | fmt.Println(Sum(bytes...)) 50 | } 51 | -------------------------------------------------------------------------------- /examples/mathutils/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func Min_int(x, y int) int { 6 | if x < y { 7 | return x 8 | } 9 | return y 10 | } 11 | 12 | func Min_int32(x, y int32) int32 { 13 | if x < y { 14 | return x 15 | } 16 | return y 17 | } 18 | 19 | func Max_float64(x, y float64) float64 { 20 | if x > y { 21 | return x 22 | } 23 | return y 24 | } 25 | 26 | func Max_string(x, y string) string { 27 | if x > y { 28 | return x 29 | } 30 | return y 31 | } 32 | 33 | func Sum_int(nums ...int) int { 34 | result := int(0) 35 | for _, x := range nums { 36 | result += x 37 | } 38 | return result 39 | } 40 | 41 | func Product_int(nums ...int) int { 42 | result := int(1) 43 | for _, x := range nums { 44 | result *= x 45 | } 46 | return result 47 | } 48 | 49 | func Sum_byte(nums ...byte) byte { 50 | result := byte(0) 51 | for _, x := range nums { 52 | result += x 53 | } 54 | return result 55 | } 56 | func main() { 57 | fmt.Println(Min_int(7, 9)) 58 | fmt.Println(Min_int32(int32(10), 93)) 59 | fmt.Println(Max_float64(3.14, 31.4)) 60 | fmt.Println(Max_string("A", "B")) 61 | 62 | fmt.Println(Sum_int(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 63 | fmt.Println(Product_int(1, 2, 3, 4, 5)) 64 | 65 | bytes := ([]byte)("Hello, world!") 66 | fmt.Println(Sum_byte(bytes...)) 67 | } 68 | -------------------------------------------------------------------------------- /examples/priorityqueue/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Person struct { 6 | name string 7 | age int 8 | } 9 | 10 | func (p Person) String() string { 11 | return fmt.Sprintf("%s is %d years old", p.name, p.age) 12 | } 13 | func (p Person) Name() string { 14 | return p.name 15 | } 16 | func (p Person) Age() int { 17 | return p.age 18 | } 19 | func Min_int() func(int, int) bool { 20 | return func(x, y int) bool { return x < y } 21 | } 22 | 23 | type Heap_int struct { 24 | elems []int 25 | less func(int, int) bool 26 | } 27 | 28 | func (h *Heap_int) Size() int { 29 | return len(h.elems) 30 | } 31 | 32 | func (h *Heap_int) Push(x int) { 33 | h.elems = append(h.elems, x) 34 | j := len(h.elems) - 1 35 | for { 36 | 37 | i := (j - 1) / 2 38 | if i == j || !h.less(h.elems[j], h.elems[i]) { 39 | break 40 | } 41 | 42 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 43 | j = i 44 | } 45 | } 46 | func (h *Heap_int) Top() (top int, ok bool) { 47 | if len(h.elems) == 0 { 48 | ok = false 49 | return 50 | } 51 | return h.elems[0], true 52 | } 53 | func (h *Heap_int) Pop() (top int, ok bool) { 54 | if len(h.elems) == 0 { 55 | ok = false 56 | return 57 | } 58 | 59 | n := len(h.elems) - 1 60 | h.elems[0], h.elems[n] = h.elems[n], h.elems[0] 61 | i := 0 62 | for { 63 | 64 | j1 := 2*i + 1 65 | if j1 >= n || j1 < 0 { 66 | break 67 | } 68 | 69 | j := j1 70 | if j2 := j1 + 1; j2 < n && h.less(h.elems[j2], h.elems[j1]) { 71 | j = j2 72 | } 73 | if !h.less(h.elems[j], h.elems[i]) { 74 | break 75 | } 76 | 77 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 78 | i = j 79 | } 80 | 81 | top = h.elems[n] 82 | h.elems = h.elems[:n] 83 | return top, true 84 | } 85 | 86 | func NewHeap_int(less func(x, y int) bool) *Heap_int { return &Heap_int{less: less} } 87 | 88 | func MaxBy_int_Person(by func(Person) int) func(Person, Person) bool { 89 | return func(x, y Person) bool { return by(x) > by(y) } 90 | } 91 | 92 | type Heap_Person struct { 93 | elems []Person 94 | less func(Person, Person) bool 95 | } 96 | 97 | func (h *Heap_Person) Size() int { 98 | return len(h.elems) 99 | } 100 | 101 | func (h *Heap_Person) Push(x Person) { 102 | h.elems = append(h.elems, x) 103 | j := len(h.elems) - 1 104 | for { 105 | 106 | i := (j - 1) / 2 107 | if i == j || !h.less(h.elems[j], h.elems[i]) { 108 | break 109 | } 110 | 111 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 112 | j = i 113 | } 114 | } 115 | func (h *Heap_Person) Top() (top Person, ok bool) { 116 | if len(h.elems) == 0 { 117 | ok = false 118 | return 119 | } 120 | return h.elems[0], true 121 | } 122 | func (h *Heap_Person) Pop() (top Person, ok bool) { 123 | if len(h.elems) == 0 { 124 | ok = false 125 | return 126 | } 127 | 128 | n := len(h.elems) - 1 129 | h.elems[0], h.elems[n] = h.elems[n], h.elems[0] 130 | i := 0 131 | for { 132 | 133 | j1 := 2*i + 1 134 | if j1 >= n || j1 < 0 { 135 | break 136 | } 137 | 138 | j := j1 139 | if j2 := j1 + 1; j2 < n && h.less(h.elems[j2], h.elems[j1]) { 140 | j = j2 141 | } 142 | if !h.less(h.elems[j], h.elems[i]) { 143 | break 144 | } 145 | 146 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 147 | i = j 148 | } 149 | 150 | top = h.elems[n] 151 | h.elems = h.elems[:n] 152 | return top, true 153 | } 154 | 155 | func NewHeap_Person(less func(x, y Person) bool) *Heap_Person { return &Heap_Person{less: less} } 156 | func main() { 157 | numbers := NewHeap_int(Min_int()) 158 | for x := 10; x >= 1; x-- { 159 | numbers.Push(x) 160 | } 161 | for { 162 | 163 | x, ok := numbers.Pop() 164 | if !ok { 165 | break 166 | } 167 | 168 | fmt.Print(x, " ") 169 | } 170 | 171 | fmt.Println() 172 | 173 | fmt.Println() 174 | 175 | people := NewHeap_Person(MaxBy_int_Person(Person.Age)) 176 | for _, person := range []Person{{"Michal", 23}, {"Viktória", 20}, {"Jano", 21}, {"Martin", 18}} { 177 | 178 | people.Push(person) 179 | } 180 | for { 181 | 182 | p, ok := people.Pop() 183 | if !ok { 184 | break 185 | } 186 | 187 | fmt.Println(p) 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /examples/priorityqueue/priorityqueue.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Heap is a container that lets you add elements into it and provides 6 | // access to the minimal (or maximal) element. 7 | type Heap(type T) struct { 8 | elems []T 9 | less func(T, T) bool 10 | } 11 | 12 | // NewHeap constructs an empty heap container with the specified comparator. 13 | // 14 | // For the usual cases, a comparator can be created using one of the Min, Max, MinBy, and MaxBy functions: 15 | // 16 | // NewHeap(Min(int)) // a minimum heap of ints 17 | // NewHeap(Max(string)) // a maximum heap of strings 18 | // NewHeap(MinBy(Person.Age)) // a minimum heap of Person values that sorts by the results of the Age method 19 | func NewHeap(less func(x, y type T) bool) *Heap(T) { 20 | return &Heap(T){ 21 | less: less, 22 | } 23 | } 24 | 25 | // The following four functions help create comparators. The same thing could (and probably should) 26 | // be used for sorting, because it's very practical. 27 | 28 | // Min returns a comparator for an orderable type T that compares using <. 29 | func Min(type T ord) func(T, T) bool { 30 | return func(x, y T) bool { 31 | return x < y 32 | } 33 | } 34 | 35 | // Max returns a comparator for an oderable type T that compares using >. 36 | func Max(type T ord) func(T, T) bool { 37 | return func(x, y T) bool { 38 | return x > y 39 | } 40 | } 41 | 42 | // MinBy returns a comparator that compares using < based on the results of the provided function. 43 | func MinBy(by func(type T) type O ord) func(T, T) bool { 44 | return func(x, y T) bool { 45 | return by(x) < by(y) 46 | } 47 | } 48 | 49 | // MaxBy returns a comparator that compares using > based on the results of the provided function. 50 | func MaxBy(by func(type T) type O ord) func(T, T) bool { 51 | return func(x, y T) bool { 52 | return by(x) > by(y) 53 | } 54 | } 55 | 56 | // Size returns the number of elements currently in the heap. 57 | func (h *Heap(type T)) Size() int { 58 | return len(h.elems) 59 | } 60 | 61 | // Push adds an element to the heap. 62 | func (h *Heap(type T)) Push(x T) { 63 | h.elems = append(h.elems, x) 64 | j := len(h.elems) - 1 65 | for { 66 | i := (j - 1) / 2 // parent 67 | if i == j || !h.less(h.elems[j], h.elems[i]) { 68 | break 69 | } 70 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 71 | j = i 72 | } 73 | } 74 | 75 | // Top returns the current minimal (or maximal) element. 76 | // 77 | // Returns false if the heap is empty. 78 | func (h *Heap(type T)) Top() (top T, ok bool) { 79 | if len(h.elems) == 0 { 80 | ok = false 81 | return 82 | } 83 | return h.elems[0], true 84 | } 85 | 86 | // Pop returns the current minimal (or maximal) element and removes it from the heap. 87 | // 88 | // Returns false if the heap is empty. 89 | func (h *Heap(type T)) Pop() (top T, ok bool) { 90 | if len(h.elems) == 0 { 91 | ok = false 92 | return 93 | } 94 | n := len(h.elems) - 1 95 | h.elems[0], h.elems[n] = h.elems[n], h.elems[0] 96 | i := 0 97 | for { 98 | j1 := 2*i + 1 99 | if j1 >= n || j1 < 0 { // j1 < 0 after int overflow 100 | break 101 | } 102 | j := j1 // left child 103 | if j2 := j1 + 1; j2 < n && h.less(h.elems[j2], h.elems[j1]) { 104 | j = j2 // = 2*i + 2 // right child 105 | } 106 | if !h.less(h.elems[j], h.elems[i]) { 107 | break 108 | } 109 | h.elems[i], h.elems[j] = h.elems[j], h.elems[i] 110 | i = j 111 | } 112 | top = h.elems[n] 113 | h.elems = h.elems[:n] 114 | return top, true 115 | } 116 | 117 | type Person struct { 118 | name string 119 | age int 120 | } 121 | 122 | func (p Person) String() string { 123 | return fmt.Sprintf("%s is %d years old", p.name, p.age) 124 | } 125 | 126 | func (p Person) Name() string { 127 | return p.name 128 | } 129 | 130 | func (p Person) Age() int { 131 | return p.age 132 | } 133 | 134 | func main() { 135 | numbers := NewHeap(Min(int)) 136 | for x := 10; x >= 1; x-- { 137 | numbers.Push(x) 138 | } 139 | for { 140 | x, ok := numbers.Pop() 141 | if !ok { 142 | break 143 | } 144 | fmt.Print(x, " ") 145 | } 146 | fmt.Println() 147 | 148 | fmt.Println() 149 | 150 | people := NewHeap(MaxBy(Person.Age)) 151 | for _, person := range []Person{ 152 | {"Michal", 23}, 153 | {"Viktória", 20}, 154 | {"Jano", 21}, 155 | {"Martin", 18}, 156 | } { 157 | people.Push(person) 158 | } 159 | for { 160 | p, ok := people.Pop() 161 | if !ok { 162 | break 163 | } 164 | fmt.Println(p) 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /examples/sliceutils/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | type Person struct { 9 | name string 10 | age int 11 | } 12 | 13 | func (p Person) Name() string { 14 | return p.name 15 | } 16 | func (p Person) Age() int { 17 | return p.age 18 | } 19 | 20 | func SortBy_int_Person(a []Person, by func(Person) int) { 21 | sort.Slice(a, func(i, j int) bool { return by(a[i]) < by(a[j]) }) 22 | } 23 | func Map_Person_string(a []Person, f func(Person) string) []string { 24 | result := make([]string, len(a)) 25 | for i := range a { 26 | result[i] = f(a[i]) 27 | } 28 | return result 29 | } 30 | 31 | func Map_Person_int(a []Person, f func(Person) int) []int { 32 | result := make([]int, len(a)) 33 | for i := range a { 34 | result[i] = f(a[i]) 35 | } 36 | return result 37 | } 38 | 39 | func Map_int_string(a []int, f func(int) string) []string { 40 | result := make([]string, len(a)) 41 | for i := range a { 42 | result[i] = f(a[i]) 43 | } 44 | return result 45 | } 46 | 47 | func Concat_string(slices ...[]string) []string { 48 | total := 0 49 | for i := range slices { 50 | total += len(slices[i]) 51 | } 52 | 53 | result := make([]string, 0, total) 54 | for i := range slices { 55 | result = append(result, slices[i]...) 56 | } 57 | return result 58 | } 59 | 60 | func Reverse_string(a []string) { 61 | for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { 62 | a[i], a[j] = a[j], a[i] 63 | } 64 | } 65 | func main() { 66 | people := []Person{{"Michal", 23}, {"Viktória", 20}, {"Jano", 21}, {"Martin", 18}} 67 | SortBy_int_Person(people, Person.Age) 68 | fmt.Println(people) 69 | 70 | names := Map_Person_string(people, Person.Name) 71 | ages := Map_Person_int(people, Person.Age) 72 | ageStrings := Map_int_string(ages, func(a int) string { return fmt.Sprint(a) }) 73 | 74 | everything := Concat_string(names, ageStrings) 75 | Reverse_string(everything) 76 | fmt.Println(everything) 77 | } 78 | -------------------------------------------------------------------------------- /examples/sliceutils/sliceutils.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sort" 6 | ) 7 | 8 | // Reverse reverses any slice in place. 9 | func Reverse(a []type T) { 10 | for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { 11 | a[i], a[j] = a[j], a[i] 12 | } 13 | } 14 | 15 | // Concat returns a concatenation of multiple slices of the same type. 16 | func Concat(slices ...[]type T) []T { 17 | total := 0 18 | for i := range slices { 19 | total += len(slices[i]) 20 | } 21 | result := make([]T, 0, total) 22 | for i := range slices { 23 | result = append(result, slices[i]...) 24 | } 25 | return result 26 | } 27 | 28 | // Map returns a new slice where each element from the original slice is transformed by f. 29 | func Map(a []type T, f func(T) type U) []U { 30 | result := make([]U, len(a)) 31 | for i := range a { 32 | result[i] = f(a[i]) 33 | } 34 | return result 35 | } 36 | 37 | // Interfaces converts a slice of an arbitrary type to a slice of empty interfaces. 38 | func Interfaces(a []type T) []interface{} { 39 | ifaces := make([]interface{}, len(a)) 40 | for i := range a { 41 | ifaces[i] = a[i] 42 | } 43 | return ifaces 44 | } 45 | 46 | // Sort sorts a slice of an arbitrary orderable type. 47 | func Sort(a []type T ord) { 48 | sort.Slice(a, func(i, j int) bool { 49 | return a[i] < a[j] 50 | }) 51 | } 52 | 53 | // SortBy sorts a slice by a key. For example: 54 | // 55 | // SortBy(people, (*Person).Age) 56 | func SortBy(a []type T, by func(T) type O ord) { 57 | sort.Slice(a, func(i, j int) bool { 58 | return by(a[i]) < by(a[j]) 59 | }) 60 | } 61 | 62 | // SortWith sorts a slice using a custom comparator. 63 | func SortWith(a []type T, with func(T, T) bool) { 64 | sort.Slice(a, func(i, j int) bool { 65 | return with(a[i], a[j]) 66 | }) 67 | } 68 | 69 | type Person struct { 70 | name string 71 | age int 72 | } 73 | 74 | func (p Person) Name() string { 75 | return p.name 76 | } 77 | 78 | func (p Person) Age() int { 79 | return p.age 80 | } 81 | 82 | func main() { 83 | people := []Person{ 84 | {"Michal", 23}, 85 | {"Viktória", 20}, 86 | {"Jano", 21}, 87 | {"Martin", 18}, 88 | } 89 | SortBy(people, Person.Age) 90 | fmt.Println(people) 91 | 92 | names := Map(people, Person.Name) 93 | ages := Map(people, Person.Age) 94 | ageStrings := Map(ages, func(a int) string { 95 | return fmt.Sprint(a) 96 | }) 97 | 98 | everything := Concat(names, ageStrings) 99 | Reverse(everything) 100 | fmt.Println(everything) 101 | } 102 | -------------------------------------------------------------------------------- /examples/syncmap/out.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type SyncMap_string_bool struct { 10 | mu sync.Mutex 11 | m map[string]bool 12 | } 13 | 14 | func (sm *SyncMap_string_bool) Delete(key string) { sm.mu.Lock(); delete(sm.m, key); sm.mu.Unlock() } 15 | 16 | func (sm *SyncMap_string_bool) Load(key string) (value bool, ok bool) { 17 | sm.mu.Lock() 18 | value, ok = sm.m[key] 19 | sm.mu.Unlock() 20 | return 21 | } 22 | 23 | func (sm *SyncMap_string_bool) LoadOrStore(key string, value bool) (actual bool, loaded bool) { 24 | sm.mu.Lock() 25 | actual, loaded = sm.m[key] 26 | if !loaded { 27 | sm.m[key] = value 28 | actual = value 29 | } 30 | 31 | sm.mu.Unlock() 32 | return 33 | } 34 | 35 | func (sm *SyncMap_string_bool) Range(f func(key string, value bool) bool) { 36 | sm.mu.Lock() 37 | for k, v := range sm.m { 38 | if !f(k, v) { 39 | break 40 | } 41 | } 42 | 43 | sm.mu.Unlock() 44 | } 45 | 46 | func (sm *SyncMap_string_bool) Store(key string, value bool) { 47 | sm.mu.Lock() 48 | sm.m[key] = value 49 | sm.mu.Unlock() 50 | } 51 | func MakeSyncMap_string_bool() *SyncMap_string_bool { 52 | return &SyncMap_string_bool{m: make(map[string]bool)} 53 | } 54 | 55 | func MarkAll_string(done chan<- bool, sm *SyncMap_string_bool, values ...string) { 56 | for _, val := range values { 57 | time.Sleep(time.Second / 10) 58 | sm.Store(val, true) 59 | } 60 | 61 | done <- true 62 | } 63 | func main() { 64 | marked := MakeSyncMap_string_bool() 65 | done := make(chan bool) 66 | go MarkAll_string(done, marked, "A", "B", "C", "D") 67 | go MarkAll_string(done, marked, "E", "F", "G", "H") 68 | go MarkAll_string(done, marked, "I", "J", "K", "L") 69 | for i := 0; i < 3; i++ { 70 | <-done 71 | } 72 | 73 | marked.Range(func(key string, value bool) bool { fmt.Println(key); return true }) 74 | } 75 | -------------------------------------------------------------------------------- /examples/syncmap/syncmap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | // SyncMap is a generic hash-map usable from multiple goroutines simultaneously. 10 | // 11 | // The API imitates the API of sync.Map. 12 | // 13 | // This is a dummy implementation to demonstrate the typing capabilities. This is not 14 | // an example of an efficient implementation of a SyncMap. 15 | type SyncMap(type K eq, type V) struct { 16 | mu sync.Mutex 17 | m map[K]V 18 | } 19 | 20 | // MakeSyncMap creates a new, empty SyncMap. 21 | // 22 | // I know it's better to make the zero value useful, this is just to better demonstrate 23 | // the unnamed type parmeters syntax. 24 | func MakeSyncMap(type K eq, type V) *SyncMap(K, V) { 25 | return &SyncMap(K, V){ 26 | m: make(map[K]V), 27 | } 28 | } 29 | 30 | // Delete deletes the value for a key. 31 | func (sm *SyncMap(type K eq, type V)) Delete(key K) { 32 | sm.mu.Lock() 33 | delete(sm.m, key) 34 | sm.mu.Unlock() 35 | } 36 | 37 | // Load returns the value stored in the map for a key, or nil if no value is present. 38 | // The ok result indicates whether value was found in the map. 39 | func (sm *SyncMap(type K eq, type V)) Load(key K) (value V, ok bool) { 40 | sm.mu.Lock() 41 | value, ok = sm.m[key] 42 | sm.mu.Unlock() 43 | return 44 | } 45 | 46 | // LoadOrStore returns the existing value for the key if present. 47 | // Otherwise, it stores and returns the given value. 48 | // The loaded result is true if the value was loaded, false if stored. 49 | func (sm *SyncMap(type K eq, type V)) LoadOrStore(key K, value V) (actual V, loaded bool) { 50 | sm.mu.Lock() 51 | actual, loaded = sm.m[key] 52 | if !loaded { 53 | sm.m[key] = value 54 | actual = value 55 | } 56 | sm.mu.Unlock() 57 | return 58 | } 59 | 60 | // Range calls f sequentially for each key and value present in the map. 61 | // If f returns false, range stops the iteration. 62 | func (sm *SyncMap(type K eq, type V)) Range(f func(key K, value V) bool) { 63 | sm.mu.Lock() 64 | for k, v := range sm.m { 65 | if !f(k, v) { 66 | break 67 | } 68 | } 69 | sm.mu.Unlock() 70 | } 71 | 72 | // Store sets the value for a key. 73 | func (sm *SyncMap(type K eq, type V)) Store(key K, value V) { 74 | sm.mu.Lock() 75 | sm.m[key] = value 76 | sm.mu.Unlock() 77 | } 78 | 79 | func MarkAll(done chan<- bool, sm *SyncMap(type T eq, bool), values ...T) { 80 | for _, val := range values { 81 | time.Sleep(time.Second / 10) 82 | sm.Store(val, true) 83 | } 84 | done <- true 85 | } 86 | 87 | func main() { 88 | marked := MakeSyncMap(string, bool) 89 | done := make(chan bool) 90 | 91 | go MarkAll(done, marked, "A", "B", "C", "D") 92 | go MarkAll(done, marked, "E", "F", "G", "H") 93 | go MarkAll(done, marked, "I", "J", "K", "L") 94 | 95 | for i := 0; i < 3; i++ { 96 | <-done 97 | } 98 | 99 | marked.Range(func(key string, value bool) bool { 100 | fmt.Println(key) 101 | return true 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/faiface/generics 2 | -------------------------------------------------------------------------------- /go/ast/import.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 ast 6 | 7 | import ( 8 | "github.com/faiface/generics/go/token" 9 | "sort" 10 | "strconv" 11 | ) 12 | 13 | // SortImports sorts runs of consecutive import lines in import blocks in f. 14 | // It also removes duplicate imports when it is possible to do so without data loss. 15 | func SortImports(fset *token.FileSet, f *File) { 16 | for _, d := range f.Decls { 17 | d, ok := d.(*GenDecl) 18 | if !ok || d.Tok != token.IMPORT { 19 | // Not an import declaration, so we're done. 20 | // Imports are always first. 21 | break 22 | } 23 | 24 | if !d.Lparen.IsValid() { 25 | // Not a block: sorted by default. 26 | continue 27 | } 28 | 29 | // Identify and sort runs of specs on successive lines. 30 | i := 0 31 | specs := d.Specs[:0] 32 | for j, s := range d.Specs { 33 | if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { 34 | // j begins a new run. End this one. 35 | specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...) 36 | i = j 37 | } 38 | } 39 | specs = append(specs, sortSpecs(fset, f, d.Specs[i:])...) 40 | d.Specs = specs 41 | 42 | // Deduping can leave a blank line before the rparen; clean that up. 43 | if len(d.Specs) > 0 { 44 | lastSpec := d.Specs[len(d.Specs)-1] 45 | lastLine := fset.Position(lastSpec.Pos()).Line 46 | rParenLine := fset.Position(d.Rparen).Line 47 | for rParenLine > lastLine+1 { 48 | rParenLine-- 49 | fset.File(d.Rparen).MergeLine(rParenLine) 50 | } 51 | } 52 | } 53 | } 54 | 55 | func importPath(s Spec) string { 56 | t, err := strconv.Unquote(s.(*ImportSpec).Path.Value) 57 | if err == nil { 58 | return t 59 | } 60 | return "" 61 | } 62 | 63 | func importName(s Spec) string { 64 | n := s.(*ImportSpec).Name 65 | if n == nil { 66 | return "" 67 | } 68 | return n.Name 69 | } 70 | 71 | func importComment(s Spec) string { 72 | c := s.(*ImportSpec).Comment 73 | if c == nil { 74 | return "" 75 | } 76 | return c.Text() 77 | } 78 | 79 | // collapse indicates whether prev may be removed, leaving only next. 80 | func collapse(prev, next Spec) bool { 81 | if importPath(next) != importPath(prev) || importName(next) != importName(prev) { 82 | return false 83 | } 84 | return prev.(*ImportSpec).Comment == nil 85 | } 86 | 87 | type posSpan struct { 88 | Start token.Pos 89 | End token.Pos 90 | } 91 | 92 | func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { 93 | // Can't short-circuit here even if specs are already sorted, 94 | // since they might yet need deduplication. 95 | // A lone import, however, may be safely ignored. 96 | if len(specs) <= 1 { 97 | return specs 98 | } 99 | 100 | // Record positions for specs. 101 | pos := make([]posSpan, len(specs)) 102 | for i, s := range specs { 103 | pos[i] = posSpan{s.Pos(), s.End()} 104 | } 105 | 106 | // Identify comments in this range. 107 | // Any comment from pos[0].Start to the final line counts. 108 | lastLine := fset.Position(pos[len(pos)-1].End).Line 109 | cstart := len(f.Comments) 110 | cend := len(f.Comments) 111 | for i, g := range f.Comments { 112 | if g.Pos() < pos[0].Start { 113 | continue 114 | } 115 | if i < cstart { 116 | cstart = i 117 | } 118 | if fset.Position(g.End()).Line > lastLine { 119 | cend = i 120 | break 121 | } 122 | } 123 | comments := f.Comments[cstart:cend] 124 | 125 | // Assign each comment to the import spec preceding it. 126 | importComments := map[*ImportSpec][]*CommentGroup{} 127 | specIndex := 0 128 | for _, g := range comments { 129 | for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { 130 | specIndex++ 131 | } 132 | s := specs[specIndex].(*ImportSpec) 133 | importComments[s] = append(importComments[s], g) 134 | } 135 | 136 | // Sort the import specs by import path. 137 | // Remove duplicates, when possible without data loss. 138 | // Reassign the import paths to have the same position sequence. 139 | // Reassign each comment to abut the end of its spec. 140 | // Sort the comments by new position. 141 | sort.Slice(specs, func(i, j int) bool { 142 | ipath := importPath(specs[i]) 143 | jpath := importPath(specs[j]) 144 | if ipath != jpath { 145 | return ipath < jpath 146 | } 147 | iname := importName(specs[i]) 148 | jname := importName(specs[j]) 149 | if iname != jname { 150 | return iname < jname 151 | } 152 | return importComment(specs[i]) < importComment(specs[j]) 153 | }) 154 | 155 | // Dedup. Thanks to our sorting, we can just consider 156 | // adjacent pairs of imports. 157 | deduped := specs[:0] 158 | for i, s := range specs { 159 | if i == len(specs)-1 || !collapse(s, specs[i+1]) { 160 | deduped = append(deduped, s) 161 | } else { 162 | p := s.Pos() 163 | fset.File(p).MergeLine(fset.Position(p).Line) 164 | } 165 | } 166 | specs = deduped 167 | 168 | // Fix up comment positions 169 | for i, s := range specs { 170 | s := s.(*ImportSpec) 171 | if s.Name != nil { 172 | s.Name.NamePos = pos[i].Start 173 | } 174 | s.Path.ValuePos = pos[i].Start 175 | s.EndPos = pos[i].End 176 | for _, g := range importComments[s] { 177 | for _, c := range g.List { 178 | c.Slash = pos[i].End 179 | } 180 | } 181 | } 182 | 183 | sort.Slice(comments, func(i, j int) bool { 184 | return comments[i].Pos() < comments[j].Pos() 185 | }) 186 | 187 | return specs 188 | } 189 | -------------------------------------------------------------------------------- /go/ast/resolve.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 | // This file implements NewPackage. 6 | 7 | package ast 8 | 9 | import ( 10 | "fmt" 11 | "github.com/faiface/generics/go/scanner" 12 | "github.com/faiface/generics/go/token" 13 | "strconv" 14 | ) 15 | 16 | type pkgBuilder struct { 17 | fset *token.FileSet 18 | errors scanner.ErrorList 19 | } 20 | 21 | func (p *pkgBuilder) error(pos token.Pos, msg string) { 22 | p.errors.Add(p.fset.Position(pos), msg) 23 | } 24 | 25 | func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) { 26 | p.error(pos, fmt.Sprintf(format, args...)) 27 | } 28 | 29 | func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { 30 | alt := scope.Insert(obj) 31 | if alt == nil && altScope != nil { 32 | // see if there is a conflicting declaration in altScope 33 | alt = altScope.Lookup(obj.Name) 34 | } 35 | if alt != nil { 36 | prevDecl := "" 37 | if pos := alt.Pos(); pos.IsValid() { 38 | prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.fset.Position(pos)) 39 | } 40 | p.error(obj.Pos(), fmt.Sprintf("%s redeclared in this block%s", obj.Name, prevDecl)) 41 | } 42 | } 43 | 44 | func resolve(scope *Scope, ident *Ident) bool { 45 | for ; scope != nil; scope = scope.Outer { 46 | if obj := scope.Lookup(ident.Name); obj != nil { 47 | ident.Obj = obj 48 | return true 49 | } 50 | } 51 | return false 52 | } 53 | 54 | // An Importer resolves import paths to package Objects. 55 | // The imports map records the packages already imported, 56 | // indexed by package id (canonical import path). 57 | // An Importer must determine the canonical import path and 58 | // check the map to see if it is already present in the imports map. 59 | // If so, the Importer can return the map entry. Otherwise, the 60 | // Importer should load the package data for the given path into 61 | // a new *Object (pkg), record pkg in the imports map, and then 62 | // return pkg. 63 | type Importer func(imports map[string]*Object, path string) (pkg *Object, err error) 64 | 65 | // NewPackage creates a new Package node from a set of File nodes. It resolves 66 | // unresolved identifiers across files and updates each file's Unresolved list 67 | // accordingly. If a non-nil importer and universe scope are provided, they are 68 | // used to resolve identifiers not declared in any of the package files. Any 69 | // remaining unresolved identifiers are reported as undeclared. If the files 70 | // belong to different packages, one package name is selected and files with 71 | // different package names are reported and then ignored. 72 | // The result is a package node and a scanner.ErrorList if there were errors. 73 | // 74 | func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) { 75 | var p pkgBuilder 76 | p.fset = fset 77 | 78 | // complete package scope 79 | pkgName := "" 80 | pkgScope := NewScope(universe) 81 | for _, file := range files { 82 | // package names must match 83 | switch name := file.Name.Name; { 84 | case pkgName == "": 85 | pkgName = name 86 | case name != pkgName: 87 | p.errorf(file.Package, "package %s; expected %s", name, pkgName) 88 | continue // ignore this file 89 | } 90 | 91 | // collect top-level file objects in package scope 92 | for _, obj := range file.Scope.Objects { 93 | p.declare(pkgScope, nil, obj) 94 | } 95 | } 96 | 97 | // package global mapping of imported package ids to package objects 98 | imports := make(map[string]*Object) 99 | 100 | // complete file scopes with imports and resolve identifiers 101 | for _, file := range files { 102 | // ignore file if it belongs to a different package 103 | // (error has already been reported) 104 | if file.Name.Name != pkgName { 105 | continue 106 | } 107 | 108 | // build file scope by processing all imports 109 | importErrors := false 110 | fileScope := NewScope(pkgScope) 111 | for _, spec := range file.Imports { 112 | if importer == nil { 113 | importErrors = true 114 | continue 115 | } 116 | path, _ := strconv.Unquote(spec.Path.Value) 117 | pkg, err := importer(imports, path) 118 | if err != nil { 119 | p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) 120 | importErrors = true 121 | continue 122 | } 123 | // TODO(gri) If a local package name != "." is provided, 124 | // global identifier resolution could proceed even if the 125 | // import failed. Consider adjusting the logic here a bit. 126 | 127 | // local name overrides imported package name 128 | name := pkg.Name 129 | if spec.Name != nil { 130 | name = spec.Name.Name 131 | } 132 | 133 | // add import to file scope 134 | if name == "." { 135 | // merge imported scope with file scope 136 | for _, obj := range pkg.Data.(*Scope).Objects { 137 | p.declare(fileScope, pkgScope, obj) 138 | } 139 | } else if name != "_" { 140 | // declare imported package object in file scope 141 | // (do not re-use pkg in the file scope but create 142 | // a new object instead; the Decl field is different 143 | // for different files) 144 | obj := NewObj(Pkg, name) 145 | obj.Decl = spec 146 | obj.Data = pkg.Data 147 | p.declare(fileScope, pkgScope, obj) 148 | } 149 | } 150 | 151 | // resolve identifiers 152 | if importErrors { 153 | // don't use the universe scope without correct imports 154 | // (objects in the universe may be shadowed by imports; 155 | // with missing imports, identifiers might get resolved 156 | // incorrectly to universe objects) 157 | pkgScope.Outer = nil 158 | } 159 | i := 0 160 | for _, ident := range file.Unresolved { 161 | if !resolve(fileScope, ident) { 162 | p.errorf(ident.Pos(), "undeclared name: %s", ident.Name) 163 | file.Unresolved[i] = ident 164 | i++ 165 | } 166 | 167 | } 168 | file.Unresolved = file.Unresolved[0:i] 169 | pkgScope.Outer = universe // reset universe scope 170 | } 171 | 172 | p.errors.Sort() 173 | return &Package{pkgName, pkgScope, imports, files}, p.errors.Err() 174 | } 175 | -------------------------------------------------------------------------------- /go/ast/scope.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 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 | // This file implements scopes and the objects they contain. 6 | 7 | package ast 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "github.com/faiface/generics/go/token" 13 | ) 14 | 15 | // A Scope maintains the set of named language entities declared 16 | // in the scope and a link to the immediately surrounding (outer) 17 | // scope. 18 | // 19 | type Scope struct { 20 | Outer *Scope 21 | Objects map[string]*Object 22 | } 23 | 24 | // NewScope creates a new scope nested in the outer scope. 25 | func NewScope(outer *Scope) *Scope { 26 | const n = 4 // initial scope capacity 27 | return &Scope{outer, make(map[string]*Object, n)} 28 | } 29 | 30 | // Lookup returns the object with the given name if it is 31 | // found in scope s, otherwise it returns nil. Outer scopes 32 | // are ignored. 33 | // 34 | func (s *Scope) Lookup(name string) *Object { 35 | return s.Objects[name] 36 | } 37 | 38 | // Insert attempts to insert a named object obj into the scope s. 39 | // If the scope already contains an object alt with the same name, 40 | // Insert leaves the scope unchanged and returns alt. Otherwise 41 | // it inserts obj and returns nil. 42 | // 43 | func (s *Scope) Insert(obj *Object) (alt *Object) { 44 | if alt = s.Objects[obj.Name]; alt == nil { 45 | s.Objects[obj.Name] = obj 46 | } 47 | return 48 | } 49 | 50 | // Debugging support 51 | func (s *Scope) String() string { 52 | var buf bytes.Buffer 53 | fmt.Fprintf(&buf, "scope %p {", s) 54 | if s != nil && len(s.Objects) > 0 { 55 | fmt.Fprintln(&buf) 56 | for _, obj := range s.Objects { 57 | fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name) 58 | } 59 | } 60 | fmt.Fprintf(&buf, "}\n") 61 | return buf.String() 62 | } 63 | 64 | // ---------------------------------------------------------------------------- 65 | // Objects 66 | 67 | // An Object describes a named language entity such as a package, 68 | // constant, type, variable, function (incl. methods), or label. 69 | // 70 | // The Data fields contains object-specific data: 71 | // 72 | // Kind Data type Data value 73 | // Pkg *Scope package scope 74 | // Con int iota for the respective declaration 75 | // 76 | type Object struct { 77 | Kind ObjKind 78 | Name string // declared name 79 | Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil 80 | Data interface{} // object-specific data; or nil 81 | Type interface{} // placeholder for type information; may be nil 82 | } 83 | 84 | // NewObj creates a new object of a given kind and name. 85 | func NewObj(kind ObjKind, name string) *Object { 86 | return &Object{Kind: kind, Name: name} 87 | } 88 | 89 | // Pos computes the source position of the declaration of an object name. 90 | // The result may be an invalid position if it cannot be computed 91 | // (obj.Decl may be nil or not correct). 92 | func (obj *Object) Pos() token.Pos { 93 | name := obj.Name 94 | switch d := obj.Decl.(type) { 95 | case *Field: 96 | for _, n := range d.Names { 97 | if n.Name == name { 98 | return n.Pos() 99 | } 100 | } 101 | case *ImportSpec: 102 | if d.Name != nil && d.Name.Name == name { 103 | return d.Name.Pos() 104 | } 105 | return d.Path.Pos() 106 | case *ValueSpec: 107 | for _, n := range d.Names { 108 | if n.Name == name { 109 | return n.Pos() 110 | } 111 | } 112 | case *TypeSpec: 113 | if d.Name.Name == name { 114 | return d.Name.Pos() 115 | } 116 | case *FuncDecl: 117 | if d.Name.Name == name { 118 | return d.Name.Pos() 119 | } 120 | case *LabeledStmt: 121 | if d.Label.Name == name { 122 | return d.Label.Pos() 123 | } 124 | case *AssignStmt: 125 | for _, x := range d.Lhs { 126 | if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { 127 | return ident.Pos() 128 | } 129 | } 130 | case *Scope: 131 | // predeclared object - nothing to do for now 132 | } 133 | return token.NoPos 134 | } 135 | 136 | // ObjKind describes what an object represents. 137 | type ObjKind int 138 | 139 | // The list of possible Object kinds. 140 | const ( 141 | Bad ObjKind = iota // for error handling 142 | Pkg // package 143 | Con // constant 144 | Typ // type 145 | Var // variable 146 | Fun // function or method 147 | Lbl // label 148 | ) 149 | 150 | var objKindStrings = [...]string{ 151 | Bad: "bad", 152 | Pkg: "package", 153 | Con: "const", 154 | Typ: "type", 155 | Var: "var", 156 | Fun: "func", 157 | Lbl: "label", 158 | } 159 | 160 | func (kind ObjKind) String() string { return objKindStrings[kind] } 161 | -------------------------------------------------------------------------------- /go/build/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 build gathers information about Go packages. 6 | // 7 | // Go Path 8 | // 9 | // The Go path is a list of directory trees containing Go source code. 10 | // It is consulted to resolve imports that cannot be found in the standard 11 | // Go tree. The default path is the value of the GOPATH environment 12 | // variable, interpreted as a path list appropriate to the operating system 13 | // (on Unix, the variable is a colon-separated string; 14 | // on Windows, a semicolon-separated string; 15 | // on Plan 9, a list). 16 | // 17 | // Each directory listed in the Go path must have a prescribed structure: 18 | // 19 | // The src/ directory holds source code. The path below 'src' determines 20 | // the import path or executable name. 21 | // 22 | // The pkg/ directory holds installed package objects. 23 | // As in the Go tree, each target operating system and 24 | // architecture pair has its own subdirectory of pkg 25 | // (pkg/GOOS_GOARCH). 26 | // 27 | // If DIR is a directory listed in the Go path, a package with 28 | // source in DIR/src/foo/bar can be imported as "foo/bar" and 29 | // has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a" 30 | // (or, for gccgo, "DIR/pkg/gccgo/foo/libbar.a"). 31 | // 32 | // The bin/ directory holds compiled commands. 33 | // Each command is named for its source directory, but only 34 | // using the final element, not the entire path. That is, the 35 | // command with source in DIR/src/foo/quux is installed into 36 | // DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped 37 | // so that you can add DIR/bin to your PATH to get at the 38 | // installed commands. 39 | // 40 | // Here's an example directory layout: 41 | // 42 | // GOPATH=/home/user/gocode 43 | // 44 | // /home/user/gocode/ 45 | // src/ 46 | // foo/ 47 | // bar/ (go code in package bar) 48 | // x.go 49 | // quux/ (go code in package main) 50 | // y.go 51 | // bin/ 52 | // quux (installed command) 53 | // pkg/ 54 | // linux_amd64/ 55 | // foo/ 56 | // bar.a (installed package object) 57 | // 58 | // Build Constraints 59 | // 60 | // A build constraint, also known as a build tag, is a line comment that begins 61 | // 62 | // // +build 63 | // 64 | // that lists the conditions under which a file should be included in the package. 65 | // Constraints may appear in any kind of source file (not just Go), but 66 | // they must appear near the top of the file, preceded 67 | // only by blank lines and other line comments. These rules mean that in Go 68 | // files a build constraint must appear before the package clause. 69 | // 70 | // To distinguish build constraints from package documentation, a series of 71 | // build constraints must be followed by a blank line. 72 | // 73 | // A build constraint is evaluated as the OR of space-separated options; 74 | // each option evaluates as the AND of its comma-separated terms; 75 | // and each term is an alphanumeric word or, preceded by !, its negation. 76 | // That is, the build constraint: 77 | // 78 | // // +build linux,386 darwin,!cgo 79 | // 80 | // corresponds to the boolean formula: 81 | // 82 | // (linux AND 386) OR (darwin AND (NOT cgo)) 83 | // 84 | // A file may have multiple build constraints. The overall constraint is the AND 85 | // of the individual constraints. That is, the build constraints: 86 | // 87 | // // +build linux darwin 88 | // // +build 386 89 | // 90 | // corresponds to the boolean formula: 91 | // 92 | // (linux OR darwin) AND 386 93 | // 94 | // During a particular build, the following words are satisfied: 95 | // 96 | // - the target operating system, as spelled by runtime.GOOS 97 | // - the target architecture, as spelled by runtime.GOARCH 98 | // - the compiler being used, either "gc" or "gccgo" 99 | // - "cgo", if ctxt.CgoEnabled is true 100 | // - "go1.1", from Go version 1.1 onward 101 | // - "go1.2", from Go version 1.2 onward 102 | // - "go1.3", from Go version 1.3 onward 103 | // - "go1.4", from Go version 1.4 onward 104 | // - "go1.5", from Go version 1.5 onward 105 | // - "go1.6", from Go version 1.6 onward 106 | // - "go1.7", from Go version 1.7 onward 107 | // - "go1.8", from Go version 1.8 onward 108 | // - "go1.9", from Go version 1.9 onward 109 | // - "go1.10", from Go version 1.10 onward 110 | // - any additional words listed in ctxt.BuildTags 111 | // 112 | // If a file's name, after stripping the extension and a possible _test suffix, 113 | // matches any of the following patterns: 114 | // *_GOOS 115 | // *_GOARCH 116 | // *_GOOS_GOARCH 117 | // (example: source_windows_amd64.go) where GOOS and GOARCH represent 118 | // any known operating system and architecture values respectively, then 119 | // the file is considered to have an implicit build constraint requiring 120 | // those terms (in addition to any explicit constraints in the file). 121 | // 122 | // To keep a file from being considered for the build: 123 | // 124 | // // +build ignore 125 | // 126 | // (any other unsatisfied word will work as well, but ``ignore'' is conventional.) 127 | // 128 | // To build a file only when using cgo, and only on Linux and OS X: 129 | // 130 | // // +build linux,cgo darwin,cgo 131 | // 132 | // Such a file is usually paired with another file implementing the 133 | // default functionality for other systems, which in this case would 134 | // carry the constraint: 135 | // 136 | // // +build !linux,!darwin !cgo 137 | // 138 | // Naming a file dns_windows.go will cause it to be included only when 139 | // building the package for Windows; similarly, math_386.s will be included 140 | // only when building the package for 32-bit x86. 141 | // 142 | // Using GOOS=android matches build tags and files as for GOOS=linux 143 | // in addition to android tags and files. 144 | // 145 | // Binary-Only Packages 146 | // 147 | // It is possible to distribute packages in binary form without including the 148 | // source code used for compiling the package. To do this, the package must 149 | // be distributed with a source file not excluded by build constraints and 150 | // containing a "//go:binary-only-package" comment. 151 | // Like a build constraint, this comment must appear near the top of the file, 152 | // preceded only by blank lines and other line comments and with a blank line 153 | // following the comment, to separate it from the package documentation. 154 | // Unlike build constraints, this comment is only recognized in non-test 155 | // Go source files. 156 | // 157 | // The minimal source code for a binary-only package is therefore: 158 | // 159 | // //go:binary-only-package 160 | // 161 | // package mypkg 162 | // 163 | // The source code may include additional Go code. That code is never compiled 164 | // but will be processed by tools like godoc and might be useful as end-user 165 | // documentation. 166 | // 167 | package build 168 | -------------------------------------------------------------------------------- /go/build/read.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 build 6 | 7 | import ( 8 | "bufio" 9 | "errors" 10 | "io" 11 | "unicode/utf8" 12 | ) 13 | 14 | type importReader struct { 15 | b *bufio.Reader 16 | buf []byte 17 | peek byte 18 | err error 19 | eof bool 20 | nerr int 21 | } 22 | 23 | func isIdent(c byte) bool { 24 | return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf 25 | } 26 | 27 | var ( 28 | errSyntax = errors.New("syntax error") 29 | errNUL = errors.New("unexpected NUL in input") 30 | ) 31 | 32 | // syntaxError records a syntax error, but only if an I/O error has not already been recorded. 33 | func (r *importReader) syntaxError() { 34 | if r.err == nil { 35 | r.err = errSyntax 36 | } 37 | } 38 | 39 | // readByte reads the next byte from the input, saves it in buf, and returns it. 40 | // If an error occurs, readByte records the error in r.err and returns 0. 41 | func (r *importReader) readByte() byte { 42 | c, err := r.b.ReadByte() 43 | if err == nil { 44 | r.buf = append(r.buf, c) 45 | if c == 0 { 46 | err = errNUL 47 | } 48 | } 49 | if err != nil { 50 | if err == io.EOF { 51 | r.eof = true 52 | } else if r.err == nil { 53 | r.err = err 54 | } 55 | c = 0 56 | } 57 | return c 58 | } 59 | 60 | // peekByte returns the next byte from the input reader but does not advance beyond it. 61 | // If skipSpace is set, peekByte skips leading spaces and comments. 62 | func (r *importReader) peekByte(skipSpace bool) byte { 63 | if r.err != nil { 64 | if r.nerr++; r.nerr > 10000 { 65 | panic("github.com/faiface/generics/go/build: import reader looping") 66 | } 67 | return 0 68 | } 69 | 70 | // Use r.peek as first input byte. 71 | // Don't just return r.peek here: it might have been left by peekByte(false) 72 | // and this might be peekByte(true). 73 | c := r.peek 74 | if c == 0 { 75 | c = r.readByte() 76 | } 77 | for r.err == nil && !r.eof { 78 | if skipSpace { 79 | // For the purposes of this reader, semicolons are never necessary to 80 | // understand the input and are treated as spaces. 81 | switch c { 82 | case ' ', '\f', '\t', '\r', '\n', ';': 83 | c = r.readByte() 84 | continue 85 | 86 | case '/': 87 | c = r.readByte() 88 | if c == '/' { 89 | for c != '\n' && r.err == nil && !r.eof { 90 | c = r.readByte() 91 | } 92 | } else if c == '*' { 93 | var c1 byte 94 | for (c != '*' || c1 != '/') && r.err == nil { 95 | if r.eof { 96 | r.syntaxError() 97 | } 98 | c, c1 = c1, r.readByte() 99 | } 100 | } else { 101 | r.syntaxError() 102 | } 103 | c = r.readByte() 104 | continue 105 | } 106 | } 107 | break 108 | } 109 | r.peek = c 110 | return r.peek 111 | } 112 | 113 | // nextByte is like peekByte but advances beyond the returned byte. 114 | func (r *importReader) nextByte(skipSpace bool) byte { 115 | c := r.peekByte(skipSpace) 116 | r.peek = 0 117 | return c 118 | } 119 | 120 | // readKeyword reads the given keyword from the input. 121 | // If the keyword is not present, readKeyword records a syntax error. 122 | func (r *importReader) readKeyword(kw string) { 123 | r.peekByte(true) 124 | for i := 0; i < len(kw); i++ { 125 | if r.nextByte(false) != kw[i] { 126 | r.syntaxError() 127 | return 128 | } 129 | } 130 | if isIdent(r.peekByte(false)) { 131 | r.syntaxError() 132 | } 133 | } 134 | 135 | // readIdent reads an identifier from the input. 136 | // If an identifier is not present, readIdent records a syntax error. 137 | func (r *importReader) readIdent() { 138 | c := r.peekByte(true) 139 | if !isIdent(c) { 140 | r.syntaxError() 141 | return 142 | } 143 | for isIdent(r.peekByte(false)) { 144 | r.peek = 0 145 | } 146 | } 147 | 148 | // readString reads a quoted string literal from the input. 149 | // If an identifier is not present, readString records a syntax error. 150 | func (r *importReader) readString(save *[]string) { 151 | switch r.nextByte(true) { 152 | case '`': 153 | start := len(r.buf) - 1 154 | for r.err == nil { 155 | if r.nextByte(false) == '`' { 156 | if save != nil { 157 | *save = append(*save, string(r.buf[start:])) 158 | } 159 | break 160 | } 161 | if r.eof { 162 | r.syntaxError() 163 | } 164 | } 165 | case '"': 166 | start := len(r.buf) - 1 167 | for r.err == nil { 168 | c := r.nextByte(false) 169 | if c == '"' { 170 | if save != nil { 171 | *save = append(*save, string(r.buf[start:])) 172 | } 173 | break 174 | } 175 | if r.eof || c == '\n' { 176 | r.syntaxError() 177 | } 178 | if c == '\\' { 179 | r.nextByte(false) 180 | } 181 | } 182 | default: 183 | r.syntaxError() 184 | } 185 | } 186 | 187 | // readImport reads an import clause - optional identifier followed by quoted string - 188 | // from the input. 189 | func (r *importReader) readImport(imports *[]string) { 190 | c := r.peekByte(true) 191 | if c == '.' { 192 | r.peek = 0 193 | } else if isIdent(c) { 194 | r.readIdent() 195 | } 196 | r.readString(imports) 197 | } 198 | 199 | // readComments is like ioutil.ReadAll, except that it only reads the leading 200 | // block of comments in the file. 201 | func readComments(f io.Reader) ([]byte, error) { 202 | r := &importReader{b: bufio.NewReader(f)} 203 | r.peekByte(true) 204 | if r.err == nil && !r.eof { 205 | // Didn't reach EOF, so must have found a non-space byte. Remove it. 206 | r.buf = r.buf[:len(r.buf)-1] 207 | } 208 | return r.buf, r.err 209 | } 210 | 211 | // readImports is like ioutil.ReadAll, except that it expects a Go file as input 212 | // and stops reading the input once the imports have completed. 213 | func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { 214 | r := &importReader{b: bufio.NewReader(f)} 215 | 216 | r.readKeyword("package") 217 | r.readIdent() 218 | for r.peekByte(true) == 'i' { 219 | r.readKeyword("import") 220 | if r.peekByte(true) == '(' { 221 | r.nextByte(false) 222 | for r.peekByte(true) != ')' && r.err == nil { 223 | r.readImport(imports) 224 | } 225 | r.nextByte(false) 226 | } else { 227 | r.readImport(imports) 228 | } 229 | } 230 | 231 | // If we stopped successfully before EOF, we read a byte that told us we were done. 232 | // Return all but that last byte, which would cause a syntax error if we let it through. 233 | if r.err == nil && !r.eof { 234 | return r.buf[:len(r.buf)-1], nil 235 | } 236 | 237 | // If we stopped for a syntax error, consume the whole file so that 238 | // we are sure we don't change the errors that go/parser returns. 239 | if r.err == errSyntax && !reportSyntaxError { 240 | r.err = nil 241 | for r.err == nil && !r.eof { 242 | r.readByte() 243 | } 244 | } 245 | 246 | return r.buf, r.err 247 | } 248 | -------------------------------------------------------------------------------- /go/build/syslist.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 build 6 | 7 | const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows zos " 8 | const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 " 9 | -------------------------------------------------------------------------------- /go/build/zcgo.go: -------------------------------------------------------------------------------- 1 | // Code generated by go tool dist; DO NOT EDIT. 2 | 3 | package build 4 | 5 | const defaultCGO_ENABLED = "" 6 | 7 | var cgoEnabled = map[string]bool{ 8 | "android/386": true, 9 | "android/amd64": true, 10 | "android/arm": true, 11 | "android/arm64": true, 12 | "darwin/386": true, 13 | "darwin/amd64": true, 14 | "darwin/arm": true, 15 | "darwin/arm64": true, 16 | "dragonfly/amd64": true, 17 | "freebsd/386": true, 18 | "freebsd/amd64": true, 19 | "linux/386": true, 20 | "linux/amd64": true, 21 | "linux/arm": true, 22 | "linux/arm64": true, 23 | "linux/mips": true, 24 | "linux/mips64": true, 25 | "linux/mips64le": true, 26 | "linux/mipsle": true, 27 | "linux/ppc64le": true, 28 | "linux/s390x": true, 29 | "netbsd/386": true, 30 | "netbsd/amd64": true, 31 | "netbsd/arm": true, 32 | "openbsd/386": true, 33 | "openbsd/amd64": true, 34 | "solaris/amd64": true, 35 | "windows/386": true, 36 | "windows/amd64": true, 37 | } 38 | -------------------------------------------------------------------------------- /go/doc/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2009 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 | # Script to test heading detection heuristic 6 | headscan: headscan.go 7 | go build headscan.go 8 | -------------------------------------------------------------------------------- /go/doc/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 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 doc extracts source code documentation from a Go AST. 6 | package doc 7 | 8 | import ( 9 | "github.com/faiface/generics/go/ast" 10 | "github.com/faiface/generics/go/token" 11 | ) 12 | 13 | // Package is the documentation for an entire package. 14 | type Package struct { 15 | Doc string 16 | Name string 17 | ImportPath string 18 | Imports []string 19 | Filenames []string 20 | Notes map[string][]*Note 21 | 22 | // Deprecated: For backward compatibility Bugs is still populated, 23 | // but all new code should use Notes instead. 24 | Bugs []string 25 | 26 | // declarations 27 | Consts []*Value 28 | Types []*Type 29 | Vars []*Value 30 | Funcs []*Func 31 | } 32 | 33 | // Value is the documentation for a (possibly grouped) var or const declaration. 34 | type Value struct { 35 | Doc string 36 | Names []string // var or const names in declaration order 37 | Decl *ast.GenDecl 38 | 39 | order int 40 | } 41 | 42 | // Type is the documentation for a type declaration. 43 | type Type struct { 44 | Doc string 45 | Name string 46 | Decl *ast.GenDecl 47 | 48 | // associated declarations 49 | Consts []*Value // sorted list of constants of (mostly) this type 50 | Vars []*Value // sorted list of variables of (mostly) this type 51 | Funcs []*Func // sorted list of functions returning this type 52 | Methods []*Func // sorted list of methods (including embedded ones) of this type 53 | } 54 | 55 | // Func is the documentation for a func declaration. 56 | type Func struct { 57 | Doc string 58 | Name string 59 | Decl *ast.FuncDecl 60 | 61 | // methods 62 | // (for functions, these fields have the respective zero value) 63 | Recv string // actual receiver "T" or "*T" 64 | Orig string // original receiver "T" or "*T" 65 | Level int // embedding level; 0 means not embedded 66 | } 67 | 68 | // A Note represents a marked comment starting with "MARKER(uid): note body". 69 | // Any note with a marker of 2 or more upper case [A-Z] letters and a uid of 70 | // at least one character is recognized. The ":" following the uid is optional. 71 | // Notes are collected in the Package.Notes map indexed by the notes marker. 72 | type Note struct { 73 | Pos, End token.Pos // position range of the comment containing the marker 74 | UID string // uid found with the marker 75 | Body string // note body text 76 | } 77 | 78 | // Mode values control the operation of New. 79 | type Mode int 80 | 81 | const ( 82 | // extract documentation for all package-level declarations, 83 | // not just exported ones 84 | AllDecls Mode = 1 << iota 85 | 86 | // show all embedded methods, not just the ones of 87 | // invisible (unexported) anonymous fields 88 | AllMethods 89 | ) 90 | 91 | // New computes the package documentation for the given package AST. 92 | // New takes ownership of the AST pkg and may edit or overwrite it. 93 | // 94 | func New(pkg *ast.Package, importPath string, mode Mode) *Package { 95 | var r reader 96 | r.readPackage(pkg, mode) 97 | r.computeMethodSets() 98 | r.cleanupTypes() 99 | return &Package{ 100 | Doc: r.doc, 101 | Name: pkg.Name, 102 | ImportPath: importPath, 103 | Imports: sortedKeys(r.imports), 104 | Filenames: r.filenames, 105 | Notes: r.notes, 106 | Bugs: noteBodies(r.notes["BUG"]), 107 | Consts: sortedValues(r.values, token.CONST), 108 | Types: sortedTypes(r.types, mode&AllMethods != 0), 109 | Vars: sortedValues(r.values, token.VAR), 110 | Funcs: sortedFuncs(r.funcs, true), 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /go/doc/filter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 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 doc 6 | 7 | import "github.com/faiface/generics/go/ast" 8 | 9 | type Filter func(string) bool 10 | 11 | func matchFields(fields *ast.FieldList, f Filter) bool { 12 | if fields != nil { 13 | for _, field := range fields.List { 14 | for _, name := range field.Names { 15 | if f(name.Name) { 16 | return true 17 | } 18 | } 19 | } 20 | } 21 | return false 22 | } 23 | 24 | func matchDecl(d *ast.GenDecl, f Filter) bool { 25 | for _, d := range d.Specs { 26 | switch v := d.(type) { 27 | case *ast.ValueSpec: 28 | for _, name := range v.Names { 29 | if f(name.Name) { 30 | return true 31 | } 32 | } 33 | case *ast.TypeSpec: 34 | if f(v.Name.Name) { 35 | return true 36 | } 37 | switch t := v.Type.(type) { 38 | case *ast.StructType: 39 | if matchFields(t.Fields, f) { 40 | return true 41 | } 42 | case *ast.InterfaceType: 43 | if matchFields(t.Methods, f) { 44 | return true 45 | } 46 | } 47 | } 48 | } 49 | return false 50 | } 51 | 52 | func filterValues(a []*Value, f Filter) []*Value { 53 | w := 0 54 | for _, vd := range a { 55 | if matchDecl(vd.Decl, f) { 56 | a[w] = vd 57 | w++ 58 | } 59 | } 60 | return a[0:w] 61 | } 62 | 63 | func filterFuncs(a []*Func, f Filter) []*Func { 64 | w := 0 65 | for _, fd := range a { 66 | if f(fd.Name) { 67 | a[w] = fd 68 | w++ 69 | } 70 | } 71 | return a[0:w] 72 | } 73 | 74 | func filterTypes(a []*Type, f Filter) []*Type { 75 | w := 0 76 | for _, td := range a { 77 | n := 0 // number of matches 78 | if matchDecl(td.Decl, f) { 79 | n = 1 80 | } else { 81 | // type name doesn't match, but we may have matching consts, vars, factories or methods 82 | td.Consts = filterValues(td.Consts, f) 83 | td.Vars = filterValues(td.Vars, f) 84 | td.Funcs = filterFuncs(td.Funcs, f) 85 | td.Methods = filterFuncs(td.Methods, f) 86 | n += len(td.Consts) + len(td.Vars) + len(td.Funcs) + len(td.Methods) 87 | } 88 | if n > 0 { 89 | a[w] = td 90 | w++ 91 | } 92 | } 93 | return a[0:w] 94 | } 95 | 96 | // Filter eliminates documentation for names that don't pass through the filter f. 97 | // TODO(gri): Recognize "Type.Method" as a name. 98 | // 99 | func (p *Package) Filter(f Filter) { 100 | p.Consts = filterValues(p.Consts, f) 101 | p.Vars = filterValues(p.Vars, f) 102 | p.Types = filterTypes(p.Types, f) 103 | p.Funcs = filterFuncs(p.Funcs, f) 104 | p.Doc = "" // don't show top-level package doc 105 | } 106 | -------------------------------------------------------------------------------- /go/doc/headscan.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 | // +build ignore 6 | 7 | /* 8 | The headscan command extracts comment headings from package files; 9 | it is used to detect false positives which may require an adjustment 10 | to the comment formatting heuristics in comment.go. 11 | 12 | Usage: headscan [-root root_directory] 13 | 14 | By default, the $GOROOT/src directory is scanned. 15 | */ 16 | package main 17 | 18 | import ( 19 | "bytes" 20 | "flag" 21 | "fmt" 22 | "github.com/faiface/generics/go/doc" 23 | "github.com/faiface/generics/go/parser" 24 | "github.com/faiface/generics/go/token" 25 | "os" 26 | "path/filepath" 27 | "regexp" 28 | "runtime" 29 | "strings" 30 | ) 31 | 32 | var ( 33 | root = flag.String("root", filepath.Join(runtime.GOROOT(), "src"), "root of filesystem tree to scan") 34 | verbose = flag.Bool("v", false, "verbose mode") 35 | ) 36 | 37 | // ToHTML in comment.go assigns a (possibly blank) ID to each heading 38 | var html_h = regexp.MustCompile(`

`) 39 | 40 | const html_endh = "

\n" 41 | 42 | func isGoFile(fi os.FileInfo) bool { 43 | return strings.HasSuffix(fi.Name(), ".go") && 44 | !strings.HasSuffix(fi.Name(), "_test.go") 45 | } 46 | 47 | func appendHeadings(list []string, comment string) []string { 48 | var buf bytes.Buffer 49 | doc.ToHTML(&buf, comment, nil) 50 | for s := buf.String(); ; { 51 | loc := html_h.FindStringIndex(s) 52 | if len(loc) == 0 { 53 | break 54 | } 55 | i := loc[1] 56 | j := strings.Index(s, html_endh) 57 | if j < 0 { 58 | list = append(list, s[i:]) // incorrect HTML 59 | break 60 | } 61 | list = append(list, s[i:j]) 62 | s = s[j+len(html_endh):] 63 | } 64 | return list 65 | } 66 | 67 | func main() { 68 | flag.Parse() 69 | fset := token.NewFileSet() 70 | nheadings := 0 71 | err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error { 72 | if !fi.IsDir() { 73 | return nil 74 | } 75 | pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments) 76 | if err != nil { 77 | if *verbose { 78 | fmt.Fprintln(os.Stderr, err) 79 | } 80 | return nil 81 | } 82 | for _, pkg := range pkgs { 83 | d := doc.New(pkg, path, doc.Mode(0)) 84 | list := appendHeadings(nil, d.Doc) 85 | for _, d := range d.Consts { 86 | list = appendHeadings(list, d.Doc) 87 | } 88 | for _, d := range d.Types { 89 | list = appendHeadings(list, d.Doc) 90 | } 91 | for _, d := range d.Vars { 92 | list = appendHeadings(list, d.Doc) 93 | } 94 | for _, d := range d.Funcs { 95 | list = appendHeadings(list, d.Doc) 96 | } 97 | if len(list) > 0 { 98 | // directories may contain multiple packages; 99 | // print path and package name 100 | fmt.Printf("%s (package %s)\n", path, pkg.Name) 101 | for _, h := range list { 102 | fmt.Printf("\t%s\n", h) 103 | } 104 | nheadings += len(list) 105 | } 106 | } 107 | return nil 108 | }) 109 | if err != nil { 110 | fmt.Fprintln(os.Stderr, err) 111 | os.Exit(1) 112 | } 113 | fmt.Println(nheadings, "headings found") 114 | } 115 | -------------------------------------------------------------------------------- /go/doc/synopsis.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 doc 6 | 7 | import ( 8 | "strings" 9 | "unicode" 10 | ) 11 | 12 | // firstSentenceLen returns the length of the first sentence in s. 13 | // The sentence ends after the first period followed by space and 14 | // not preceded by exactly one uppercase letter. 15 | // 16 | func firstSentenceLen(s string) int { 17 | var ppp, pp, p rune 18 | for i, q := range s { 19 | if q == '\n' || q == '\r' || q == '\t' { 20 | q = ' ' 21 | } 22 | if q == ' ' && p == '.' && (!unicode.IsUpper(pp) || unicode.IsUpper(ppp)) { 23 | return i 24 | } 25 | if p == '。' || p == '.' { 26 | return i 27 | } 28 | ppp, pp, p = pp, p, q 29 | } 30 | return len(s) 31 | } 32 | 33 | const ( 34 | keepNL = 1 << iota 35 | ) 36 | 37 | // clean replaces each sequence of space, \n, \r, or \t characters 38 | // with a single space and removes any trailing and leading spaces. 39 | // If the keepNL flag is set, newline characters are passed through 40 | // instead of being change to spaces. 41 | func clean(s string, flags int) string { 42 | var b []byte 43 | p := byte(' ') 44 | for i := 0; i < len(s); i++ { 45 | q := s[i] 46 | if (flags&keepNL) == 0 && q == '\n' || q == '\r' || q == '\t' { 47 | q = ' ' 48 | } 49 | if q != ' ' || p != ' ' { 50 | b = append(b, q) 51 | p = q 52 | } 53 | } 54 | // remove trailing blank, if any 55 | if n := len(b); n > 0 && p == ' ' { 56 | b = b[0 : n-1] 57 | } 58 | return string(b) 59 | } 60 | 61 | // Synopsis returns a cleaned version of the first sentence in s. 62 | // That sentence ends after the first period followed by space and 63 | // not preceded by exactly one uppercase letter. The result string 64 | // has no \n, \r, or \t characters and uses only single spaces between 65 | // words. If s starts with any of the IllegalPrefixes, the result 66 | // is the empty string. 67 | // 68 | func Synopsis(s string) string { 69 | s = clean(s[0:firstSentenceLen(s)], 0) 70 | for _, prefix := range IllegalPrefixes { 71 | if strings.HasPrefix(strings.ToLower(s), prefix) { 72 | return "" 73 | } 74 | } 75 | return s 76 | } 77 | 78 | var IllegalPrefixes = []string{ 79 | "copyright", 80 | "all rights", 81 | "author", 82 | } 83 | -------------------------------------------------------------------------------- /go/format/format.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 format implements standard formatting of Go source. 6 | package format 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "github.com/faiface/generics/go/ast" 12 | "github.com/faiface/generics/go/parser" 13 | "github.com/faiface/generics/go/printer" 14 | "github.com/faiface/generics/go/token" 15 | "io" 16 | ) 17 | 18 | var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} 19 | 20 | const parserMode = parser.ParseComments 21 | 22 | // Node formats node in canonical gofmt style and writes the result to dst. 23 | // 24 | // The node type must be *ast.File, *printer.CommentedNode, []ast.Decl, 25 | // []ast.Stmt, or assignment-compatible to ast.Expr, ast.Decl, ast.Spec, 26 | // or ast.Stmt. Node does not modify node. Imports are not sorted for 27 | // nodes representing partial source files (for instance, if the node is 28 | // not an *ast.File or a *printer.CommentedNode not wrapping an *ast.File). 29 | // 30 | // The function may return early (before the entire result is written) 31 | // and return a formatting error, for instance due to an incorrect AST. 32 | // 33 | func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { 34 | // Determine if we have a complete source file (file != nil). 35 | var file *ast.File 36 | var cnode *printer.CommentedNode 37 | switch n := node.(type) { 38 | case *ast.File: 39 | file = n 40 | case *printer.CommentedNode: 41 | if f, ok := n.Node.(*ast.File); ok { 42 | file = f 43 | cnode = n 44 | } 45 | } 46 | 47 | // Sort imports if necessary. 48 | if file != nil && hasUnsortedImports(file) { 49 | // Make a copy of the AST because ast.SortImports is destructive. 50 | // TODO(gri) Do this more efficiently. 51 | var buf bytes.Buffer 52 | err := config.Fprint(&buf, fset, file) 53 | if err != nil { 54 | return err 55 | } 56 | file, err = parser.ParseFile(fset, "", buf.Bytes(), parserMode) 57 | if err != nil { 58 | // We should never get here. If we do, provide good diagnostic. 59 | return fmt.Errorf("format.Node internal error (%s)", err) 60 | } 61 | ast.SortImports(fset, file) 62 | 63 | // Use new file with sorted imports. 64 | node = file 65 | if cnode != nil { 66 | node = &printer.CommentedNode{Node: file, Comments: cnode.Comments} 67 | } 68 | } 69 | 70 | return config.Fprint(dst, fset, node) 71 | } 72 | 73 | // Source formats src in canonical gofmt style and returns the result 74 | // or an (I/O or syntax) error. src is expected to be a syntactically 75 | // correct Go source file, or a list of Go declarations or statements. 76 | // 77 | // If src is a partial source file, the leading and trailing space of src 78 | // is applied to the result (such that it has the same leading and trailing 79 | // space as src), and the result is indented by the same amount as the first 80 | // line of src containing code. Imports are not sorted for partial source files. 81 | // 82 | // Caution: Tools relying on consistent formatting based on the installed 83 | // version of gofmt (for instance, such as for presubmit checks) should 84 | // execute that gofmt binary instead of calling Source. 85 | // 86 | func Source(src []byte) ([]byte, error) { 87 | fset := token.NewFileSet() 88 | file, sourceAdj, indentAdj, err := parse(fset, "", src, true) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | if sourceAdj == nil { 94 | // Complete source file. 95 | // TODO(gri) consider doing this always. 96 | ast.SortImports(fset, file) 97 | } 98 | 99 | return format(fset, file, sourceAdj, indentAdj, src, config) 100 | } 101 | 102 | func hasUnsortedImports(file *ast.File) bool { 103 | for _, d := range file.Decls { 104 | d, ok := d.(*ast.GenDecl) 105 | if !ok || d.Tok != token.IMPORT { 106 | // Not an import declaration, so we're done. 107 | // Imports are always first. 108 | return false 109 | } 110 | if d.Lparen.IsValid() { 111 | // For now assume all grouped imports are unsorted. 112 | // TODO(gri) Should check if they are sorted already. 113 | return true 114 | } 115 | // Ungrouped imports are sorted by default. 116 | } 117 | return false 118 | } 119 | -------------------------------------------------------------------------------- /go/format/internal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 | // TODO(gri): This file and the file src/cmd/gofmt/internal.go are 6 | // the same (but for this comment and the package name). Do not modify 7 | // one without the other. Determine if we can factor out functionality 8 | // in a public API. See also #11844 for context. 9 | 10 | package format 11 | 12 | import ( 13 | "bytes" 14 | "github.com/faiface/generics/go/ast" 15 | "github.com/faiface/generics/go/parser" 16 | "github.com/faiface/generics/go/printer" 17 | "github.com/faiface/generics/go/token" 18 | "strings" 19 | ) 20 | 21 | // parse parses src, which was read from the named file, 22 | // as a Go source file, declaration, or statement list. 23 | func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( 24 | file *ast.File, 25 | sourceAdj func(src []byte, indent int) []byte, 26 | indentAdj int, 27 | err error, 28 | ) { 29 | // Try as whole source file. 30 | file, err = parser.ParseFile(fset, filename, src, parserMode) 31 | // If there's no error, return. If the error is that the source file didn't begin with a 32 | // package line and source fragments are ok, fall through to 33 | // try as a source fragment. Stop and return on any other error. 34 | if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { 35 | return 36 | } 37 | 38 | // If this is a declaration list, make it a source file 39 | // by inserting a package clause. 40 | // Insert using a ';', not a newline, so that the line numbers 41 | // in psrc match the ones in src. 42 | psrc := append([]byte("package p;"), src...) 43 | file, err = parser.ParseFile(fset, filename, psrc, parserMode) 44 | if err == nil { 45 | sourceAdj = func(src []byte, indent int) []byte { 46 | // Remove the package clause. 47 | // Gofmt has turned the ';' into a '\n'. 48 | src = src[indent+len("package p\n"):] 49 | return bytes.TrimSpace(src) 50 | } 51 | return 52 | } 53 | // If the error is that the source file didn't begin with a 54 | // declaration, fall through to try as a statement list. 55 | // Stop and return on any other error. 56 | if !strings.Contains(err.Error(), "expected declaration") { 57 | return 58 | } 59 | 60 | // If this is a statement list, make it a source file 61 | // by inserting a package clause and turning the list 62 | // into a function body. This handles expressions too. 63 | // Insert using a ';', not a newline, so that the line numbers 64 | // in fsrc match the ones in src. Add an extra '\n' before the '}' 65 | // to make sure comments are flushed before the '}'. 66 | fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}') 67 | file, err = parser.ParseFile(fset, filename, fsrc, parserMode) 68 | if err == nil { 69 | sourceAdj = func(src []byte, indent int) []byte { 70 | // Cap adjusted indent to zero. 71 | if indent < 0 { 72 | indent = 0 73 | } 74 | // Remove the wrapping. 75 | // Gofmt has turned the ';' into a '\n'. 76 | // There will be two non-blank lines with indent, hence 2*indent. 77 | src = src[2*indent+len("package p\n\nfunc _() {"):] 78 | // Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway 79 | src = src[:len(src)-len("}\n")] 80 | return bytes.TrimSpace(src) 81 | } 82 | // Gofmt has also indented the function body one level. 83 | // Adjust that with indentAdj. 84 | indentAdj = -1 85 | } 86 | 87 | // Succeeded, or out of options. 88 | return 89 | } 90 | 91 | // format formats the given package file originally obtained from src 92 | // and adjusts the result based on the original source via sourceAdj 93 | // and indentAdj. 94 | func format( 95 | fset *token.FileSet, 96 | file *ast.File, 97 | sourceAdj func(src []byte, indent int) []byte, 98 | indentAdj int, 99 | src []byte, 100 | cfg printer.Config, 101 | ) ([]byte, error) { 102 | if sourceAdj == nil { 103 | // Complete source file. 104 | var buf bytes.Buffer 105 | err := cfg.Fprint(&buf, fset, file) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return buf.Bytes(), nil 110 | } 111 | 112 | // Partial source file. 113 | // Determine and prepend leading space. 114 | i, j := 0, 0 115 | for j < len(src) && isSpace(src[j]) { 116 | if src[j] == '\n' { 117 | i = j + 1 // byte offset of last line in leading space 118 | } 119 | j++ 120 | } 121 | var res []byte 122 | res = append(res, src[:i]...) 123 | 124 | // Determine and prepend indentation of first code line. 125 | // Spaces are ignored unless there are no tabs, 126 | // in which case spaces count as one tab. 127 | indent := 0 128 | hasSpace := false 129 | for _, b := range src[i:j] { 130 | switch b { 131 | case ' ': 132 | hasSpace = true 133 | case '\t': 134 | indent++ 135 | } 136 | } 137 | if indent == 0 && hasSpace { 138 | indent = 1 139 | } 140 | for i := 0; i < indent; i++ { 141 | res = append(res, '\t') 142 | } 143 | 144 | // Format the source. 145 | // Write it without any leading and trailing space. 146 | cfg.Indent = indent + indentAdj 147 | var buf bytes.Buffer 148 | err := cfg.Fprint(&buf, fset, file) 149 | if err != nil { 150 | return nil, err 151 | } 152 | out := sourceAdj(buf.Bytes(), cfg.Indent) 153 | 154 | // If the adjusted output is empty, the source 155 | // was empty but (possibly) for white space. 156 | // The result is the incoming source. 157 | if len(out) == 0 { 158 | return src, nil 159 | } 160 | 161 | // Otherwise, append output to leading space. 162 | res = append(res, out...) 163 | 164 | // Determine and append trailing space. 165 | i = len(src) 166 | for i > 0 && isSpace(src[i-1]) { 167 | i-- 168 | } 169 | return append(res, src[i:]...), nil 170 | } 171 | 172 | // isSpace reports whether the byte is a space character. 173 | // isSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'. 174 | func isSpace(b byte) bool { 175 | return b == ' ' || b == '\t' || b == '\n' || b == '\r' 176 | } 177 | -------------------------------------------------------------------------------- /go/importer/importer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 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 importer provides access to export data importers. 6 | package importer 7 | 8 | import ( 9 | "io" 10 | "runtime" 11 | 12 | "github.com/faiface/generics/go/build" 13 | "github.com/faiface/generics/go/internal/gccgoimporter" 14 | "github.com/faiface/generics/go/internal/gcimporter" 15 | "github.com/faiface/generics/go/internal/srcimporter" 16 | "github.com/faiface/generics/go/token" 17 | "github.com/faiface/generics/go/types" 18 | ) 19 | 20 | // A Lookup function returns a reader to access package data for 21 | // a given import path, or an error if no matching package is found. 22 | type Lookup func(path string) (io.ReadCloser, error) 23 | 24 | // ForCompiler returns an Importer for importing from installed packages 25 | // for the compilers "gc" and "gccgo", or for importing directly 26 | // from the source if the compiler argument is "source". In this 27 | // latter case, importing may fail under circumstances where the 28 | // exported API is not entirely defined in pure Go source code 29 | // (if the package API depends on cgo-defined entities, the type 30 | // checker won't have access to those). 31 | // 32 | // If lookup is nil, the default package lookup mechanism for the 33 | // given compiler is used, and the resulting importer attempts 34 | // to resolve relative and absolute import paths to canonical 35 | // import path IDs before finding the imported file. 36 | // 37 | // If lookup is non-nil, then the returned importer calls lookup 38 | // each time it needs to resolve an import path. In this mode 39 | // the importer can only be invoked with canonical import paths 40 | // (not relative or absolute ones); it is assumed that the translation 41 | // to canonical import paths is being done by the client of the 42 | // importer. 43 | func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Importer { 44 | switch compiler { 45 | case "gc": 46 | return &gcimports{ 47 | fset: fset, 48 | packages: make(map[string]*types.Package), 49 | lookup: lookup, 50 | } 51 | 52 | case "gccgo": 53 | var inst gccgoimporter.GccgoInstallation 54 | if err := inst.InitFromDriver("gccgo"); err != nil { 55 | return nil 56 | } 57 | return &gccgoimports{ 58 | packages: make(map[string]*types.Package), 59 | importer: inst.GetImporter(nil, nil), 60 | lookup: lookup, 61 | } 62 | 63 | case "source": 64 | if lookup != nil { 65 | panic("source importer for custom import path lookup not supported (issue #13847).") 66 | } 67 | 68 | return srcimporter.New(&build.Default, fset, make(map[string]*types.Package)) 69 | } 70 | 71 | // compiler not supported 72 | return nil 73 | } 74 | 75 | // For calls ForCompiler with a new FileSet. 76 | // 77 | // Deprecated: use ForCompiler, which populates a FileSet 78 | // with the positions of objects created by the importer. 79 | func For(compiler string, lookup Lookup) types.Importer { 80 | return ForCompiler(token.NewFileSet(), compiler, lookup) 81 | } 82 | 83 | // Default returns an Importer for the compiler that built the running binary. 84 | // If available, the result implements types.ImporterFrom. 85 | func Default() types.Importer { 86 | return For(runtime.Compiler, nil) 87 | } 88 | 89 | // gc importer 90 | 91 | type gcimports struct { 92 | fset *token.FileSet 93 | packages map[string]*types.Package 94 | lookup Lookup 95 | } 96 | 97 | func (m *gcimports) Import(path string) (*types.Package, error) { 98 | return m.ImportFrom(path, "" /* no vendoring */, 0) 99 | } 100 | 101 | func (m *gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) { 102 | if mode != 0 { 103 | panic("mode must be 0") 104 | } 105 | return gcimporter.Import(m.fset, m.packages, path, srcDir, m.lookup) 106 | } 107 | 108 | // gccgo importer 109 | 110 | type gccgoimports struct { 111 | packages map[string]*types.Package 112 | importer gccgoimporter.Importer 113 | lookup Lookup 114 | } 115 | 116 | func (m *gccgoimports) Import(path string) (*types.Package, error) { 117 | return m.ImportFrom(path, "" /* no vendoring */, 0) 118 | } 119 | 120 | func (m *gccgoimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) { 121 | if mode != 0 { 122 | panic("mode must be 0") 123 | } 124 | return m.importer(m.packages, path, srcDir, m.lookup) 125 | } 126 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/ar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 gccgoimporter 6 | 7 | import ( 8 | "bytes" 9 | "debug/elf" 10 | "errors" 11 | "fmt" 12 | "io" 13 | "strconv" 14 | "strings" 15 | 16 | "github.com/faiface/generics/go/internal/xcoff" 17 | ) 18 | 19 | // Magic strings for different archive file formats. 20 | const ( 21 | armag = "!\n" 22 | armagt = "!\n" 23 | armagb = "\n" 24 | ) 25 | 26 | // Offsets and sizes for fields in a standard archive header. 27 | const ( 28 | arNameOff = 0 29 | arNameSize = 16 30 | arDateOff = arNameOff + arNameSize 31 | arDateSize = 12 32 | arUIDOff = arDateOff + arDateSize 33 | arUIDSize = 6 34 | arGIDOff = arUIDOff + arUIDSize 35 | arGIDSize = 6 36 | arModeOff = arGIDOff + arGIDSize 37 | arModeSize = 8 38 | arSizeOff = arModeOff + arModeSize 39 | arSizeSize = 10 40 | arFmagOff = arSizeOff + arSizeSize 41 | arFmagSize = 2 42 | 43 | arHdrSize = arFmagOff + arFmagSize 44 | ) 45 | 46 | // The contents of the fmag field of a standard archive header. 47 | const arfmag = "`\n" 48 | 49 | // arExportData takes an archive file and returns a ReadSeeker for the 50 | // export data in that file. This assumes that there is only one 51 | // object in the archive containing export data, which is not quite 52 | // what gccgo does; gccgo concatenates together all the export data 53 | // for all the objects in the file. In practice that case does not arise. 54 | func arExportData(archive io.ReadSeeker) (io.ReadSeeker, error) { 55 | if _, err := archive.Seek(0, io.SeekStart); err != nil { 56 | return nil, err 57 | } 58 | 59 | var buf [len(armag)]byte 60 | if _, err := archive.Read(buf[:]); err != nil { 61 | return nil, err 62 | } 63 | 64 | switch string(buf[:]) { 65 | case armag: 66 | return standardArExportData(archive) 67 | case armagt: 68 | return nil, errors.New("unsupported thin archive") 69 | case armagb: 70 | return aixBigArExportData(archive) 71 | default: 72 | return nil, fmt.Errorf("unrecognized archive file format %q", buf[:]) 73 | } 74 | } 75 | 76 | // standardArExportData returns export data from a standard archive. 77 | func standardArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) { 78 | off := int64(len(armag)) 79 | for { 80 | var hdrBuf [arHdrSize]byte 81 | if _, err := archive.Read(hdrBuf[:]); err != nil { 82 | return nil, err 83 | } 84 | off += arHdrSize 85 | 86 | if bytes.Compare(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) != 0 { 87 | return nil, fmt.Errorf("archive header format header (%q)", hdrBuf[:]) 88 | } 89 | 90 | size, err := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 10, 64) 91 | if err != nil { 92 | return nil, fmt.Errorf("error parsing size in archive header (%q): %v", hdrBuf[:], err) 93 | } 94 | 95 | fn := hdrBuf[arNameOff : arNameOff+arNameSize] 96 | if fn[0] == '/' && (fn[1] == ' ' || fn[1] == '/' || bytes.Compare(fn[:8], []byte("/SYM64/ ")) == 0) { 97 | // Archive symbol table or extended name table, 98 | // which we don't care about. 99 | } else { 100 | archiveAt := readerAtFromSeeker(archive) 101 | ret, err := elfFromAr(io.NewSectionReader(archiveAt, off, size)) 102 | if ret != nil || err != nil { 103 | return ret, err 104 | } 105 | } 106 | 107 | if size&1 != 0 { 108 | size++ 109 | } 110 | off += size 111 | if _, err := archive.Seek(off, io.SeekStart); err != nil { 112 | return nil, err 113 | } 114 | } 115 | } 116 | 117 | // elfFromAr tries to get export data from an archive member as an ELF file. 118 | // If there is no export data, this returns nil, nil. 119 | func elfFromAr(member *io.SectionReader) (io.ReadSeeker, error) { 120 | ef, err := elf.NewFile(member) 121 | if err != nil { 122 | return nil, err 123 | } 124 | sec := ef.Section(".go_export") 125 | if sec == nil { 126 | return nil, nil 127 | } 128 | return sec.Open(), nil 129 | } 130 | 131 | // aixBigArExportData returns export data from an AIX big archive. 132 | func aixBigArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) { 133 | archiveAt := readerAtFromSeeker(archive) 134 | arch, err := xcoff.NewArchive(archiveAt) 135 | if err != nil { 136 | return nil, err 137 | } 138 | 139 | for _, mem := range arch.Members { 140 | f, err := arch.GetFile(mem.Name) 141 | if err != nil { 142 | return nil, err 143 | } 144 | sdat := f.CSect(".go_export") 145 | if sdat != nil { 146 | return bytes.NewReader(sdat), nil 147 | } 148 | } 149 | 150 | return nil, fmt.Errorf(".go_export not found in this archive") 151 | } 152 | 153 | // readerAtFromSeeker turns an io.ReadSeeker into an io.ReaderAt. 154 | // This is only safe because there won't be any concurrent seeks 155 | // while this code is executing. 156 | func readerAtFromSeeker(rs io.ReadSeeker) io.ReaderAt { 157 | if ret, ok := rs.(io.ReaderAt); ok { 158 | return ret 159 | } 160 | return seekerReadAt{rs} 161 | } 162 | 163 | type seekerReadAt struct { 164 | seeker io.ReadSeeker 165 | } 166 | 167 | func (sra seekerReadAt) ReadAt(p []byte, off int64) (int, error) { 168 | if _, err := sra.seeker.Seek(off, io.SeekStart); err != nil { 169 | return 0, err 170 | } 171 | return sra.seeker.Read(p) 172 | } 173 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/gccgoinstallation.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 gccgoimporter 6 | 7 | import ( 8 | "bufio" 9 | "github.com/faiface/generics/go/types" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "strings" 14 | ) 15 | 16 | // Information about a specific installation of gccgo. 17 | type GccgoInstallation struct { 18 | // Version of gcc (e.g. 4.8.0). 19 | GccVersion string 20 | 21 | // Target triple (e.g. x86_64-unknown-linux-gnu). 22 | TargetTriple string 23 | 24 | // Built-in library paths used by this installation. 25 | LibPaths []string 26 | } 27 | 28 | // Ask the driver at the given path for information for this GccgoInstallation. 29 | // The given arguments are passed directly to the call of the driver. 30 | func (inst *GccgoInstallation) InitFromDriver(gccgoPath string, args ...string) (err error) { 31 | argv := append([]string{"-###", "-S", "-x", "go", "-"}, args...) 32 | cmd := exec.Command(gccgoPath, argv...) 33 | stderr, err := cmd.StderrPipe() 34 | if err != nil { 35 | return 36 | } 37 | 38 | err = cmd.Start() 39 | if err != nil { 40 | return 41 | } 42 | 43 | scanner := bufio.NewScanner(stderr) 44 | for scanner.Scan() { 45 | line := scanner.Text() 46 | switch { 47 | case strings.HasPrefix(line, "Target: "): 48 | inst.TargetTriple = line[8:] 49 | 50 | case line[0] == ' ': 51 | args := strings.Fields(line) 52 | for _, arg := range args[1:] { 53 | if strings.HasPrefix(arg, "-L") { 54 | inst.LibPaths = append(inst.LibPaths, arg[2:]) 55 | } 56 | } 57 | } 58 | } 59 | 60 | argv = append([]string{"-dumpversion"}, args...) 61 | stdout, err := exec.Command(gccgoPath, argv...).Output() 62 | if err != nil { 63 | return 64 | } 65 | inst.GccVersion = strings.TrimSpace(string(stdout)) 66 | 67 | return 68 | } 69 | 70 | // Return the list of export search paths for this GccgoInstallation. 71 | func (inst *GccgoInstallation) SearchPaths() (paths []string) { 72 | for _, lpath := range inst.LibPaths { 73 | spath := filepath.Join(lpath, "go", inst.GccVersion) 74 | fi, err := os.Stat(spath) 75 | if err != nil || !fi.IsDir() { 76 | continue 77 | } 78 | paths = append(paths, spath) 79 | 80 | spath = filepath.Join(spath, inst.TargetTriple) 81 | fi, err = os.Stat(spath) 82 | if err != nil || !fi.IsDir() { 83 | continue 84 | } 85 | paths = append(paths, spath) 86 | } 87 | 88 | paths = append(paths, inst.LibPaths...) 89 | 90 | return 91 | } 92 | 93 | // Return an importer that searches incpaths followed by the gcc installation's 94 | // built-in search paths and the current directory. 95 | func (inst *GccgoInstallation) GetImporter(incpaths []string, initmap map[*types.Package]InitData) Importer { 96 | return GetImporter(append(append(incpaths, inst.SearchPaths()...), "."), initmap) 97 | } 98 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/gccgoinstallation_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 gccgoimporter 6 | 7 | import ( 8 | "github.com/faiface/generics/go/types" 9 | "testing" 10 | ) 11 | 12 | // importablePackages is a list of packages that we verify that we can 13 | // import. This should be all standard library packages in all relevant 14 | // versions of gccgo. Note that since gccgo follows a different release 15 | // cycle, and since different systems have different versions installed, 16 | // we can't use the last-two-versions rule of the gc toolchain. 17 | var importablePackages = [...]string{ 18 | "archive/tar", 19 | "archive/zip", 20 | "bufio", 21 | "bytes", 22 | "compress/bzip2", 23 | "compress/flate", 24 | "compress/gzip", 25 | "compress/lzw", 26 | "compress/zlib", 27 | "container/heap", 28 | "container/list", 29 | "container/ring", 30 | "crypto/aes", 31 | "crypto/cipher", 32 | "crypto/des", 33 | "crypto/dsa", 34 | "crypto/ecdsa", 35 | "crypto/elliptic", 36 | "crypto", 37 | "crypto/hmac", 38 | "crypto/md5", 39 | "crypto/rand", 40 | "crypto/rc4", 41 | "crypto/rsa", 42 | "crypto/sha1", 43 | "crypto/sha256", 44 | "crypto/sha512", 45 | "crypto/subtle", 46 | "crypto/tls", 47 | "crypto/x509", 48 | "crypto/x509/pkix", 49 | "database/sql/driver", 50 | "database/sql", 51 | "debug/dwarf", 52 | "debug/elf", 53 | "debug/gosym", 54 | "debug/macho", 55 | "debug/pe", 56 | "encoding/ascii85", 57 | "encoding/asn1", 58 | "encoding/base32", 59 | "encoding/base64", 60 | "encoding/binary", 61 | "encoding/csv", 62 | "encoding/gob", 63 | // "encoding", // Added in GCC 4.9. 64 | "encoding/hex", 65 | "encoding/json", 66 | "encoding/pem", 67 | "encoding/xml", 68 | "errors", 69 | "expvar", 70 | "flag", 71 | "fmt", 72 | "github.com/faiface/generics/go/ast", 73 | "github.com/faiface/generics/go/build", 74 | "github.com/faiface/generics/go/doc", 75 | // "github.com/faiface/generics/go/format", // Added in GCC 4.8. 76 | "github.com/faiface/generics/go/parser", 77 | "github.com/faiface/generics/go/printer", 78 | "github.com/faiface/generics/go/scanner", 79 | "github.com/faiface/generics/go/token", 80 | "hash/adler32", 81 | "hash/crc32", 82 | "hash/crc64", 83 | "hash/fnv", 84 | "hash", 85 | "html", 86 | "html/template", 87 | "image/color", 88 | // "image/color/palette", // Added in GCC 4.9. 89 | "image/draw", 90 | "image/gif", 91 | "image", 92 | "image/jpeg", 93 | "image/png", 94 | "index/suffixarray", 95 | "io", 96 | "io/ioutil", 97 | "log", 98 | "log/syslog", 99 | "math/big", 100 | "math/cmplx", 101 | "math", 102 | "math/rand", 103 | "mime", 104 | "mime/multipart", 105 | "net", 106 | "net/http/cgi", 107 | // "net/http/cookiejar", // Added in GCC 4.8. 108 | "net/http/fcgi", 109 | "net/http", 110 | "net/http/httptest", 111 | "net/http/httputil", 112 | "net/http/pprof", 113 | "net/mail", 114 | "net/rpc", 115 | "net/rpc/jsonrpc", 116 | "net/smtp", 117 | "net/textproto", 118 | "net/url", 119 | "os/exec", 120 | "os", 121 | "os/signal", 122 | "os/user", 123 | "path/filepath", 124 | "path", 125 | "reflect", 126 | "regexp", 127 | "regexp/syntax", 128 | "runtime/debug", 129 | "runtime", 130 | "runtime/pprof", 131 | "sort", 132 | "strconv", 133 | "strings", 134 | "sync/atomic", 135 | "sync", 136 | "syscall", 137 | "testing", 138 | "testing/iotest", 139 | "testing/quick", 140 | "text/scanner", 141 | "text/tabwriter", 142 | "text/template", 143 | "text/template/parse", 144 | "time", 145 | "unicode", 146 | "unicode/utf16", 147 | "unicode/utf8", 148 | } 149 | 150 | func TestInstallationImporter(t *testing.T) { 151 | // This test relies on gccgo being around. 152 | gpath := gccgoPath() 153 | if gpath == "" { 154 | t.Skip("This test needs gccgo") 155 | } 156 | 157 | var inst GccgoInstallation 158 | err := inst.InitFromDriver(gpath) 159 | if err != nil { 160 | t.Fatal(err) 161 | } 162 | imp := inst.GetImporter(nil, nil) 163 | 164 | // Ensure we don't regress the number of packages we can parse. First import 165 | // all packages into the same map and then each individually. 166 | pkgMap := make(map[string]*types.Package) 167 | for _, pkg := range importablePackages { 168 | _, err = imp(pkgMap, pkg, ".", nil) 169 | if err != nil { 170 | t.Error(err) 171 | } 172 | } 173 | 174 | for _, pkg := range importablePackages { 175 | _, err = imp(make(map[string]*types.Package), pkg, ".", nil) 176 | if err != nil { 177 | t.Error(err) 178 | } 179 | } 180 | 181 | // Test for certain specific entities in the imported data. 182 | for _, test := range [...]importerTest{ 183 | {pkgpath: "io", name: "Reader", want: "type Reader interface{Read(p []byte) (n int, err error)}"}, 184 | {pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"}, 185 | {pkgpath: "math", name: "Pi", want: "const Pi untyped float"}, 186 | {pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"}, 187 | {pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"}, 188 | {pkgpath: "unsafe", name: "Pointer", want: "type Pointer"}, 189 | } { 190 | runImporterTest(t, imp, nil, &test) 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/parser_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 gccgoimporter 6 | 7 | import ( 8 | "bytes" 9 | "github.com/faiface/generics/go/types" 10 | "strings" 11 | "testing" 12 | "text/scanner" 13 | ) 14 | 15 | var typeParserTests = []struct { 16 | id, typ, want, underlying, methods string 17 | }{ 18 | {id: "foo", typ: "", want: "int8"}, 19 | {id: "foo", typ: ">", want: "*error"}, 20 | {id: "foo", typ: "", want: "unsafe.Pointer"}, 21 | {id: "foo", typ: ">>", want: "foo.Bar", underlying: "*foo.Bar"}, 22 | {id: "foo", typ: "\nfunc (? ) M ();\n>", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"}, 23 | {id: "foo", typ: ">", want: "bar.foo", underlying: "int8"}, 24 | {id: "foo", typ: ">", want: "[]int8"}, 25 | {id: "foo", typ: ">", want: "[42]int8"}, 26 | {id: "foo", typ: "] >", want: "map[int8]int16"}, 27 | {id: "foo", typ: ">", want: "chan int8"}, 28 | {id: "foo", typ: ">", want: "<-chan int8"}, 29 | {id: "foo", typ: ">", want: "chan<- int8"}, 30 | {id: "foo", typ: "; I16 \"i16\"; }>", want: "struct{I8 int8; I16 int16 \"i16\"}"}, 31 | {id: "foo", typ: ", b ) ; Bar (? , ? ...) (? , ? ); Baz (); }>", want: "interface{Bar(int16, ...int8) (int16, int8); Baz(); Foo(a int8, b int16) int8}"}, 32 | {id: "foo", typ: ") >", want: "func(int8) int16"}, 33 | } 34 | 35 | func TestTypeParser(t *testing.T) { 36 | for _, test := range typeParserTests { 37 | var p parser 38 | p.init("test.gox", strings.NewReader(test.typ), make(map[string]*types.Package)) 39 | p.version = "v2" 40 | p.pkgname = test.id 41 | p.pkgpath = test.id 42 | p.maybeCreatePackage() 43 | typ := p.parseType(p.pkg) 44 | 45 | if p.tok != scanner.EOF { 46 | t.Errorf("expected full parse, stopped at %q", p.lit) 47 | } 48 | 49 | // interfaces must be explicitly completed 50 | if ityp, _ := typ.(*types.Interface); ityp != nil { 51 | ityp.Complete() 52 | } 53 | 54 | got := typ.String() 55 | if got != test.want { 56 | t.Errorf("got type %q, expected %q", got, test.want) 57 | } 58 | 59 | if test.underlying != "" { 60 | underlying := typ.Underlying().String() 61 | if underlying != test.underlying { 62 | t.Errorf("got underlying type %q, expected %q", underlying, test.underlying) 63 | } 64 | } 65 | 66 | if test.methods != "" { 67 | nt := typ.(*types.Named) 68 | var buf bytes.Buffer 69 | for i := 0; i != nt.NumMethods(); i++ { 70 | buf.WriteString(nt.Method(i).String()) 71 | } 72 | methods := buf.String() 73 | if methods != test.methods { 74 | t.Errorf("got methods %q, expected %q", methods, test.methods) 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/aliases.go: -------------------------------------------------------------------------------- 1 | package aliases 2 | 3 | type ( 4 | T0 [10]int 5 | T1 []byte 6 | T2 struct { 7 | x int 8 | } 9 | T3 interface { 10 | m() T2 11 | } 12 | T4 func(int, T0) chan T2 13 | ) 14 | 15 | // basic aliases 16 | type ( 17 | Ai = int 18 | A0 = T0 19 | A1 = T1 20 | A2 = T2 21 | A3 = T3 22 | A4 = T4 23 | 24 | A10 = [10]int 25 | A11 = []byte 26 | A12 = struct { 27 | x int 28 | } 29 | A13 = interface { 30 | m() A2 31 | } 32 | A14 = func(int, A0) chan A2 33 | ) 34 | 35 | // alias receiver types 36 | func (T0) m1() {} 37 | func (A0) m2() {} 38 | 39 | // alias receiver types (long type declaration chains) 40 | type ( 41 | V0 = V1 42 | V1 = (V2) 43 | V2 = (V3) 44 | V3 = T0 45 | ) 46 | 47 | func (V1) n() {} 48 | 49 | // cycles 50 | type C0 struct { 51 | f1 C1 52 | f2 C2 53 | } 54 | 55 | type ( 56 | C1 *C0 57 | C2 = C1 58 | ) 59 | 60 | type ( 61 | C5 struct { 62 | f *C6 63 | } 64 | C6 = C5 65 | ) 66 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/aliases.gox: -------------------------------------------------------------------------------- 1 | v2; 2 | package aliases; 3 | prefix go; 4 | package aliases go.aliases go.aliases; 5 | type > 6 | func (? ) .go.aliases.m1 (); 7 | func (? ) .go.aliases.m2 (); 8 | func (? >>>) .go.aliases.n (); 9 | >>; 10 | type >>>; 11 | type >>; 12 | type >>; 13 | type ; }>>; 14 | type ; }>>>; }>>; 15 | type , ? ) >>>; 16 | type ; 17 | type ; }>>>; 18 | type , ? ) >>>>; 19 | type >; 20 | type >>; .go.aliases.f2 >; }>>; 21 | type ; 22 | type ; 23 | type >>; }>>; 24 | type ; 25 | type ; 26 | type ; 27 | type ; 28 | type ; 29 | type ; 30 | type >; 31 | type ; 32 | type ; 33 | type ; 34 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/complexnums.go: -------------------------------------------------------------------------------- 1 | package complexnums 2 | 3 | const NN = -1 - 1i 4 | const NP = -1 + 1i 5 | const PN = 1 - 1i 6 | const PP = 1 + 1i 7 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/complexnums.gox: -------------------------------------------------------------------------------- 1 | v1; 2 | package complexnums; 3 | pkgpath complexnums; 4 | priority 1; 5 | const NN = -0.1E1-0.1E1i ; 6 | const NP = -0.1E1+0.1E1i ; 7 | const PN = 0.1E1-0.1E1i ; 8 | const PP = 0.1E1+0.1E1i ; 9 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/conversions.go: -------------------------------------------------------------------------------- 1 | package conversions 2 | 3 | type Units string 4 | 5 | const Bits = Units("bits") 6 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/conversions.gox: -------------------------------------------------------------------------------- 1 | v2; 2 | package conversions; 3 | prefix go; 4 | package conversions go.conversions go.conversions; 5 | const Bits > = convert(, "bits"); 6 | type ; 7 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/escapeinfo.go: -------------------------------------------------------------------------------- 1 | // Test case for escape info in export data. To compile and extract .gox file: 2 | // gccgo -fgo-optimize-allocs -c escapeinfo.go 3 | // objcopy -j .go_export escapeinfo.o escapeinfo.gox 4 | 5 | package escapeinfo 6 | 7 | type T struct{ data []byte } 8 | 9 | func NewT(data []byte) *T { 10 | return &T{data} 11 | } 12 | 13 | func (*T) Read(p []byte) {} 14 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/escapeinfo.gox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gccgoimporter/testdata/escapeinfo.gox -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/imports.go: -------------------------------------------------------------------------------- 1 | package imports 2 | 3 | import "fmt" 4 | 5 | var Hello = fmt.Sprintf("Hello, world") 6 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/imports.gox: -------------------------------------------------------------------------------- 1 | v1; 2 | package imports; 3 | pkgpath imports; 4 | priority 7; 5 | import fmt fmt "fmt"; 6 | init imports imports..import 7 math math..import 1 runtime runtime..import 1 strconv strconv..import 2 io io..import 3 reflect reflect..import 3 syscall syscall..import 3 time time..import 4 os os..import 5 fmt fmt..import 6; 7 | var Hello ; 8 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/issue27856.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | type M struct { 4 | E E 5 | } 6 | type F struct { 7 | _ *M 8 | } 9 | type E = F 10 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/issue27856.gox: -------------------------------------------------------------------------------- 1 | v2; 2 | package main; 3 | pkgpath main; 4 | import runtime runtime "runtime"; 5 | init runtime runtime..import sys runtime_internal_sys..import; 6 | init_graph 0 1; 7 | type ; }>>>; }>>>; 8 | type ; 9 | type ; 10 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/issue29198.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 server 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | ) 11 | 12 | type A struct { 13 | x int 14 | } 15 | 16 | func (a *A) AMethod(y int) *Server { 17 | return nil 18 | } 19 | 20 | // FooServer is a server that provides Foo services 21 | type FooServer Server 22 | 23 | func (f *FooServer) WriteEvents(ctx context.Context, x int) error { 24 | return errors.New("hey!") 25 | } 26 | 27 | type Server struct { 28 | FooServer *FooServer 29 | user string 30 | ctx context.Context 31 | } 32 | 33 | func New(sctx context.Context, u string) (*Server, error) { 34 | s := &Server{user: u, ctx: sctx} 35 | s.FooServer = (*FooServer)(s) 36 | return s, nil 37 | } 38 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/issue29198.gox: -------------------------------------------------------------------------------- 1 | v2; 2 | package server; 3 | pkgpath issue29198; 4 | import context context "context"; 5 | import errors errors "errors"; 6 | init context context..import fmt fmt..import poll internal_poll..import testlog internal_testlog..import io io..import os os..import reflect reflect..import runtime runtime..import sys runtime_internal_sys..import strconv strconv..import sync sync..import syscall syscall..import time time..import unicode unicode..import; 7 | init_graph 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 2 4 2 7 2 8 2 10 2 11 2 12 4 7 4 8 4 10 5 2 5 3 5 4 5 7 5 8 5 10 5 11 5 12 6 7 6 8 6 9 6 10 6 13 7 8 9 7 9 8 10 7 10 8 11 7 11 8 11 10 12 7 12 8 12 10 12 11; 8 | type ; }> 9 | func (a >) AMethod (y ) 10 | func (f >) WriteEvents (ctx ; .time.ext ; .time.loc ; .time.zone ; .time.offset ; .time.isDST ; }>>>; .time.tx ; .time.index ; .time.isstd ; .time.isutc ; }>>>; .time.cacheStart ; .time.cacheEnd ; .time.cacheZone >; }> 11 | func (l >) String () ; 12 | func (l ) .time.lookupFirstZone () ; 13 | func (l ) .time.get () ; 14 | func (l ) .time.lookup (sec ) (name , offset , isDST , start , end ); 15 | func (l ) .time.lookupName (name , unix ) (offset , ok ); 16 | func (l ) .time.firstZoneUsed () ; 17 | >>; }> 18 | func (t ) In (loc ) ; 19 | func (t ) .time.date (full ) (year , month 20 | func (m ) String () ; 21 | >, day , yday ); 22 | func (t ) Sub (u ) 23 | func (d ) Truncate (m ) ; 24 | func (d ) String () ; 25 | func (d ) Round (m ) ; 26 | func (d ) Seconds () ; 27 | func (d ) Nanoseconds () ; 28 | func (d ) Minutes () ; 29 | func (d ) Hours () ; 30 | >; 31 | func (t ) Add (d ) ; 32 | func (t ) UTC () ; 33 | func (t ) AddDate (years , months , days ) ; 34 | func (t ) MarshalBinary () (? >, ? ); 35 | func (t ) Nanosecond () ; 36 | func (t ) Round (d ) ; 37 | func (t ) Minute () ; 38 | func (t ) Clock () (hour , min , sec ); 39 | func (t ) ISOWeek () (year , week ); 40 | func (t ) Day () ; 41 | func (t >) .time.mono () ; 42 | func (t ) UnixNano () ; 43 | func (t ) .time.sec () ; 44 | func (t ) Second () ; 45 | func (t ) Before (u ) ; 46 | func (t ) UnmarshalBinary (data >) ; 47 | func (t ) Month () ; 48 | func (t ) YearDay () ; 49 | func (t ) Location () ; 50 | func (t ) Zone () (name , offset ); 51 | func (t ) Local () ; 52 | func (t ) .time.setLoc (loc ); 53 | func (t ) Truncate (d ) ; 54 | func (t ) MarshalJSON () (? >, ? ); 55 | func (t ) AppendFormat (b >, layout ) >; 56 | func (t ) GobDecode (data >) ; 57 | func (t ) UnmarshalJSON (data >) ; 58 | func (t ) MarshalText () (? >, ? ); 59 | func (t ) GobEncode () (? >, ? ); 60 | func (t ) .time.stripMono (); 61 | func (t ) After (u ) ; 62 | func (t ) Hour () ; 63 | func (t ) UnmarshalText (data >) ; 64 | func (t ) Equal (u ) ; 65 | func (t ) .time.setMono (m ); 66 | func (t ) Year () ; 67 | func (t ) IsZero () ; 68 | func (t ) .time.addSec (d ); 69 | func (t ) Weekday () 70 | func (d ) String () ; 71 | >; 72 | func (t ) String () ; 73 | func (t ) .time.nsec () ; 74 | func (t ) Format (layout ) ; 75 | func (t ) .time.unixSec () ; 76 | func (t ) Unix () ; 77 | func (t ) .time.abs () ; 78 | func (t ) .time.locabs () (name , offset , abs ); 79 | func (t ) Date () (year , month , day ); 80 | >, ok ); Done () >; Err () ; Value (key ) ; }>>, x ) ; 81 | >>; .issue29198.user ; .issue29198.ctx ; }>>>; 82 | >; 83 | type ; 84 | func New (sctx , u ) (? >, ? ); 85 | type ; 86 | checksum 86C8D76B2582F55A8BD2CA9E00060358EC1CE214; 87 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/libimportsar.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gccgoimporter/testdata/libimportsar.a -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/nointerface.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 nointerface 6 | 7 | type I int 8 | 9 | //go:nointerface 10 | func (p *I) Get() int { return int(*p) } 11 | 12 | func (p *I) Set(v int) { *p = I(v) } 13 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/nointerface.gox: -------------------------------------------------------------------------------- 1 | v3; 2 | package nointerface 3 | pkgpath nointerface 4 | types 3 2 133 17 5 | type 1 "I" 6 | func /*nointerface*/ (p ) Get () 7 | func (p ) Set (v ) 8 | type 2 * 9 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/pointer.go: -------------------------------------------------------------------------------- 1 | package pointer 2 | 3 | type Int8Ptr *int8 4 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/pointer.gox: -------------------------------------------------------------------------------- 1 | v1; 2 | package pointer; 3 | pkgpath pointer; 4 | type >>; 5 | -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/time.gox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gccgoimporter/testdata/time.gox -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/unicode.gox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gccgoimporter/testdata/unicode.gox -------------------------------------------------------------------------------- /go/internal/gccgoimporter/testdata/v1reflect.gox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gccgoimporter/testdata/v1reflect.gox -------------------------------------------------------------------------------- /go/internal/gcimporter/exportdata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 | // This file implements FindExportData. 6 | 7 | package gcimporter 8 | 9 | import ( 10 | "bufio" 11 | "fmt" 12 | "io" 13 | "strconv" 14 | "strings" 15 | ) 16 | 17 | func readGopackHeader(r *bufio.Reader) (name string, size int, err error) { 18 | // See $GOROOT/include/ar.h. 19 | hdr := make([]byte, 16+12+6+6+8+10+2) 20 | _, err = io.ReadFull(r, hdr) 21 | if err != nil { 22 | return 23 | } 24 | // leave for debugging 25 | if false { 26 | fmt.Printf("header: %s", hdr) 27 | } 28 | s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) 29 | size, err = strconv.Atoi(s) 30 | if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { 31 | err = fmt.Errorf("invalid archive header") 32 | return 33 | } 34 | name = strings.TrimSpace(string(hdr[:16])) 35 | return 36 | } 37 | 38 | // FindExportData positions the reader r at the beginning of the 39 | // export data section of an underlying GC-created object/archive 40 | // file by reading from it. The reader must be positioned at the 41 | // start of the file before calling this function. The hdr result 42 | // is the string before the export data, either "$$" or "$$B". 43 | // 44 | func FindExportData(r *bufio.Reader) (hdr string, err error) { 45 | // Read first line to make sure this is an object file. 46 | line, err := r.ReadSlice('\n') 47 | if err != nil { 48 | err = fmt.Errorf("can't find export data (%v)", err) 49 | return 50 | } 51 | 52 | if string(line) == "!\n" { 53 | // Archive file. Scan to __.PKGDEF. 54 | var name string 55 | if name, _, err = readGopackHeader(r); err != nil { 56 | return 57 | } 58 | 59 | // First entry should be __.PKGDEF. 60 | if name != "__.PKGDEF" { 61 | err = fmt.Errorf("go archive is missing __.PKGDEF") 62 | return 63 | } 64 | 65 | // Read first line of __.PKGDEF data, so that line 66 | // is once again the first line of the input. 67 | if line, err = r.ReadSlice('\n'); err != nil { 68 | err = fmt.Errorf("can't find export data (%v)", err) 69 | return 70 | } 71 | } 72 | 73 | // Now at __.PKGDEF in archive or still at beginning of file. 74 | // Either way, line should begin with "go object ". 75 | if !strings.HasPrefix(string(line), "go object ") { 76 | err = fmt.Errorf("not a Go object file") 77 | return 78 | } 79 | 80 | // Skip over object header to export data. 81 | // Begins after first line starting with $$. 82 | for line[0] != '$' { 83 | if line, err = r.ReadSlice('\n'); err != nil { 84 | err = fmt.Errorf("can't find export data (%v)", err) 85 | return 86 | } 87 | } 88 | hdr = string(line) 89 | 90 | return 91 | } 92 | -------------------------------------------------------------------------------- /go/internal/gcimporter/gcimporter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 gcimporter implements Import for gc-generated object files. 6 | package gcimporter // import "github.com/faiface/generics/go/internal/gcimporter" 7 | 8 | import ( 9 | "bufio" 10 | "fmt" 11 | "github.com/faiface/generics/go/build" 12 | "github.com/faiface/generics/go/token" 13 | "github.com/faiface/generics/go/types" 14 | "io" 15 | "io/ioutil" 16 | "os" 17 | "path/filepath" 18 | "strings" 19 | ) 20 | 21 | // debugging/development support 22 | const debug = false 23 | 24 | var pkgExts = [...]string{".a", ".o"} 25 | 26 | // FindPkg returns the filename and unique package id for an import 27 | // path based on package information provided by build.Import (using 28 | // the build.Default build.Context). A relative srcDir is interpreted 29 | // relative to the current working directory. 30 | // If no file was found, an empty filename is returned. 31 | // 32 | func FindPkg(path, srcDir string) (filename, id string) { 33 | if path == "" { 34 | return 35 | } 36 | 37 | var noext string 38 | switch { 39 | default: 40 | // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" 41 | // Don't require the source files to be present. 42 | if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282 43 | srcDir = abs 44 | } 45 | bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) 46 | if bp.PkgObj == "" { 47 | id = path // make sure we have an id to print in error message 48 | return 49 | } 50 | noext = strings.TrimSuffix(bp.PkgObj, ".a") 51 | id = bp.ImportPath 52 | 53 | case build.IsLocalImport(path): 54 | // "./x" -> "/this/directory/x.ext", "/this/directory/x" 55 | noext = filepath.Join(srcDir, path) 56 | id = noext 57 | 58 | case filepath.IsAbs(path): 59 | // for completeness only - go/build.Import 60 | // does not support absolute imports 61 | // "/x" -> "/x.ext", "/x" 62 | noext = path 63 | id = path 64 | } 65 | 66 | if false { // for debugging 67 | if path != id { 68 | fmt.Printf("%s -> %s\n", path, id) 69 | } 70 | } 71 | 72 | // try extensions 73 | for _, ext := range pkgExts { 74 | filename = noext + ext 75 | if f, err := os.Stat(filename); err == nil && !f.IsDir() { 76 | return 77 | } 78 | } 79 | 80 | filename = "" // not found 81 | return 82 | } 83 | 84 | // Import imports a gc-generated package given its import path and srcDir, adds 85 | // the corresponding package object to the packages map, and returns the object. 86 | // The packages map must contain all packages already imported. 87 | // 88 | func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) { 89 | var rc io.ReadCloser 90 | var id string 91 | if lookup != nil { 92 | // With custom lookup specified, assume that caller has 93 | // converted path to a canonical import path for use in the map. 94 | if path == "unsafe" { 95 | return types.Unsafe, nil 96 | } 97 | id = path 98 | 99 | // No need to re-import if the package was imported completely before. 100 | if pkg = packages[id]; pkg != nil && pkg.Complete() { 101 | return 102 | } 103 | f, err := lookup(path) 104 | if err != nil { 105 | return nil, err 106 | } 107 | rc = f 108 | } else { 109 | var filename string 110 | filename, id = FindPkg(path, srcDir) 111 | if filename == "" { 112 | if path == "unsafe" { 113 | return types.Unsafe, nil 114 | } 115 | return nil, fmt.Errorf("can't find import: %q", id) 116 | } 117 | 118 | // no need to re-import if the package was imported completely before 119 | if pkg = packages[id]; pkg != nil && pkg.Complete() { 120 | return 121 | } 122 | 123 | // open file 124 | f, err := os.Open(filename) 125 | if err != nil { 126 | return nil, err 127 | } 128 | defer func() { 129 | if err != nil { 130 | // add file name to error 131 | err = fmt.Errorf("%s: %v", filename, err) 132 | } 133 | }() 134 | rc = f 135 | } 136 | defer rc.Close() 137 | 138 | var hdr string 139 | buf := bufio.NewReader(rc) 140 | if hdr, err = FindExportData(buf); err != nil { 141 | return 142 | } 143 | 144 | switch hdr { 145 | case "$$\n": 146 | err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path) 147 | 148 | case "$$B\n": 149 | var data []byte 150 | data, err = ioutil.ReadAll(buf) 151 | if err != nil { 152 | break 153 | } 154 | 155 | // The indexed export format starts with an 'i'; the older 156 | // binary export format starts with a 'c', 'd', or 'v' 157 | // (from "version"). Select appropriate importer. 158 | if len(data) > 0 && data[0] == 'i' { 159 | _, pkg, err = iImportData(fset, packages, data[1:], id) 160 | } else { 161 | _, pkg, err = BImportData(fset, packages, data, id) 162 | } 163 | 164 | default: 165 | err = fmt.Errorf("unknown export data header: %q", hdr) 166 | } 167 | 168 | return 169 | } 170 | 171 | func deref(typ types.Type) types.Type { 172 | if p, _ := typ.(*types.Pointer); p != nil { 173 | return p.Elem() 174 | } 175 | return typ 176 | } 177 | 178 | type byPath []*types.Package 179 | 180 | func (a byPath) Len() int { return len(a) } 181 | func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 182 | func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } 183 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/a.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // Input for TestIssue13566 6 | 7 | package a 8 | 9 | import "encoding/json" 10 | 11 | type A struct { 12 | a *A 13 | json json.RawMessage 14 | } 15 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/b.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // Input for TestIssue13566 6 | 7 | package b 8 | 9 | import "./a" 10 | 11 | type A a.A 12 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/exports.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 | // This file is used to generate an object file which 6 | // serves as test file for gcimporter_test.go. 7 | 8 | package exports 9 | 10 | import "github.com/faiface/generics/go/ast" 11 | 12 | // Issue 3682: Correctly read dotted identifiers from export data. 13 | const init1 = 0 14 | 15 | func init() {} 16 | 17 | const ( 18 | C0 int = 0 19 | C1 = 3.14159265 20 | C2 = 2.718281828i 21 | C3 = -123.456e-789 22 | C4 = +123.456E+789 23 | C5 = 1234i 24 | C6 = "foo\n" 25 | C7 = `bar\n` 26 | ) 27 | 28 | type ( 29 | T1 int 30 | T2 [10]int 31 | T3 []int 32 | T4 *int 33 | T5 chan int 34 | T6a chan<- int 35 | T6b chan (<-chan int) 36 | T6c chan<- (chan int) 37 | T7 <-chan *ast.File 38 | T8 struct{} 39 | T9 struct { 40 | a int 41 | b, c float32 42 | d []string `go:"tag"` 43 | } 44 | T10 struct { 45 | T8 46 | T9 47 | _ *T10 48 | } 49 | T11 map[int]string 50 | T12 interface{} 51 | T13 interface { 52 | m1() 53 | m2(int) float32 54 | } 55 | T14 interface { 56 | T12 57 | T13 58 | m3(x ...struct{}) []T9 59 | } 60 | T15 func() 61 | T16 func(int) 62 | T17 func(x int) 63 | T18 func() float32 64 | T19 func() (x float32) 65 | T20 func(...interface{}) 66 | T21 struct{ next *T21 } 67 | T22 struct{ link *T23 } 68 | T23 struct{ link *T22 } 69 | T24 *T24 70 | T25 *T26 71 | T26 *T27 72 | T27 *T25 73 | T28 func(T28) T28 74 | ) 75 | 76 | var ( 77 | V0 int 78 | V1 = -991.0 79 | V2 float32 = 1.2 80 | ) 81 | 82 | func F1() {} 83 | func F2(x int) {} 84 | func F3() int { return 0 } 85 | func F4() float32 { return 0 } 86 | func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10) 87 | 88 | func (p *T1) M1() 89 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/issue15920.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 p 6 | 7 | // The underlying type of Error is the underlying type of error. 8 | // Make sure we can import this again without problems. 9 | type Error error 10 | 11 | func F() Error { return nil } 12 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/issue20046.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 p 6 | 7 | var V interface { 8 | M() 9 | } 10 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/issue25301.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 issue25301 6 | 7 | type ( 8 | A = interface { 9 | M() 10 | } 11 | T interface { 12 | A 13 | } 14 | S struct{} 15 | ) 16 | 17 | func (S) M() { println("m") } 18 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/issue25596.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 issue25596 6 | 7 | type E interface { 8 | M() T 9 | } 10 | 11 | type T interface { 12 | E 13 | } 14 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/p.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // Input for TestIssue15517 6 | 7 | package p 8 | 9 | const C = 0 10 | 11 | var V int 12 | 13 | func F() {} 14 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 | // To create a test case for a new export format version, 6 | // build this package with the latest compiler and store 7 | // the resulting .a file appropriately named in the versions 8 | // directory. The VersionHandling test will pick it up. 9 | // 10 | // In the testdata/versions: 11 | // 12 | // go build -o test_go1.$X_$Y.a test.go 13 | // 14 | // with $X = Go version and $Y = export format version 15 | // (add 'b' or 'i' to distinguish between binary and 16 | // indexed format starting with 1.11 as long as both 17 | // formats are supported). 18 | // 19 | // Make sure this source is extended such that it exercises 20 | // whatever export format change has taken place. 21 | 22 | package test 23 | 24 | // Any release before and including Go 1.7 didn't encode 25 | // the package for a blank struct field. 26 | type BlankField struct { 27 | _ int 28 | } 29 | -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.11_0i.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.11_6b.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.11_999b.a: -------------------------------------------------------------------------------- 1 | ! 2 | __.PKGDEF 0 0 0 644 270 ` 3 | go object darwin amd64 devel +be36bd996e Tue Jun 12 22:09:45 2018 +0000 X:framepointer 4 | build id "S9c1I0If5VsOppTWPHCU/_8Hpr6HmG5jjojTSCgoo" 5 | ---- 6 | 7 | 8 | $$B 9 | version 999 10 | 11 | test 12 | . 13 | |SGOROOTsrcgointernalgcimportertestdataversions 14 | test.goBlankField_   15 | $$ 16 | _go_.o 0 0 0 644 2028 ` 17 | go object darwin amd64 devel +be36bd996e Tue Jun 12 22:09:45 2018 +0000 X:framepointer 18 | build id "S9c1I0If5VsOppTWPHCU/_8Hpr6HmG5jjojTSCgoo" 19 | ---- 20 | 21 | 22 | ! 23 | go19ld�0type..hash."".BlankField�p�&type.*"".BlankField�h�type.uintptr�~r2�Tgclocals·2a5305abe05176240e61b8620e19a815�Tgclocals·33cdeccccebe80329f1fdbee7f5874cb�.gofile..�,type..eq."".BlankField�q�type.bool�Tgclocals·f207267fbf96a0178e8758c6e3e0ce28�>go.loc.type..hash."".BlankField�@go.info.type..hash."".BlankField�,go.info.*"".BlankField�go.info.uintptr�Bgo.range.type..hash."".BlankField�Dgo.isstmt.type..hash."".BlankField�:go.loc.type..eq."".BlankField�go.range.type..eq."".BlankField�@go.isstmt.type..eq."".BlankField�8type..hashfunc."".BlankField�4type..eqfunc."".BlankField�.type..alg."".BlankField�"runtime.gcbits.01�@type..namedata.*test.BlankField.� runtime.algarray�$type."".BlankField�runtime.gcbits.�(type..importpath."".�"type..namedata._-�type.int��: H�D$H�D$�     �D$�type..hash."".BlankField�ph~r2type..eq."".BlankField�pq~r2*test.BlankField�4f6;_/Users/gri/go/src/go/internal/gcimporter/testdata/versions_K� �(�0  24 |  25 |  26 |  27 | � 0   � 28 | ��� 4DX:l8 �8"�8"� $� & 29 | � 30 | (�*�� 0@ T:h8 |8 �8,� .� 0 31 | �2�4�6 24�8�:&&�pp0�<@8P 32 | :`>�@�B||�D�>��06@@P 33 | :X 34 | `Bp�>� 35 | B�D�F�����go19ld -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.11_999i.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.7_0.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.7_0.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.7_1.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.7_1.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.8_4.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.8_4.a -------------------------------------------------------------------------------- /go/internal/gcimporter/testdata/versions/test_go1.8_5.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/gcimporter/testdata/versions/test_go1.8_5.a -------------------------------------------------------------------------------- /go/internal/srcimporter/testdata/issue20855/issue20855.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 issue20855 6 | 7 | func init() // "missing function body" is a soft error 8 | -------------------------------------------------------------------------------- /go/internal/srcimporter/testdata/issue23092/issue23092.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 issue23092 6 | -------------------------------------------------------------------------------- /go/internal/srcimporter/testdata/issue24392/issue24392.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 issue24392 6 | -------------------------------------------------------------------------------- /go/internal/xcoff/ar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 xcoff 6 | 7 | import ( 8 | "encoding/binary" 9 | "fmt" 10 | "io" 11 | "os" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | const ( 17 | SAIAMAG = 0x8 18 | AIAFMAG = "`\n" 19 | AIAMAG = "\n" 20 | AIAMAGBIG = "\n" 21 | 22 | // Sizeof 23 | FL_HSZ_BIG = 0x80 24 | AR_HSZ_BIG = 0x70 25 | ) 26 | 27 | type bigarFileHeader struct { 28 | Flmagic [SAIAMAG]byte // Archive magic string 29 | Flmemoff [20]byte // Member table offset 30 | Flgstoff [20]byte // 32-bits global symtab offset 31 | Flgst64off [20]byte // 64-bits global symtab offset 32 | Flfstmoff [20]byte // First member offset 33 | Fllstmoff [20]byte // Last member offset 34 | Flfreeoff [20]byte // First member on free list offset 35 | } 36 | 37 | type bigarMemberHeader struct { 38 | Arsize [20]byte // File member size 39 | Arnxtmem [20]byte // Next member pointer 40 | Arprvmem [20]byte // Previous member pointer 41 | Ardate [12]byte // File member date 42 | Aruid [12]byte // File member uid 43 | Argid [12]byte // File member gid 44 | Armode [12]byte // File member mode (octal) 45 | Arnamlen [4]byte // File member name length 46 | // _ar_nam is removed because it's easier to get name without it. 47 | } 48 | 49 | // Archive represents an open AIX big archive. 50 | type Archive struct { 51 | ArchiveHeader 52 | Members []*Member 53 | 54 | closer io.Closer 55 | } 56 | 57 | // MemberHeader holds information about a big archive file header 58 | type ArchiveHeader struct { 59 | magic string 60 | } 61 | 62 | // Member represents a member of an AIX big archive. 63 | type Member struct { 64 | MemberHeader 65 | sr *io.SectionReader 66 | } 67 | 68 | // MemberHeader holds information about a big archive member 69 | type MemberHeader struct { 70 | Name string 71 | Size uint64 72 | } 73 | 74 | // OpenArchive opens the named archive using os.Open and prepares it for use 75 | // as an AIX big archive. 76 | func OpenArchive(name string) (*Archive, error) { 77 | f, err := os.Open(name) 78 | if err != nil { 79 | return nil, err 80 | } 81 | arch, err := NewArchive(f) 82 | if err != nil { 83 | f.Close() 84 | return nil, err 85 | } 86 | arch.closer = f 87 | return arch, nil 88 | } 89 | 90 | // Close closes the Archive. 91 | // If the Archive was created using NewArchive directly instead of OpenArchive, 92 | // Close has no effect. 93 | func (a *Archive) Close() error { 94 | var err error 95 | if a.closer != nil { 96 | err = a.closer.Close() 97 | a.closer = nil 98 | } 99 | return err 100 | } 101 | 102 | // NewArchive creates a new Archive for accessing an AIX big archive in an underlying reader. 103 | func NewArchive(r io.ReaderAt) (*Archive, error) { 104 | parseDecimalBytes := func(b []byte) (int64, error) { 105 | return strconv.ParseInt(strings.TrimSpace(string(b)), 10, 64) 106 | } 107 | sr := io.NewSectionReader(r, 0, 1<<63-1) 108 | 109 | // Read File Header 110 | var magic [SAIAMAG]byte 111 | if _, err := sr.ReadAt(magic[:], 0); err != nil { 112 | return nil, err 113 | } 114 | 115 | arch := new(Archive) 116 | switch string(magic[:]) { 117 | case AIAMAGBIG: 118 | arch.magic = string(magic[:]) 119 | case AIAMAG: 120 | return nil, fmt.Errorf("small AIX archive not supported") 121 | default: 122 | return nil, fmt.Errorf("unrecognised archive magic: 0x%x", magic) 123 | } 124 | 125 | var fhdr bigarFileHeader 126 | if _, err := sr.Seek(0, os.SEEK_SET); err != nil { 127 | return nil, err 128 | } 129 | if err := binary.Read(sr, binary.BigEndian, &fhdr); err != nil { 130 | return nil, err 131 | } 132 | 133 | off, err := parseDecimalBytes(fhdr.Flfstmoff[:]) 134 | if err != nil { 135 | return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err) 136 | } 137 | 138 | if off == 0 { 139 | // Occurs if the archive is empty. 140 | return arch, nil 141 | } 142 | 143 | lastoff, err := parseDecimalBytes(fhdr.Fllstmoff[:]) 144 | if err != nil { 145 | return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err) 146 | } 147 | 148 | // Read members 149 | for { 150 | // Read Member Header 151 | // The member header is normally 2 bytes larger. But it's easier 152 | // to read the name if the header is read without _ar_nam. 153 | // However, AIAFMAG must be read afterward. 154 | if _, err := sr.Seek(off, os.SEEK_SET); err != nil { 155 | return nil, err 156 | } 157 | 158 | var mhdr bigarMemberHeader 159 | if err := binary.Read(sr, binary.BigEndian, &mhdr); err != nil { 160 | return nil, err 161 | } 162 | 163 | member := new(Member) 164 | arch.Members = append(arch.Members, member) 165 | 166 | size, err := parseDecimalBytes(mhdr.Arsize[:]) 167 | if err != nil { 168 | return nil, fmt.Errorf("error parsing size in member header(%q); %v", mhdr, err) 169 | } 170 | member.Size = uint64(size) 171 | 172 | // Read name 173 | namlen, err := parseDecimalBytes(mhdr.Arnamlen[:]) 174 | if err != nil { 175 | return nil, fmt.Errorf("error parsing name length in member header(%q); %v", mhdr, err) 176 | } 177 | name := make([]byte, namlen) 178 | if err := binary.Read(sr, binary.BigEndian, name); err != nil { 179 | return nil, err 180 | } 181 | member.Name = string(name) 182 | 183 | fileoff := off + AR_HSZ_BIG + namlen 184 | if fileoff&1 != 0 { 185 | fileoff++ 186 | if _, err := sr.Seek(1, os.SEEK_CUR); err != nil { 187 | return nil, err 188 | } 189 | } 190 | 191 | // Read AIAFMAG string 192 | var fmag [2]byte 193 | if err := binary.Read(sr, binary.BigEndian, &fmag); err != nil { 194 | return nil, err 195 | } 196 | if string(fmag[:]) != AIAFMAG { 197 | return nil, fmt.Errorf("AIAFMAG not found after member header") 198 | } 199 | 200 | fileoff += 2 // Add the two bytes of AIAFMAG 201 | member.sr = io.NewSectionReader(sr, fileoff, size) 202 | 203 | if off == lastoff { 204 | break 205 | } 206 | off, err = parseDecimalBytes(mhdr.Arnxtmem[:]) 207 | if err != nil { 208 | return nil, fmt.Errorf("error parsing offset of first member in archive header(%q); %v", fhdr, err) 209 | } 210 | 211 | } 212 | 213 | return arch, nil 214 | 215 | } 216 | 217 | // GetFile returns the XCOFF file defined by member name. 218 | // FIXME: This doesn't work if an archive has two members with the same 219 | // name which can occur if a archive has both 32-bits and 64-bits files. 220 | func (arch *Archive) GetFile(name string) (*File, error) { 221 | for _, mem := range arch.Members { 222 | if mem.Name == name { 223 | return NewFile(mem.sr) 224 | } 225 | } 226 | return nil, fmt.Errorf("unknown member %s in archive", name) 227 | 228 | } 229 | -------------------------------------------------------------------------------- /go/internal/xcoff/ar_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 xcoff 6 | 7 | import ( 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | type archiveTest struct { 13 | file string 14 | hdr ArchiveHeader 15 | members []*MemberHeader 16 | membersFileHeader []FileHeader 17 | } 18 | 19 | var archTest = []archiveTest{ 20 | { 21 | "testdata/bigar-ppc64", 22 | ArchiveHeader{AIAMAGBIG}, 23 | []*MemberHeader{ 24 | {"printbye.o", 836}, 25 | {"printhello.o", 860}, 26 | }, 27 | []FileHeader{ 28 | FileHeader{U64_TOCMAGIC}, 29 | FileHeader{U64_TOCMAGIC}, 30 | }, 31 | }, 32 | { 33 | "testdata/bigar-empty", 34 | ArchiveHeader{AIAMAGBIG}, 35 | []*MemberHeader{}, 36 | []FileHeader{}, 37 | }, 38 | } 39 | 40 | func TestOpenArchive(t *testing.T) { 41 | for i := range archTest { 42 | tt := &archTest[i] 43 | arch, err := OpenArchive(tt.file) 44 | if err != nil { 45 | t.Error(err) 46 | continue 47 | } 48 | if !reflect.DeepEqual(arch.ArchiveHeader, tt.hdr) { 49 | t.Errorf("open archive %s:\n\thave %#v\n\twant %#v\n", tt.file, arch.ArchiveHeader, tt.hdr) 50 | continue 51 | } 52 | 53 | for i, mem := range arch.Members { 54 | if i >= len(tt.members) { 55 | break 56 | } 57 | have := &mem.MemberHeader 58 | want := tt.members[i] 59 | if !reflect.DeepEqual(have, want) { 60 | t.Errorf("open %s, member %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 61 | } 62 | 63 | f, err := arch.GetFile(mem.Name) 64 | if err != nil { 65 | t.Error(err) 66 | continue 67 | } 68 | if !reflect.DeepEqual(f.FileHeader, tt.membersFileHeader[i]) { 69 | t.Errorf("open %s, member file header %d:\n\thave %#v\n\twant %#v\n", tt.file, i, f.FileHeader, tt.membersFileHeader[i]) 70 | } 71 | } 72 | tn := len(tt.members) 73 | an := len(arch.Members) 74 | if tn != an { 75 | t.Errorf("open %s: len(Members) = %d, want %d", tt.file, an, tn) 76 | } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /go/internal/xcoff/file_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 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 xcoff 6 | 7 | import ( 8 | "reflect" 9 | "testing" 10 | ) 11 | 12 | type fileTest struct { 13 | file string 14 | hdr FileHeader 15 | sections []*SectionHeader 16 | needed []string 17 | } 18 | 19 | var fileTests = []fileTest{ 20 | { 21 | "testdata/gcc-ppc32-aix-dwarf2-exec", 22 | FileHeader{U802TOCMAGIC}, 23 | []*SectionHeader{ 24 | {".text", 0x10000290, 0x00000bbd, STYP_TEXT, 0x7ae6, 0x36}, 25 | {".data", 0x20000e4d, 0x00000437, STYP_DATA, 0x7d02, 0x2b}, 26 | {".bss", 0x20001284, 0x0000021c, STYP_BSS, 0, 0}, 27 | {".loader", 0x00000000, 0x000004b3, STYP_LOADER, 0, 0}, 28 | {".dwline", 0x00000000, 0x000000df, STYP_DWARF | SSUBTYP_DWLINE, 0x7eb0, 0x7}, 29 | {".dwinfo", 0x00000000, 0x00000314, STYP_DWARF | SSUBTYP_DWINFO, 0x7ef6, 0xa}, 30 | {".dwabrev", 0x00000000, 0x000000d6, STYP_DWARF | SSUBTYP_DWABREV, 0, 0}, 31 | {".dwarnge", 0x00000000, 0x00000020, STYP_DWARF | SSUBTYP_DWARNGE, 0x7f5a, 0x2}, 32 | {".dwloc", 0x00000000, 0x00000074, STYP_DWARF | SSUBTYP_DWLOC, 0, 0}, 33 | {".debug", 0x00000000, 0x00005e4f, STYP_DEBUG, 0, 0}, 34 | }, 35 | []string{"libc.a/shr.o"}, 36 | }, 37 | { 38 | "testdata/gcc-ppc64-aix-dwarf2-exec", 39 | FileHeader{U64_TOCMAGIC}, 40 | []*SectionHeader{ 41 | {".text", 0x10000480, 0x00000afd, STYP_TEXT, 0x8322, 0x34}, 42 | {".data", 0x20000f7d, 0x000002f3, STYP_DATA, 0x85fa, 0x25}, 43 | {".bss", 0x20001270, 0x00000428, STYP_BSS, 0, 0}, 44 | {".loader", 0x00000000, 0x00000535, STYP_LOADER, 0, 0}, 45 | {".dwline", 0x00000000, 0x000000b4, STYP_DWARF | SSUBTYP_DWLINE, 0x8800, 0x4}, 46 | {".dwinfo", 0x00000000, 0x0000036a, STYP_DWARF | SSUBTYP_DWINFO, 0x8838, 0x7}, 47 | {".dwabrev", 0x00000000, 0x000000b5, STYP_DWARF | SSUBTYP_DWABREV, 0, 0}, 48 | {".dwarnge", 0x00000000, 0x00000040, STYP_DWARF | SSUBTYP_DWARNGE, 0x889a, 0x2}, 49 | {".dwloc", 0x00000000, 0x00000062, STYP_DWARF | SSUBTYP_DWLOC, 0, 0}, 50 | {".debug", 0x00000000, 0x00006605, STYP_DEBUG, 0, 0}, 51 | }, 52 | []string{"libc.a/shr_64.o"}, 53 | }, 54 | } 55 | 56 | func TestOpen(t *testing.T) { 57 | for i := range fileTests { 58 | tt := &fileTests[i] 59 | 60 | f, err := Open(tt.file) 61 | if err != nil { 62 | t.Error(err) 63 | continue 64 | } 65 | if !reflect.DeepEqual(f.FileHeader, tt.hdr) { 66 | t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) 67 | continue 68 | } 69 | 70 | for i, sh := range f.Sections { 71 | if i >= len(tt.sections) { 72 | break 73 | } 74 | have := &sh.SectionHeader 75 | want := tt.sections[i] 76 | if !reflect.DeepEqual(have, want) { 77 | t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) 78 | } 79 | } 80 | tn := len(tt.sections) 81 | fn := len(f.Sections) 82 | if tn != fn { 83 | t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) 84 | } 85 | tl := tt.needed 86 | fl, err := f.ImportedLibraries() 87 | if err != nil { 88 | t.Error(err) 89 | } 90 | if !reflect.DeepEqual(tl, fl) { 91 | t.Errorf("open %s: loader import = %v, want %v", tt.file, tl, fl) 92 | } 93 | } 94 | } 95 | 96 | func TestOpenFailure(t *testing.T) { 97 | filename := "file.go" // not an XCOFF object file 98 | _, err := Open(filename) // don't crash 99 | if err == nil { 100 | t.Errorf("open %s: succeeded unexpectedly", filename) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/bigar-empty: -------------------------------------------------------------------------------- 1 | 2 | 0 0 0 0 0 0 -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/bigar-ppc64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/xcoff/testdata/bigar-ppc64 -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/faiface/generics/8cf65f0b43803410724d8c671cb4d328543ba07d/go/internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void 4 | main(int argc, char *argv[]) 5 | { 6 | printf("hello, world\n"); 7 | } 8 | -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/printbye.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void printbye(){ 4 | printf("Goodbye\n"); 5 | } 6 | -------------------------------------------------------------------------------- /go/internal/xcoff/testdata/printhello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void printhello(){ 4 | printf("Helloworld\n"); 5 | } 6 | -------------------------------------------------------------------------------- /go/scanner/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 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 scanner 6 | 7 | import ( 8 | "fmt" 9 | "github.com/faiface/generics/go/token" 10 | "io" 11 | "sort" 12 | ) 13 | 14 | // In an ErrorList, an error is represented by an *Error. 15 | // The position Pos, if valid, points to the beginning of 16 | // the offending token, and the error condition is described 17 | // by Msg. 18 | // 19 | type Error struct { 20 | Pos token.Position 21 | Msg string 22 | } 23 | 24 | // Error implements the error interface. 25 | func (e Error) Error() string { 26 | if e.Pos.Filename != "" || e.Pos.IsValid() { 27 | // don't print "" 28 | // TODO(gri) reconsider the semantics of Position.IsValid 29 | return e.Pos.String() + ": " + e.Msg 30 | } 31 | return e.Msg 32 | } 33 | 34 | // ErrorList is a list of *Errors. 35 | // The zero value for an ErrorList is an empty ErrorList ready to use. 36 | // 37 | type ErrorList []*Error 38 | 39 | // Add adds an Error with given position and error message to an ErrorList. 40 | func (p *ErrorList) Add(pos token.Position, msg string) { 41 | *p = append(*p, &Error{pos, msg}) 42 | } 43 | 44 | // Reset resets an ErrorList to no errors. 45 | func (p *ErrorList) Reset() { *p = (*p)[0:0] } 46 | 47 | // ErrorList implements the sort Interface. 48 | func (p ErrorList) Len() int { return len(p) } 49 | func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 50 | 51 | func (p ErrorList) Less(i, j int) bool { 52 | e := &p[i].Pos 53 | f := &p[j].Pos 54 | // Note that it is not sufficient to simply compare file offsets because 55 | // the offsets do not reflect modified line information (through //line 56 | // comments). 57 | if e.Filename != f.Filename { 58 | return e.Filename < f.Filename 59 | } 60 | if e.Line != f.Line { 61 | return e.Line < f.Line 62 | } 63 | if e.Column != f.Column { 64 | return e.Column < f.Column 65 | } 66 | return p[i].Msg < p[j].Msg 67 | } 68 | 69 | // Sort sorts an ErrorList. *Error entries are sorted by position, 70 | // other errors are sorted by error message, and before any *Error 71 | // entry. 72 | // 73 | func (p ErrorList) Sort() { 74 | sort.Sort(p) 75 | } 76 | 77 | // RemoveMultiples sorts an ErrorList and removes all but the first error per line. 78 | func (p *ErrorList) RemoveMultiples() { 79 | sort.Sort(p) 80 | var last token.Position // initial last.Line is != any legal error line 81 | i := 0 82 | for _, e := range *p { 83 | if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line { 84 | last = e.Pos 85 | (*p)[i] = e 86 | i++ 87 | } 88 | } 89 | (*p) = (*p)[0:i] 90 | } 91 | 92 | // An ErrorList implements the error interface. 93 | func (p ErrorList) Error() string { 94 | switch len(p) { 95 | case 0: 96 | return "no errors" 97 | case 1: 98 | return p[0].Error() 99 | } 100 | return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1) 101 | } 102 | 103 | // Err returns an error equivalent to this error list. 104 | // If the list is empty, Err returns nil. 105 | func (p ErrorList) Err() error { 106 | if len(p) == 0 { 107 | return nil 108 | } 109 | return p 110 | } 111 | 112 | // PrintError is a utility function that prints a list of errors to w, 113 | // one error per line, if the err parameter is an ErrorList. Otherwise 114 | // it prints the err string. 115 | // 116 | func PrintError(w io.Writer, err error) { 117 | if list, ok := err.(ErrorList); ok { 118 | for _, e := range list { 119 | fmt.Fprintf(w, "%s\n", e) 120 | } 121 | } else if err != nil { 122 | fmt.Fprintf(w, "%s\n", err) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /go/token/serialize.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 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 token 6 | 7 | type serializedFile struct { 8 | // fields correspond 1:1 to fields with same (lower-case) name in File 9 | Name string 10 | Base int 11 | Size int 12 | Lines []int 13 | Infos []lineInfo 14 | } 15 | 16 | type serializedFileSet struct { 17 | Base int 18 | Files []serializedFile 19 | } 20 | 21 | // Read calls decode to deserialize a file set into s; s must not be nil. 22 | func (s *FileSet) Read(decode func(interface{}) error) error { 23 | var ss serializedFileSet 24 | if err := decode(&ss); err != nil { 25 | return err 26 | } 27 | 28 | s.mutex.Lock() 29 | s.base = ss.Base 30 | files := make([]*File, len(ss.Files)) 31 | for i := 0; i < len(ss.Files); i++ { 32 | f := &ss.Files[i] 33 | files[i] = &File{ 34 | set: s, 35 | name: f.Name, 36 | base: f.Base, 37 | size: f.Size, 38 | lines: f.Lines, 39 | infos: f.Infos, 40 | } 41 | } 42 | s.files = files 43 | s.last = nil 44 | s.mutex.Unlock() 45 | 46 | return nil 47 | } 48 | 49 | // Write calls encode to serialize the file set s. 50 | func (s *FileSet) Write(encode func(interface{}) error) error { 51 | var ss serializedFileSet 52 | 53 | s.mutex.Lock() 54 | ss.Base = s.base 55 | files := make([]serializedFile, len(s.files)) 56 | for i, f := range s.files { 57 | f.mutex.Lock() 58 | files[i] = serializedFile{ 59 | Name: f.name, 60 | Base: f.base, 61 | Size: f.size, 62 | Lines: append([]int(nil), f.lines...), 63 | Infos: append([]lineInfo(nil), f.infos...), 64 | } 65 | f.mutex.Unlock() 66 | } 67 | ss.Files = files 68 | s.mutex.Unlock() 69 | 70 | return encode(ss) 71 | } 72 | -------------------------------------------------------------------------------- /go/token/token.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 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 token defines constants representing the lexical tokens of the Go 6 | // programming language and basic operations on tokens (printing, predicates). 7 | // 8 | package token 9 | 10 | import "strconv" 11 | 12 | // Token is the set of lexical tokens of the Go programming language. 13 | type Token int 14 | 15 | // The list of tokens. 16 | const ( 17 | // Special tokens 18 | ILLEGAL Token = iota 19 | EOF 20 | COMMENT 21 | 22 | literal_beg 23 | // Identifiers and basic type literals 24 | // (these tokens stand for classes of literals) 25 | IDENT // main 26 | INT // 12345 27 | FLOAT // 123.45 28 | IMAG // 123.45i 29 | CHAR // 'a' 30 | STRING // "abc" 31 | literal_end 32 | 33 | operator_beg 34 | // Operators and delimiters 35 | ADD // + 36 | SUB // - 37 | MUL // * 38 | QUO // / 39 | REM // % 40 | 41 | AND // & 42 | OR // | 43 | XOR // ^ 44 | SHL // << 45 | SHR // >> 46 | AND_NOT // &^ 47 | 48 | ADD_ASSIGN // += 49 | SUB_ASSIGN // -= 50 | MUL_ASSIGN // *= 51 | QUO_ASSIGN // /= 52 | REM_ASSIGN // %= 53 | 54 | AND_ASSIGN // &= 55 | OR_ASSIGN // |= 56 | XOR_ASSIGN // ^= 57 | SHL_ASSIGN // <<= 58 | SHR_ASSIGN // >>= 59 | AND_NOT_ASSIGN // &^= 60 | 61 | LAND // && 62 | LOR // || 63 | ARROW // <- 64 | INC // ++ 65 | DEC // -- 66 | 67 | EQL // == 68 | LSS // < 69 | GTR // > 70 | ASSIGN // = 71 | NOT // ! 72 | 73 | NEQ // != 74 | LEQ // <= 75 | GEQ // >= 76 | DEFINE // := 77 | ELLIPSIS // ... 78 | 79 | LPAREN // ( 80 | LBRACK // [ 81 | LBRACE // { 82 | COMMA // , 83 | PERIOD // . 84 | 85 | RPAREN // ) 86 | RBRACK // ] 87 | RBRACE // } 88 | SEMICOLON // ; 89 | COLON // : 90 | operator_end 91 | 92 | keyword_beg 93 | // Keywords 94 | BREAK 95 | CASE 96 | CHAN 97 | CONST 98 | CONTINUE 99 | 100 | DEFAULT 101 | DEFER 102 | ELSE 103 | FALLTHROUGH 104 | FOR 105 | 106 | FUNC 107 | GO 108 | GOTO 109 | IF 110 | IMPORT 111 | 112 | INTERFACE 113 | MAP 114 | PACKAGE 115 | RANGE 116 | RETURN 117 | 118 | SELECT 119 | STRUCT 120 | SWITCH 121 | TYPE 122 | VAR 123 | keyword_end 124 | ) 125 | 126 | var tokens = [...]string{ 127 | ILLEGAL: "ILLEGAL", 128 | 129 | EOF: "EOF", 130 | COMMENT: "COMMENT", 131 | 132 | IDENT: "IDENT", 133 | INT: "INT", 134 | FLOAT: "FLOAT", 135 | IMAG: "IMAG", 136 | CHAR: "CHAR", 137 | STRING: "STRING", 138 | 139 | ADD: "+", 140 | SUB: "-", 141 | MUL: "*", 142 | QUO: "/", 143 | REM: "%", 144 | 145 | AND: "&", 146 | OR: "|", 147 | XOR: "^", 148 | SHL: "<<", 149 | SHR: ">>", 150 | AND_NOT: "&^", 151 | 152 | ADD_ASSIGN: "+=", 153 | SUB_ASSIGN: "-=", 154 | MUL_ASSIGN: "*=", 155 | QUO_ASSIGN: "/=", 156 | REM_ASSIGN: "%=", 157 | 158 | AND_ASSIGN: "&=", 159 | OR_ASSIGN: "|=", 160 | XOR_ASSIGN: "^=", 161 | SHL_ASSIGN: "<<=", 162 | SHR_ASSIGN: ">>=", 163 | AND_NOT_ASSIGN: "&^=", 164 | 165 | LAND: "&&", 166 | LOR: "||", 167 | ARROW: "<-", 168 | INC: "++", 169 | DEC: "--", 170 | 171 | EQL: "==", 172 | LSS: "<", 173 | GTR: ">", 174 | ASSIGN: "=", 175 | NOT: "!", 176 | 177 | NEQ: "!=", 178 | LEQ: "<=", 179 | GEQ: ">=", 180 | DEFINE: ":=", 181 | ELLIPSIS: "...", 182 | 183 | LPAREN: "(", 184 | LBRACK: "[", 185 | LBRACE: "{", 186 | COMMA: ",", 187 | PERIOD: ".", 188 | 189 | RPAREN: ")", 190 | RBRACK: "]", 191 | RBRACE: "}", 192 | SEMICOLON: ";", 193 | COLON: ":", 194 | 195 | BREAK: "break", 196 | CASE: "case", 197 | CHAN: "chan", 198 | CONST: "const", 199 | CONTINUE: "continue", 200 | 201 | DEFAULT: "default", 202 | DEFER: "defer", 203 | ELSE: "else", 204 | FALLTHROUGH: "fallthrough", 205 | FOR: "for", 206 | 207 | FUNC: "func", 208 | GO: "go", 209 | GOTO: "goto", 210 | IF: "if", 211 | IMPORT: "import", 212 | 213 | INTERFACE: "interface", 214 | MAP: "map", 215 | PACKAGE: "package", 216 | RANGE: "range", 217 | RETURN: "return", 218 | 219 | SELECT: "select", 220 | STRUCT: "struct", 221 | SWITCH: "switch", 222 | TYPE: "type", 223 | VAR: "var", 224 | } 225 | 226 | // String returns the string corresponding to the token tok. 227 | // For operators, delimiters, and keywords the string is the actual 228 | // token character sequence (e.g., for the token ADD, the string is 229 | // "+"). For all other tokens the string corresponds to the token 230 | // constant name (e.g. for the token IDENT, the string is "IDENT"). 231 | // 232 | func (tok Token) String() string { 233 | s := "" 234 | if 0 <= tok && tok < Token(len(tokens)) { 235 | s = tokens[tok] 236 | } 237 | if s == "" { 238 | s = "token(" + strconv.Itoa(int(tok)) + ")" 239 | } 240 | return s 241 | } 242 | 243 | // A set of constants for precedence-based expression parsing. 244 | // Non-operators have lowest precedence, followed by operators 245 | // starting with precedence 1 up to unary operators. The highest 246 | // precedence serves as "catch-all" precedence for selector, 247 | // indexing, and other operator and delimiter tokens. 248 | // 249 | const ( 250 | LowestPrec = 0 // non-operators 251 | UnaryPrec = 6 252 | HighestPrec = 7 253 | ) 254 | 255 | // Precedence returns the operator precedence of the binary 256 | // operator op. If op is not a binary operator, the result 257 | // is LowestPrecedence. 258 | // 259 | func (op Token) Precedence() int { 260 | switch op { 261 | case LOR: 262 | return 1 263 | case LAND: 264 | return 2 265 | case EQL, NEQ, LSS, LEQ, GTR, GEQ: 266 | return 3 267 | case ADD, SUB, OR, XOR: 268 | return 4 269 | case MUL, QUO, REM, SHL, SHR, AND, AND_NOT: 270 | return 5 271 | } 272 | return LowestPrec 273 | } 274 | 275 | var keywords map[string]Token 276 | 277 | func init() { 278 | keywords = make(map[string]Token) 279 | for i := keyword_beg + 1; i < keyword_end; i++ { 280 | keywords[tokens[i]] = i 281 | } 282 | } 283 | 284 | // Lookup maps an identifier to its keyword token or IDENT (if not a keyword). 285 | // 286 | func Lookup(ident string) Token { 287 | if tok, is_keyword := keywords[ident]; is_keyword { 288 | return tok 289 | } 290 | return IDENT 291 | } 292 | 293 | // Predicates 294 | 295 | // IsLiteral returns true for tokens corresponding to identifiers 296 | // and basic type literals; it returns false otherwise. 297 | // 298 | func (tok Token) IsLiteral() bool { return literal_beg < tok && tok < literal_end } 299 | 300 | // IsOperator returns true for tokens corresponding to operators and 301 | // delimiters; it returns false otherwise. 302 | // 303 | func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator_end } 304 | 305 | // IsKeyword returns true for tokens corresponding to keywords; 306 | // it returns false otherwise. 307 | // 308 | func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end } 309 | -------------------------------------------------------------------------------- /go/types/conversions.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 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 | // This file implements typechecking of conversions. 6 | 7 | package types 8 | 9 | import ( 10 | "github.com/faiface/generics/go/constant" 11 | ) 12 | 13 | // Conversion type-checks the conversion T(x). 14 | // The result is in x. 15 | func (check *Checker) conversion(x *operand, T Type) { 16 | constArg := x.mode == constant_ 17 | 18 | var ok bool 19 | switch { 20 | case constArg && isConstType(T): 21 | // constant conversion 22 | switch t := T.Underlying().(*Basic); { 23 | case representableConst(x.val, check.conf, t, &x.val): 24 | ok = true 25 | case isInteger(x.typ) && isString(t): 26 | codepoint := int64(-1) 27 | if i, ok := constant.Int64Val(x.val); ok { 28 | codepoint = i 29 | } 30 | // If codepoint < 0 the absolute value is too large (or unknown) for 31 | // conversion. This is the same as converting any other out-of-range 32 | // value - let string(codepoint) do the work. 33 | x.val = constant.MakeString(string(codepoint)) 34 | ok = true 35 | } 36 | case x.convertibleTo(check.conf, T): 37 | // non-constant conversion 38 | x.mode = value 39 | ok = true 40 | } 41 | 42 | if !ok { 43 | check.errorf(x.pos(), "cannot convert %s to %s", x, T) 44 | x.mode = invalid 45 | return 46 | } 47 | 48 | // The conversion argument types are final. For untyped values the 49 | // conversion provides the type, per the spec: "A constant may be 50 | // given a type explicitly by a constant declaration or conversion,...". 51 | if isUntyped(x.typ) { 52 | final := T 53 | // - For conversions to interfaces, use the argument's default type. 54 | // - For conversions of untyped constants to non-constant types, also 55 | // use the default type (e.g., []byte("foo") should report string 56 | // not []byte as type for the constant "foo"). 57 | // - Keep untyped nil for untyped nil arguments. 58 | // - For integer to string conversions, keep the argument type. 59 | // (See also the TODO below.) 60 | if IsInterface(T) || constArg && !isConstType(T) { 61 | final = Default(x.typ) 62 | } else if isInteger(x.typ) && isString(T) { 63 | final = x.typ 64 | } 65 | check.updateExprType(x.expr, final, true) 66 | } 67 | 68 | x.typ = T 69 | } 70 | 71 | // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type 72 | // of x is fully known, but that's not the case for say string(1< 0 { 103 | buf.WriteString(", ") 104 | } 105 | WriteExpr(buf, arg) 106 | } 107 | if x.Ellipsis.IsValid() { 108 | buf.WriteString("...") 109 | } 110 | buf.WriteByte(')') 111 | 112 | case *ast.StarExpr: 113 | buf.WriteByte('*') 114 | WriteExpr(buf, x.X) 115 | 116 | case *ast.UnaryExpr: 117 | buf.WriteString(x.Op.String()) 118 | WriteExpr(buf, x.X) 119 | 120 | case *ast.BinaryExpr: 121 | WriteExpr(buf, x.X) 122 | buf.WriteByte(' ') 123 | buf.WriteString(x.Op.String()) 124 | buf.WriteByte(' ') 125 | WriteExpr(buf, x.Y) 126 | 127 | case *ast.ArrayType: 128 | buf.WriteByte('[') 129 | if x.Len != nil { 130 | WriteExpr(buf, x.Len) 131 | } 132 | buf.WriteByte(']') 133 | WriteExpr(buf, x.Elt) 134 | 135 | case *ast.StructType: 136 | buf.WriteString("struct{") 137 | writeFieldList(buf, x.Fields, "; ", false) 138 | buf.WriteByte('}') 139 | 140 | case *ast.FuncType: 141 | buf.WriteString("func") 142 | writeSigExpr(buf, x) 143 | 144 | case *ast.InterfaceType: 145 | buf.WriteString("interface{") 146 | writeFieldList(buf, x.Methods, "; ", true) 147 | buf.WriteByte('}') 148 | 149 | case *ast.MapType: 150 | buf.WriteString("map[") 151 | WriteExpr(buf, x.Key) 152 | buf.WriteByte(']') 153 | WriteExpr(buf, x.Value) 154 | 155 | case *ast.ChanType: 156 | var s string 157 | switch x.Dir { 158 | case ast.SEND: 159 | s = "chan<- " 160 | case ast.RECV: 161 | s = "<-chan " 162 | default: 163 | s = "chan " 164 | } 165 | buf.WriteString(s) 166 | WriteExpr(buf, x.Value) 167 | } 168 | } 169 | 170 | func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) { 171 | buf.WriteByte('(') 172 | writeFieldList(buf, sig.Params, ", ", false) 173 | buf.WriteByte(')') 174 | 175 | res := sig.Results 176 | n := res.NumFields() 177 | if n == 0 { 178 | // no result 179 | return 180 | } 181 | 182 | buf.WriteByte(' ') 183 | if n == 1 && len(res.List[0].Names) == 0 { 184 | // single unnamed result 185 | WriteExpr(buf, res.List[0].Type) 186 | return 187 | } 188 | 189 | // multiple or named result(s) 190 | buf.WriteByte('(') 191 | writeFieldList(buf, res, ", ", false) 192 | buf.WriteByte(')') 193 | } 194 | 195 | func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) { 196 | for i, f := range fields.List { 197 | if i > 0 { 198 | buf.WriteString(sep) 199 | } 200 | 201 | // field list names 202 | for i, name := range f.Names { 203 | if i > 0 { 204 | buf.WriteString(", ") 205 | } 206 | buf.WriteString(name.Name) 207 | } 208 | 209 | // types of interface methods consist of signatures only 210 | if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface { 211 | writeSigExpr(buf, sig) 212 | continue 213 | } 214 | 215 | // named fields are separated with a blank from the field type 216 | if len(f.Names) > 0 { 217 | buf.WriteByte(' ') 218 | } 219 | 220 | WriteExpr(buf, f.Type) 221 | 222 | // ignore tag 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /go/types/objset.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | // This file implements objsets. 6 | // 7 | // An objset is similar to a Scope but objset elements 8 | // are identified by their unique id, instead of their 9 | // object name. 10 | 11 | package types 12 | 13 | // An objset is a set of objects identified by their unique id. 14 | // The zero value for objset is a ready-to-use empty objset. 15 | type objset map[string]Object // initialized lazily 16 | 17 | // insert attempts to insert an object obj into objset s. 18 | // If s already contains an alternative object alt with 19 | // the same name, insert leaves s unchanged and returns alt. 20 | // Otherwise it inserts obj and returns nil. 21 | func (s *objset) insert(obj Object) Object { 22 | id := obj.Id() 23 | if alt := (*s)[id]; alt != nil { 24 | return alt 25 | } 26 | if *s == nil { 27 | *s = make(map[string]Object) 28 | } 29 | (*s)[id] = obj 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /go/types/ordering.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 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 | // This file implements resolveOrder. 6 | 7 | package types 8 | 9 | import ( 10 | "github.com/faiface/generics/go/ast" 11 | "sort" 12 | ) 13 | 14 | // resolveOrder computes the order in which package-level objects 15 | // must be type-checked. 16 | // 17 | // Interface types appear first in the list, sorted topologically 18 | // by dependencies on embedded interfaces that are also declared 19 | // in this package, followed by all other objects sorted in source 20 | // order. 21 | // 22 | // TODO(gri) Consider sorting all types by dependencies here, and 23 | // in the process check _and_ report type cycles. This may simplify 24 | // the full type-checking phase. 25 | // 26 | func (check *Checker) resolveOrder() []Object { 27 | var ifaces, others []Object 28 | 29 | // collect interface types with their dependencies, and all other objects 30 | for obj := range check.objMap { 31 | if ityp := check.interfaceFor(obj); ityp != nil { 32 | ifaces = append(ifaces, obj) 33 | // determine dependencies on embedded interfaces 34 | for _, f := range ityp.Methods.List { 35 | if len(f.Names) == 0 { 36 | // Embedded interface: The type must be a (possibly 37 | // qualified) identifier denoting another interface. 38 | // Imported interfaces are already fully resolved, 39 | // so we can ignore qualified identifiers. 40 | if ident, _ := f.Type.(*ast.Ident); ident != nil { 41 | embedded := check.pkg.scope.Lookup(ident.Name) 42 | if check.interfaceFor(embedded) != nil { 43 | check.objMap[obj].addDep(embedded) 44 | } 45 | } 46 | } 47 | } 48 | } else { 49 | others = append(others, obj) 50 | } 51 | } 52 | 53 | // final object order 54 | var order []Object 55 | 56 | // sort interface types topologically by dependencies, 57 | // and in source order if there are no dependencies 58 | sort.Sort(inSourceOrder(ifaces)) 59 | visited := make(objSet) 60 | for _, obj := range ifaces { 61 | check.appendInPostOrder(&order, obj, visited) 62 | } 63 | 64 | // sort everything else in source order 65 | sort.Sort(inSourceOrder(others)) 66 | 67 | return append(order, others...) 68 | } 69 | 70 | // interfaceFor returns the AST interface denoted by obj, or nil. 71 | func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType { 72 | tname, _ := obj.(*TypeName) 73 | if tname == nil { 74 | return nil // not a type 75 | } 76 | d := check.objMap[obj] 77 | if d == nil { 78 | check.dump("%s: %s should have been declared", obj.Pos(), obj.Name()) 79 | unreachable() 80 | } 81 | if d.typ == nil { 82 | return nil // invalid AST - ignore (will be handled later) 83 | } 84 | ityp, _ := d.typ.(*ast.InterfaceType) 85 | return ityp 86 | } 87 | 88 | func (check *Checker) appendInPostOrder(order *[]Object, obj Object, visited objSet) { 89 | if visited[obj] { 90 | // We've already seen this object; either because it's 91 | // already added to order, or because we have a cycle. 92 | // In both cases we stop. Cycle errors are reported 93 | // when type-checking types. 94 | return 95 | } 96 | visited[obj] = true 97 | 98 | d := check.objMap[obj] 99 | for _, obj := range orderedSetObjects(d.deps) { 100 | check.appendInPostOrder(order, obj, visited) 101 | } 102 | 103 | *order = append(*order, obj) 104 | } 105 | 106 | func orderedSetObjects(set objSet) []Object { 107 | list := make([]Object, len(set)) 108 | i := 0 109 | for obj := range set { 110 | // we don't care about the map element value 111 | list[i] = obj 112 | i++ 113 | } 114 | sort.Sort(inSourceOrder(list)) 115 | return list 116 | } 117 | 118 | // inSourceOrder implements the sort.Sort interface. 119 | type inSourceOrder []Object 120 | 121 | func (a inSourceOrder) Len() int { return len(a) } 122 | func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() } 123 | func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 124 | -------------------------------------------------------------------------------- /go/types/package.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 types 6 | 7 | import ( 8 | "fmt" 9 | "github.com/faiface/generics/go/token" 10 | ) 11 | 12 | // A Package describes a Go package. 13 | type Package struct { 14 | path string 15 | name string 16 | scope *Scope 17 | complete bool 18 | imports []*Package 19 | fake bool // scope lookup errors are silently dropped if package is fake (internal use only) 20 | } 21 | 22 | // NewPackage returns a new Package for the given package path and name. 23 | // The package is not complete and contains no explicit imports. 24 | func NewPackage(path, name string) *Package { 25 | scope := NewScope(Universe, token.NoPos, token.NoPos, fmt.Sprintf("package %q", path)) 26 | return &Package{path: path, name: name, scope: scope} 27 | } 28 | 29 | // Path returns the package path. 30 | func (pkg *Package) Path() string { return pkg.path } 31 | 32 | // Name returns the package name. 33 | func (pkg *Package) Name() string { return pkg.name } 34 | 35 | // SetName sets the package name. 36 | func (pkg *Package) SetName(name string) { pkg.name = name } 37 | 38 | // Scope returns the (complete or incomplete) package scope 39 | // holding the objects declared at package level (TypeNames, 40 | // Consts, Vars, and Funcs). 41 | func (pkg *Package) Scope() *Scope { return pkg.scope } 42 | 43 | // A package is complete if its scope contains (at least) all 44 | // exported objects; otherwise it is incomplete. 45 | func (pkg *Package) Complete() bool { return pkg.complete } 46 | 47 | // MarkComplete marks a package as complete. 48 | func (pkg *Package) MarkComplete() { pkg.complete = true } 49 | 50 | // Imports returns the list of packages directly imported by 51 | // pkg; the list is in source order. 52 | // 53 | // If pkg was loaded from export data, Imports includes packages that 54 | // provide package-level objects referenced by pkg. This may be more or 55 | // less than the set of packages directly imported by pkg's source code. 56 | func (pkg *Package) Imports() []*Package { return pkg.imports } 57 | 58 | // SetImports sets the list of explicitly imported packages to list. 59 | // It is the caller's responsibility to make sure list elements are unique. 60 | func (pkg *Package) SetImports(list []*Package) { pkg.imports = list } 61 | 62 | func (pkg *Package) String() string { 63 | return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path) 64 | } 65 | -------------------------------------------------------------------------------- /go/types/return.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | // This file implements isTerminating. 6 | 7 | package types 8 | 9 | import ( 10 | "github.com/faiface/generics/go/ast" 11 | "github.com/faiface/generics/go/token" 12 | ) 13 | 14 | // isTerminating reports if s is a terminating statement. 15 | // If s is labeled, label is the label name; otherwise s 16 | // is "". 17 | func (check *Checker) isTerminating(s ast.Stmt, label string) bool { 18 | switch s := s.(type) { 19 | default: 20 | unreachable() 21 | 22 | case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt, 23 | *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt, 24 | *ast.RangeStmt: 25 | // no chance 26 | 27 | case *ast.LabeledStmt: 28 | return check.isTerminating(s.Stmt, s.Label.Name) 29 | 30 | case *ast.ExprStmt: 31 | // the predeclared (possibly parenthesized) panic() function is terminating 32 | if call, _ := unparen(s.X).(*ast.CallExpr); call != nil { 33 | if id, _ := call.Fun.(*ast.Ident); id != nil { 34 | if _, obj := check.scope.LookupParent(id.Name, token.NoPos); obj != nil { 35 | if b, _ := obj.(*Builtin); b != nil && b.id == _Panic { 36 | return true 37 | } 38 | } 39 | } 40 | } 41 | 42 | case *ast.ReturnStmt: 43 | return true 44 | 45 | case *ast.BranchStmt: 46 | if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH { 47 | return true 48 | } 49 | 50 | case *ast.BlockStmt: 51 | return check.isTerminatingList(s.List, "") 52 | 53 | case *ast.IfStmt: 54 | if s.Else != nil && 55 | check.isTerminating(s.Body, "") && 56 | check.isTerminating(s.Else, "") { 57 | return true 58 | } 59 | 60 | case *ast.SwitchStmt: 61 | return check.isTerminatingSwitch(s.Body, label) 62 | 63 | case *ast.TypeSwitchStmt: 64 | return check.isTerminatingSwitch(s.Body, label) 65 | 66 | case *ast.SelectStmt: 67 | for _, s := range s.Body.List { 68 | cc := s.(*ast.CommClause) 69 | if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { 70 | return false 71 | } 72 | 73 | } 74 | return true 75 | 76 | case *ast.ForStmt: 77 | if s.Cond == nil && !hasBreak(s.Body, label, true) { 78 | return true 79 | } 80 | } 81 | 82 | return false 83 | } 84 | 85 | func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool { 86 | // trailing empty statements are permitted - skip them 87 | for i := len(list) - 1; i >= 0; i-- { 88 | if _, ok := list[i].(*ast.EmptyStmt); !ok { 89 | return check.isTerminating(list[i], label) 90 | } 91 | } 92 | return false // all statements are empty 93 | } 94 | 95 | func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool { 96 | hasDefault := false 97 | for _, s := range body.List { 98 | cc := s.(*ast.CaseClause) 99 | if cc.List == nil { 100 | hasDefault = true 101 | } 102 | if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { 103 | return false 104 | } 105 | } 106 | return hasDefault 107 | } 108 | 109 | // TODO(gri) For nested breakable statements, the current implementation of hasBreak 110 | // will traverse the same subtree repeatedly, once for each label. Replace 111 | // with a single-pass label/break matching phase. 112 | 113 | // hasBreak reports if s is or contains a break statement 114 | // referring to the label-ed statement or implicit-ly the 115 | // closest outer breakable statement. 116 | func hasBreak(s ast.Stmt, label string, implicit bool) bool { 117 | switch s := s.(type) { 118 | default: 119 | unreachable() 120 | 121 | case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt, 122 | *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, 123 | *ast.DeferStmt, *ast.ReturnStmt: 124 | // no chance 125 | 126 | case *ast.LabeledStmt: 127 | return hasBreak(s.Stmt, label, implicit) 128 | 129 | case *ast.BranchStmt: 130 | if s.Tok == token.BREAK { 131 | if s.Label == nil { 132 | return implicit 133 | } 134 | if s.Label.Name == label { 135 | return true 136 | } 137 | } 138 | 139 | case *ast.BlockStmt: 140 | return hasBreakList(s.List, label, implicit) 141 | 142 | case *ast.IfStmt: 143 | if hasBreak(s.Body, label, implicit) || 144 | s.Else != nil && hasBreak(s.Else, label, implicit) { 145 | return true 146 | } 147 | 148 | case *ast.CaseClause: 149 | return hasBreakList(s.Body, label, implicit) 150 | 151 | case *ast.SwitchStmt: 152 | if label != "" && hasBreak(s.Body, label, false) { 153 | return true 154 | } 155 | 156 | case *ast.TypeSwitchStmt: 157 | if label != "" && hasBreak(s.Body, label, false) { 158 | return true 159 | } 160 | 161 | case *ast.CommClause: 162 | return hasBreakList(s.Body, label, implicit) 163 | 164 | case *ast.SelectStmt: 165 | if label != "" && hasBreak(s.Body, label, false) { 166 | return true 167 | } 168 | 169 | case *ast.ForStmt: 170 | if label != "" && hasBreak(s.Body, label, false) { 171 | return true 172 | } 173 | 174 | case *ast.RangeStmt: 175 | if label != "" && hasBreak(s.Body, label, false) { 176 | return true 177 | } 178 | } 179 | 180 | return false 181 | } 182 | 183 | func hasBreakList(list []ast.Stmt, label string, implicit bool) bool { 184 | for _, s := range list { 185 | if hasBreak(s, label, implicit) { 186 | return true 187 | } 188 | } 189 | return false 190 | } 191 | -------------------------------------------------------------------------------- /go/types/scope.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | // This file implements Scopes. 6 | 7 | package types 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "io" 13 | "github.com/faiface/generics/go/token" 14 | "sort" 15 | "strings" 16 | ) 17 | 18 | // TODO(gri) Provide scopes with a name or other mechanism so that 19 | // objects can use that information for better printing. 20 | 21 | // A Scope maintains a set of objects and links to its containing 22 | // (parent) and contained (children) scopes. Objects may be inserted 23 | // and looked up by name. The zero value for Scope is a ready-to-use 24 | // empty scope. 25 | type Scope struct { 26 | parent *Scope 27 | children []*Scope 28 | elems map[string]Object // lazily allocated 29 | pos, end token.Pos // scope extent; may be invalid 30 | comment string // for debugging only 31 | isFunc bool // set if this is a function scope (internal use only) 32 | } 33 | 34 | // NewScope returns a new, empty scope contained in the given parent 35 | // scope, if any. The comment is for debugging only. 36 | func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope { 37 | s := &Scope{parent, nil, nil, pos, end, comment, false} 38 | // don't add children to Universe scope! 39 | if parent != nil && parent != Universe { 40 | parent.children = append(parent.children, s) 41 | } 42 | return s 43 | } 44 | 45 | // Parent returns the scope's containing (parent) scope. 46 | func (s *Scope) Parent() *Scope { return s.parent } 47 | 48 | // Len() returns the number of scope elements. 49 | func (s *Scope) Len() int { return len(s.elems) } 50 | 51 | // Names returns the scope's element names in sorted order. 52 | func (s *Scope) Names() []string { 53 | names := make([]string, len(s.elems)) 54 | i := 0 55 | for name := range s.elems { 56 | names[i] = name 57 | i++ 58 | } 59 | sort.Strings(names) 60 | return names 61 | } 62 | 63 | // NumChildren() returns the number of scopes nested in s. 64 | func (s *Scope) NumChildren() int { return len(s.children) } 65 | 66 | // Child returns the i'th child scope for 0 <= i < NumChildren(). 67 | func (s *Scope) Child(i int) *Scope { return s.children[i] } 68 | 69 | // Lookup returns the object in scope s with the given name if such an 70 | // object exists; otherwise the result is nil. 71 | func (s *Scope) Lookup(name string) Object { 72 | return s.elems[name] 73 | } 74 | 75 | // LookupParent follows the parent chain of scopes starting with s until 76 | // it finds a scope where Lookup(name) returns a non-nil object, and then 77 | // returns that scope and object. If a valid position pos is provided, 78 | // only objects that were declared at or before pos are considered. 79 | // If no such scope and object exists, the result is (nil, nil). 80 | // 81 | // Note that obj.Parent() may be different from the returned scope if the 82 | // object was inserted into the scope and already had a parent at that 83 | // time (see Insert, below). This can only happen for dot-imported objects 84 | // whose scope is the scope of the package that exported them. 85 | func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { 86 | for ; s != nil; s = s.parent { 87 | if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) { 88 | return s, obj 89 | } 90 | } 91 | return nil, nil 92 | } 93 | 94 | // Insert attempts to insert an object obj into scope s. 95 | // If s already contains an alternative object alt with 96 | // the same name, Insert leaves s unchanged and returns alt. 97 | // Otherwise it inserts obj, sets the object's parent scope 98 | // if not already set, and returns nil. 99 | func (s *Scope) Insert(obj Object) Object { 100 | name := obj.Name() 101 | if alt := s.elems[name]; alt != nil { 102 | return alt 103 | } 104 | if s.elems == nil { 105 | s.elems = make(map[string]Object) 106 | } 107 | s.elems[name] = obj 108 | if obj.Parent() == nil { 109 | obj.setParent(s) 110 | } 111 | return nil 112 | } 113 | 114 | // Pos and End describe the scope's source code extent [pos, end). 115 | // The results are guaranteed to be valid only if the type-checked 116 | // AST has complete position information. The extent is undefined 117 | // for Universe and package scopes. 118 | func (s *Scope) Pos() token.Pos { return s.pos } 119 | func (s *Scope) End() token.Pos { return s.end } 120 | 121 | // Contains returns true if pos is within the scope's extent. 122 | // The result is guaranteed to be valid only if the type-checked 123 | // AST has complete position information. 124 | func (s *Scope) Contains(pos token.Pos) bool { 125 | return s.pos <= pos && pos < s.end 126 | } 127 | 128 | // Innermost returns the innermost (child) scope containing 129 | // pos. If pos is not within any scope, the result is nil. 130 | // The result is also nil for the Universe scope. 131 | // The result is guaranteed to be valid only if the type-checked 132 | // AST has complete position information. 133 | func (s *Scope) Innermost(pos token.Pos) *Scope { 134 | // Package scopes do not have extents since they may be 135 | // discontiguous, so iterate over the package's files. 136 | if s.parent == Universe { 137 | for _, s := range s.children { 138 | if inner := s.Innermost(pos); inner != nil { 139 | return inner 140 | } 141 | } 142 | } 143 | 144 | if s.Contains(pos) { 145 | for _, s := range s.children { 146 | if s.Contains(pos) { 147 | return s.Innermost(pos) 148 | } 149 | } 150 | return s 151 | } 152 | return nil 153 | } 154 | 155 | // WriteTo writes a string representation of the scope to w, 156 | // with the scope elements sorted by name. 157 | // The level of indentation is controlled by n >= 0, with 158 | // n == 0 for no indentation. 159 | // If recurse is set, it also writes nested (children) scopes. 160 | func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { 161 | const ind = ". " 162 | indn := strings.Repeat(ind, n) 163 | 164 | fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s) 165 | if len(s.elems) == 0 { 166 | fmt.Fprintf(w, "}\n") 167 | return 168 | } 169 | 170 | fmt.Fprintln(w) 171 | indn1 := indn + ind 172 | for _, name := range s.Names() { 173 | fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) 174 | } 175 | 176 | if recurse { 177 | for _, s := range s.children { 178 | fmt.Fprintln(w) 179 | s.WriteTo(w, n+1, recurse) 180 | } 181 | } 182 | 183 | fmt.Fprintf(w, "%s}", indn) 184 | } 185 | 186 | // String returns a string representation of the scope, for debugging. 187 | func (s *Scope) String() string { 188 | var buf bytes.Buffer 189 | s.WriteTo(&buf, 0, false) 190 | return buf.String() 191 | } 192 | -------------------------------------------------------------------------------- /go/types/selection.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 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 | // This file implements Selections. 6 | 7 | package types 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | ) 13 | 14 | // SelectionKind describes the kind of a selector expression x.f 15 | // (excluding qualified identifiers). 16 | type SelectionKind int 17 | 18 | const ( 19 | FieldVal SelectionKind = iota // x.f is a struct field selector 20 | MethodVal // x.f is a method selector 21 | MethodExpr // x.f is a method expression 22 | ) 23 | 24 | // A Selection describes a selector expression x.f. 25 | // For the declarations: 26 | // 27 | // type T struct{ x int; E } 28 | // type E struct{} 29 | // func (e E) m() {} 30 | // var p *T 31 | // 32 | // the following relations exist: 33 | // 34 | // Selector Kind Recv Obj Type Index Indirect 35 | // 36 | // p.x FieldVal T x int {0} true 37 | // p.m MethodVal *T m func (e *T) m() {1, 0} true 38 | // T.m MethodExpr T m func m(_ T) {1, 0} false 39 | // 40 | type Selection struct { 41 | kind SelectionKind 42 | recv Type // type of x 43 | obj Object // object denoted by x.f 44 | index []int // path from x to x.f 45 | indirect bool // set if there was any pointer indirection on the path 46 | } 47 | 48 | // Kind returns the selection kind. 49 | func (s *Selection) Kind() SelectionKind { return s.kind } 50 | 51 | // Recv returns the type of x in x.f. 52 | func (s *Selection) Recv() Type { return s.recv } 53 | 54 | // Obj returns the object denoted by x.f; a *Var for 55 | // a field selection, and a *Func in all other cases. 56 | func (s *Selection) Obj() Object { return s.obj } 57 | 58 | // Type returns the type of x.f, which may be different from the type of f. 59 | // See Selection for more information. 60 | func (s *Selection) Type() Type { 61 | switch s.kind { 62 | case MethodVal: 63 | // The type of x.f is a method with its receiver type set 64 | // to the type of x. 65 | sig := *s.obj.(*Func).typ.(*Signature) 66 | recv := *sig.recv 67 | recv.typ = s.recv 68 | sig.recv = &recv 69 | return &sig 70 | 71 | case MethodExpr: 72 | // The type of x.f is a function (without receiver) 73 | // and an additional first argument with the same type as x. 74 | // TODO(gri) Similar code is already in call.go - factor! 75 | // TODO(gri) Compute this eagerly to avoid allocations. 76 | sig := *s.obj.(*Func).typ.(*Signature) 77 | arg0 := *sig.recv 78 | sig.recv = nil 79 | arg0.typ = s.recv 80 | var params []*Var 81 | if sig.params != nil { 82 | params = sig.params.vars 83 | } 84 | sig.params = NewTuple(append([]*Var{&arg0}, params...)...) 85 | return &sig 86 | } 87 | 88 | // In all other cases, the type of x.f is the type of x. 89 | return s.obj.Type() 90 | } 91 | 92 | // Index describes the path from x to f in x.f. 93 | // The last index entry is the field or method index of the type declaring f; 94 | // either: 95 | // 96 | // 1) the list of declared methods of a named type; or 97 | // 2) the list of methods of an interface type; or 98 | // 3) the list of fields of a struct type. 99 | // 100 | // The earlier index entries are the indices of the embedded fields implicitly 101 | // traversed to get from (the type of) x to f, starting at embedding depth 0. 102 | func (s *Selection) Index() []int { return s.index } 103 | 104 | // Indirect reports whether any pointer indirection was required to get from 105 | // x to f in x.f. 106 | func (s *Selection) Indirect() bool { return s.indirect } 107 | 108 | func (s *Selection) String() string { return SelectionString(s, nil) } 109 | 110 | // SelectionString returns the string form of s. 111 | // The Qualifier controls the printing of 112 | // package-level objects, and may be nil. 113 | // 114 | // Examples: 115 | // "field (T) f int" 116 | // "method (T) f(X) Y" 117 | // "method expr (T) f(X) Y" 118 | // 119 | func SelectionString(s *Selection, qf Qualifier) string { 120 | var k string 121 | switch s.kind { 122 | case FieldVal: 123 | k = "field " 124 | case MethodVal: 125 | k = "method " 126 | case MethodExpr: 127 | k = "method expr " 128 | default: 129 | unreachable() 130 | } 131 | var buf bytes.Buffer 132 | buf.WriteString(k) 133 | buf.WriteByte('(') 134 | WriteType(&buf, s.Recv(), qf) 135 | fmt.Fprintf(&buf, ") %s", s.obj.Name()) 136 | if T := s.Type(); s.kind == FieldVal { 137 | buf.WriteByte(' ') 138 | WriteType(&buf, T, qf) 139 | } else { 140 | WriteSignature(&buf, T.(*Signature), qf) 141 | } 142 | return buf.String() 143 | } 144 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/faiface/generics/degen" 10 | "github.com/faiface/generics/go/ast" 11 | "github.com/faiface/generics/go/importer" 12 | "github.com/faiface/generics/go/parser" 13 | "github.com/faiface/generics/go/printer" 14 | "github.com/faiface/generics/go/token" 15 | "github.com/faiface/generics/go/types" 16 | ) 17 | 18 | var ( 19 | output = flag.String("out", "out.go", "output file") 20 | debug = flag.Bool("debug", false, "prints intermediate type-checking errors to the standard output and other debug info") 21 | maxPass = flag.Int("maxpass", -1, "maximum number of passes") 22 | ) 23 | 24 | func init() { 25 | flag.Usage = func() { 26 | fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [flags...] \n", os.Args[0]) 27 | flag.PrintDefaults() 28 | } 29 | } 30 | 31 | func fail(err error) { 32 | fmt.Fprintln(os.Stderr, err) 33 | os.Exit(1) 34 | } 35 | 36 | func main() { 37 | flag.Parse() 38 | if len(flag.Args()) != 1 || flag.Arg(0) == "" { 39 | flag.Usage() 40 | return 41 | } 42 | 43 | fset := token.NewFileSet() 44 | 45 | file, err := parser.ParseFile( 46 | fset, 47 | flag.Arg(0), 48 | nil, 49 | parser.DeclarationErrors, 50 | ) 51 | if err != nil { 52 | fail(err) 53 | } 54 | 55 | typesCfg := types.Config{ 56 | Importer: importer.Default(), 57 | } 58 | info := types.Info{ 59 | Types: make(map[ast.Expr]types.TypeAndValue), 60 | GenericCalls: make(map[*ast.CallExpr]*types.GenericCall), 61 | } 62 | _, err = typesCfg.Check("", fset, []*ast.File{file}, &info) 63 | if err != nil { 64 | fail(err) 65 | } 66 | 67 | // degenerate 68 | for pass := 1; *maxPass < 0 || pass <= *maxPass; pass++ { 69 | if *debug { 70 | fmt.Printf("PASS %d\n", pass) 71 | } 72 | 73 | var changed bool 74 | file, changed = degen.Degen(fset, file, *debug) 75 | 76 | var b bytes.Buffer 77 | err := printer.Fprint(&b, fset, file) 78 | if err != nil { 79 | fail(err) 80 | } 81 | 82 | fset = token.NewFileSet() 83 | file, err = parser.ParseFile( 84 | fset, 85 | flag.Arg(0), 86 | &b, 87 | parser.DeclarationErrors, 88 | ) 89 | if err != nil { 90 | fail(err) 91 | } 92 | 93 | if !changed { 94 | break 95 | } 96 | } 97 | 98 | // filter out generic function declarations 99 | var decls []ast.Decl 100 | for _, decl := range file.Decls { 101 | switch decl := decl.(type) { 102 | default: 103 | decls = append(decls, decl) 104 | 105 | case *ast.FuncDecl: 106 | if len(decl.TypeParams) == 0 { 107 | decls = append(decls, decl) 108 | } 109 | 110 | case *ast.GenDecl: 111 | if decl.Tok != token.TYPE { 112 | decls = append(decls, decl) 113 | continue 114 | } 115 | 116 | for _, spec := range decl.Specs { 117 | spec := spec.(*ast.TypeSpec) 118 | 119 | if len(spec.Params) == 0 { 120 | decls = append(decls, &ast.GenDecl{ 121 | Tok: decl.Tok, 122 | Specs: []ast.Spec{spec}, 123 | }) 124 | } 125 | } 126 | } 127 | } 128 | file.Decls = decls 129 | 130 | outputFile, err := os.Create(*output) 131 | if err != nil { 132 | fail(err) 133 | } 134 | defer outputFile.Close() 135 | printer.Fprint(outputFile, fset, file) 136 | } 137 | --------------------------------------------------------------------------------