@@ -28,17 +28,16 @@ import (
28
28
_ "embed"
29
29
"flag"
30
30
"fmt"
31
- "go/ast"
32
31
"go/constant"
33
32
"go/format"
34
- "go/parser"
35
- "go/printer"
36
33
"go/token"
34
+ "go/types"
37
35
"log"
38
36
"math/big"
39
37
"os"
40
38
"path"
41
39
"path/filepath"
40
+ "sort"
42
41
"strings"
43
42
"text/template"
44
43
@@ -107,7 +106,7 @@ func main() {
107
106
packagesList = append (packagesList , path .Join (pkgParent , pkg ))
108
107
}
109
108
110
- cfg := & packages.Config {Mode : packages .NeedName | packages .NeedFiles }
109
+ cfg := & packages.Config {Mode : packages .NeedName | packages .NeedFiles | packages . NeedTypes }
111
110
pkgs , err := packages .Load (cfg , packagesList ... )
112
111
if err != nil {
113
112
fmt .Fprintf (os .Stderr , "load: %v\n " , err )
@@ -127,7 +126,6 @@ type generator struct {
127
126
dir string
128
127
w * bytes.Buffer
129
128
cuePkgPath string
130
- fset * token.FileSet
131
129
first bool
132
130
}
133
131
@@ -142,7 +140,6 @@ func generate(pkg *packages.Package) error {
142
140
dir : pkgDir ,
143
141
cuePkgPath : cuePkg ,
144
142
w : & bytes.Buffer {},
145
- fset : token .NewFileSet (),
146
143
}
147
144
148
145
params := headerParams {
@@ -175,13 +172,8 @@ func generate(pkg *packages.Package) error {
175
172
if ! skipRegister {
176
173
fmt .Fprintf (g .w , "var p = &pkg.Package{\n Native: []*pkg.Builtin{" )
177
174
g .first = true
178
- for _ , filename := range pkg .GoFiles {
179
- if filename == genFile {
180
- continue
181
- }
182
- if err := g .processGo (filename ); err != nil {
183
- return err
184
- }
175
+ if err := g .processGo (pkg ); err != nil {
176
+ return err
185
177
}
186
178
fmt .Fprintf (g .w , "},\n " )
187
179
if err := g .processCUE (); err != nil {
@@ -192,6 +184,7 @@ func generate(pkg *packages.Package) error {
192
184
193
185
b , err := format .Source (g .w .Bytes ())
194
186
if err != nil {
187
+ fmt .Printf ("go/format error on %s: %v\n " , pkg .PkgPath , err )
195
188
b = g .w .Bytes () // write the unformatted source
196
189
}
197
190
@@ -241,115 +234,90 @@ func (g *generator) processCUE() error {
241
234
return nil
242
235
}
243
236
244
- func (g * generator ) processGo (filename string ) error {
245
- f , err := parser .ParseFile (g .fset , filename , nil , parser .ParseComments )
246
- if err != nil {
247
- return err
248
- }
237
+ func (g * generator ) processGo (pkg * packages.Package ) error {
238
+ // We sort the objects by their original source code position.
239
+ // Otherwise go/types defaults to sorting by name strings.
240
+ // We could remove this code if we were fine with sorting by name.
241
+ scope := pkg .Types .Scope ()
242
+ type objWithPos struct {
243
+ obj types.Object
244
+ pos token.Position
245
+ }
246
+ var objs []objWithPos
247
+ for _ , name := range scope .Names () {
248
+ obj := scope .Lookup (name )
249
+ objs = append (objs , objWithPos {obj , pkg .Fset .Position (obj .Pos ())})
250
+ }
251
+ sort .Slice (objs , func (i , j int ) bool {
252
+ obj1 , obj2 := objs [i ], objs [j ]
253
+ if obj1 .pos .Filename == obj2 .pos .Filename {
254
+ return obj1 .pos .Line < obj2 .pos .Line
255
+ }
256
+ return obj1 .pos .Filename < obj2 .pos .Filename
257
+ })
249
258
250
- for _ , d := range f .Decls {
251
- switch x := d .(type ) {
252
- case * ast.GenDecl :
253
- switch x .Tok {
254
- case token .CONST :
255
- for _ , spec := range x .Specs {
256
- spec := spec .(* ast.ValueSpec )
257
- if ast .IsExported (spec .Names [0 ].Name ) {
258
- g .genConst (spec )
259
- }
260
- }
261
- case token .VAR :
262
- continue
263
- case token .TYPE :
264
- // TODO: support type declarations.
265
- continue
266
- case token .IMPORT :
267
- continue
259
+ for _ , obj := range objs {
260
+ obj := obj .obj // no longer need the token.Position
261
+ if ! obj .Exported () {
262
+ continue
263
+ }
264
+ // TODO: support type declarations.
265
+ switch obj := obj .(type ) {
266
+ case * types.Const :
267
+ var value string
268
+ switch v := obj .Val (); v .Kind () {
269
+ case constant .Bool , constant .Int , constant .String :
270
+ // TODO: convert octal numbers
271
+ value = v .ExactString ()
272
+ case constant .Float :
273
+ var rat big.Rat
274
+ rat .SetString (v .ExactString ())
275
+ var float big.Float
276
+ float .SetRat (& rat )
277
+ value = float .Text ('g' , - 1 )
268
278
default :
269
- panic (fmt .Errorf ("gen %s: unexpected spec of type %s" , filename , x .Tok ))
279
+ fmt .Printf ("Dropped entry %s.%s (%T: %v)\n " , g .cuePkgPath , obj .Name (), v .Kind (), v .ExactString ())
280
+ continue
270
281
}
271
- case * ast.FuncDecl :
272
- g .genFunc (x )
282
+ g .sep ()
283
+ fmt .Fprintf (g .w , "{\n Name: %q,\n Const: %q,\n }" , obj .Name (), value )
284
+ case * types.Func :
285
+ g .genFunc (obj )
273
286
}
274
287
}
275
288
return nil
276
289
}
277
290
278
- func (g * generator ) genConst (spec * ast.ValueSpec ) {
279
- name := spec .Names [0 ].Name
280
- value := ""
281
- switch v := g .toValue (spec .Values [0 ]); v .Kind () {
282
- case constant .Bool , constant .Int , constant .String :
283
- // TODO: convert octal numbers
284
- value = v .ExactString ()
285
- case constant .Float :
286
- var rat big.Rat
287
- rat .SetString (v .ExactString ())
288
- var float big.Float
289
- float .SetRat (& rat )
290
- value = float .Text ('g' , - 1 )
291
- default :
292
- fmt .Printf ("Dropped entry %s.%s (%T: %v)\n " , g .cuePkgPath , name , v .Kind (), v .ExactString ())
293
- return
294
- }
295
- g .sep ()
296
- fmt .Fprintf (g .w , "{\n Name: %q,\n Const: %q,\n }" , name , value )
297
- }
298
-
299
- func (g * generator ) toValue (x ast.Expr ) constant.Value {
300
- switch x := x .(type ) {
301
- case * ast.BasicLit :
302
- return constant .MakeFromLiteral (x .Value , x .Kind , 0 )
303
- case * ast.BinaryExpr :
304
- return constant .BinaryOp (g .toValue (x .X ), x .Op , g .toValue (x .Y ))
305
- case * ast.UnaryExpr :
306
- return constant .UnaryOp (x .Op , g .toValue (x .X ), 0 )
307
- default :
308
- panic (fmt .Errorf ("%s: unsupported expression type %T: %#v" , g .cuePkgPath , x , x ))
309
- }
310
- }
291
+ var errorType = types .Universe .Lookup ("error" ).Type ()
311
292
312
- func (g * generator ) genFunc (x * ast.FuncDecl ) {
313
- if x .Body == nil || ! ast .IsExported (x .Name .Name ) {
293
+ func (g * generator ) genFunc (fn * types.Func ) {
294
+ sign := fn .Type ().(* types.Signature )
295
+ if sign .Recv () != nil {
314
296
return
315
297
}
316
- types := []string {}
317
- if x .Type .Results != nil {
318
- for _ , f := range x .Type .Results .List {
319
- if len (f .Names ) > 0 {
320
- for range f .Names {
321
- types = append (types , g .goKind (f .Type ))
322
- }
323
- } else {
324
- types = append (types , g .goKind (f .Type ))
325
- }
326
- }
327
- }
328
- if x .Recv != nil {
329
- return
330
- }
331
- if n := len (types ); n != 1 && (n != 2 || types [1 ] != "error" ) {
332
- fmt .Printf ("Dropped func %s.%s: must have one return value or a value and an error %v\n " , g .cuePkgPath , x .Name .Name , types )
298
+ params := sign .Params ()
299
+ results := sign .Results ()
300
+ if results == nil || (results .Len () != 1 && results .At (1 ).Type () != errorType ) {
301
+ fmt .Printf ("Dropped func %s.%s: must have one return value or a value and an error %v\n " , g .cuePkgPath , fn .Name (), sign )
333
302
return
334
303
}
335
304
336
305
g .sep ()
337
306
fmt .Fprintf (g .w , "{\n " )
338
307
defer fmt .Fprintf (g .w , "}" )
339
308
340
- fmt .Fprintf (g .w , "Name: %q,\n " , x .Name . Name )
309
+ fmt .Fprintf (g .w , "Name: %q,\n " , fn .Name () )
341
310
342
311
args := []string {}
343
312
vals := []string {}
344
313
kind := []string {}
345
- for _ , f := range x .Type .Params .List {
346
- for _ , name := range f .Names {
347
- typ := strings .Title (g .goKind (f .Type ))
348
- argKind := g .goToCUE (f .Type )
349
- vals = append (vals , fmt .Sprintf ("c.%s(%d)" , typ , len (args )))
350
- args = append (args , name .Name )
351
- kind = append (kind , argKind )
352
- }
314
+ for i := 0 ; i < params .Len (); i ++ {
315
+ param := params .At (i )
316
+ typ := strings .Title (g .goKind (param .Type ()))
317
+ argKind := g .goToCUE (param .Type ())
318
+ vals = append (vals , fmt .Sprintf ("c.%s(%d)" , typ , len (args )))
319
+ args = append (args , param .Name ())
320
+ kind = append (kind , argKind )
353
321
}
354
322
355
323
fmt .Fprintf (g .w , "Params: []pkg.Param{\n " )
@@ -358,8 +326,7 @@ func (g *generator) genFunc(x *ast.FuncDecl) {
358
326
}
359
327
fmt .Fprintf (g .w , "\n },\n " )
360
328
361
- expr := x .Type .Results .List [0 ].Type
362
- fmt .Fprintf (g .w , "Result: %s,\n " , g .goToCUE (expr ))
329
+ fmt .Fprintf (g .w , "Result: %s,\n " , g .goToCUE (results .At (0 ).Type ()))
363
330
364
331
argList := strings .Join (args , ", " )
365
332
valList := strings .Join (vals , ", " )
@@ -376,45 +343,45 @@ func (g *generator) genFunc(x *ast.FuncDecl) {
376
343
}
377
344
fmt .Fprintln (g .w , "if c.Do() {" )
378
345
defer fmt .Fprintln (g .w , "}" )
379
- if len ( types ) == 1 {
380
- fmt .Fprintf (g .w , "c.Ret = %s(%s)" , x .Name . Name , argList )
346
+ if results . Len ( ) == 1 {
347
+ fmt .Fprintf (g .w , "c.Ret = %s(%s)" , fn .Name () , argList )
381
348
} else {
382
- fmt .Fprintf (g .w , "c.Ret, c.Err = %s(%s)" , x .Name . Name , argList )
349
+ fmt .Fprintf (g .w , "c.Ret, c.Err = %s(%s)" , fn .Name () , argList )
383
350
}
384
351
}
385
352
386
- func (g * generator ) goKind (expr ast.Expr ) string {
387
- if star , isStar := expr .(* ast.StarExpr ); isStar {
388
- expr = star .X
353
+ // TODO(mvdan): goKind and goToCUE still use a lot of strings; simplify.
354
+
355
+ func (g * generator ) goKind (typ types.Type ) string {
356
+ if ptr , ok := typ .(* types.Pointer ); ok {
357
+ typ = ptr .Elem ()
389
358
}
390
- w := & bytes.Buffer {}
391
- printer .Fprint (w , g .fset , expr )
392
- switch str := w .String (); str {
393
- case "big.Int" :
359
+ switch str := types .TypeString (typ , nil ); str {
360
+ case "math/big.Int" :
394
361
return "bigInt"
395
- case "big.Float" :
362
+ case "math/ big.Float" :
396
363
return "bigFloat"
397
- case "big.Rat" :
364
+ case "math/ big.Rat" :
398
365
return "bigRat"
399
- case "adt.Bottom" :
366
+ case "cuelang.org/go/internal/core/ adt.Bottom" :
400
367
return "error"
401
- case "internal .Decimal" :
368
+ case "github.com/cockroachdb/apd/v3 .Decimal" :
402
369
return "decimal"
403
- case "pkg.List" :
370
+ case "cuelang.org/go/internal/ pkg.List" :
404
371
return "cueList"
405
- case "pkg.Struct" :
372
+ case "cuelang.org/go/internal/ pkg.Struct" :
406
373
return "struct"
407
- case "[]*internal .Decimal" :
374
+ case "[]*github.com/cockroachdb/apd/v3 .Decimal" :
408
375
return "decimalList"
409
- case "cue.Value" :
376
+ case "cuelang.org/go/ cue.Value" :
410
377
return "value"
411
- case "cue.List" :
378
+ case "cuelang.org/go/ cue.List" :
412
379
return "list"
413
380
case "[]string" :
414
381
return "stringList"
415
382
case "[]byte" :
416
383
return "bytes"
417
- case "[]cue.Value" :
384
+ case "[]cuelang.org/go/ cue.Value" :
418
385
return "list"
419
386
case "io.Reader" :
420
387
return "reader"
@@ -425,9 +392,9 @@ func (g *generator) goKind(expr ast.Expr) string {
425
392
}
426
393
}
427
394
428
- func (g * generator ) goToCUE (expr ast. Expr ) (cueKind string ) {
395
+ func (g * generator ) goToCUE (typ types. Type ) (cueKind string ) {
429
396
// TODO: detect list and structs types for return values.
430
- switch k := g .goKind (expr ); k {
397
+ switch k := g .goKind (typ ); k {
431
398
case "error" :
432
399
cueKind += "adt.BottomKind"
433
400
case "bool" :
0 commit comments