1
2
3
4
5 package inline
6
7
8
9 import (
10 "fmt"
11 "go/ast"
12 "go/constant"
13 "go/format"
14 "go/token"
15 "go/types"
16 "strconv"
17 "strings"
18
19 "golang.org/x/tools/go/types/typeutil"
20 "golang.org/x/tools/internal/typeparams"
21 )
22
23
24 type falconResult struct {
25 Types []falconType
26 Constraints []string
27 }
28
29
30
31
32
33
34
35
36
37
38 type falconType struct {
39 Name string
40 Kind types.BasicKind
41 }
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 func falcon(logf func(string, ...any), fset *token.FileSet, params map[*types.Var]*paramInfo, info *types.Info, decl *ast.FuncDecl) falconResult {
115
116 st := &falconState{
117 logf: logf,
118 fset: fset,
119 params: params,
120 info: info,
121 decl: decl,
122 }
123
124
125 st.int = st.typename(types.Typ[types.Int])
126 st.any = "interface{}"
127 for obj, info := range st.params {
128 if isBasic(obj.Type(), types.IsConstType) {
129 info.FalconType = st.typename(obj.Type())
130 }
131 }
132
133 st.stmt(st.decl.Body)
134
135 return st.result
136 }
137
138 type falconState struct {
139
140 logf func(string, ...any)
141 fset *token.FileSet
142 params map[*types.Var]*paramInfo
143 info *types.Info
144 decl *ast.FuncDecl
145
146
147 int string
148 any string
149 typenames typeutil.Map
150
151 result falconResult
152 }
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169 func (st *falconState) typename(t types.Type) string {
170 name, ok := st.typenames.At(t).(string)
171 if !ok {
172 basic := t.Underlying().(*types.Basic)
173
174
175
176
177 name = fmt.Sprintf("%s۰%d", basic, st.typenames.Len())
178 st.typenames.Set(t, name)
179 st.logf("falcon: emit type %s %s // %q", name, basic, t)
180 st.result.Types = append(st.result.Types, falconType{
181 Name: name,
182 Kind: basic.Kind(),
183 })
184 }
185 return name
186 }
187
188
189
190
191
192
193
194 func (st *falconState) emit(constraint ast.Expr) {
195 var out strings.Builder
196 if err := format.Node(&out, st.fset, constraint); err != nil {
197 panic(err)
198 }
199 syntax := out.String()
200 st.logf("falcon: emit constraint %s", syntax)
201 st.result.Constraints = append(st.result.Constraints, syntax)
202 }
203
204
205
206 func (st *falconState) emitNonNegative(index ast.Expr) {
207 st.emit(&ast.IndexExpr{
208 X: &ast.CompositeLit{
209 Type: &ast.ArrayType{
210 Elt: makeIdent(st.int),
211 },
212 },
213 Index: index,
214 })
215 }
216
217
218
219 func (st *falconState) emitMonotonic(i, j ast.Expr) {
220 st.emit(&ast.SliceExpr{
221 X: &ast.CompositeLit{
222 Type: &ast.ArrayType{
223 Elt: makeIdent(st.int),
224 },
225 },
226 Low: i,
227 High: j,
228 })
229 }
230
231
232
233
234
235 func (st *falconState) emitUnique(typ ast.Expr, elems []ast.Expr) {
236 if len(elems) > 1 {
237 var elts []ast.Expr
238 for _, elem := range elems {
239 elts = append(elts, &ast.KeyValueExpr{
240 Key: elem,
241 Value: makeIntLit(0),
242 })
243 }
244 st.emit(&ast.CompositeLit{
245 Type: typ,
246 Elts: elts,
247 })
248 }
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 func (st *falconState) stmt(s ast.Stmt) {
265 ast.Inspect(s, func(n ast.Node) bool {
266 switch n := n.(type) {
267 case ast.Expr:
268 _ = st.expr(n)
269 return false
270
271 case *ast.AssignStmt:
272 switch n.Tok {
273 case token.QUO_ASSIGN, token.REM_ASSIGN:
274
275
276
277 _ = st.expr(n.Lhs[0])
278 kY := st.expr(n.Rhs[0])
279 if kY, ok := kY.(ast.Expr); ok {
280 op := token.QUO
281 if n.Tok == token.REM_ASSIGN {
282 op = token.REM
283 }
284 st.emit(&ast.BinaryExpr{
285 Op: op,
286 X: makeIntLit(1),
287 Y: kY,
288 })
289 }
290 return false
291 }
292
293 case *ast.SwitchStmt:
294 if n.Init != nil {
295 st.stmt(n.Init)
296 }
297 tBool := types.Type(types.Typ[types.Bool])
298 tagType := tBool
299 if n.Tag != nil {
300 st.expr(n.Tag)
301 tagType = st.info.TypeOf(n.Tag)
302 }
303
304
305
306
307
308 var unique []ast.Expr
309 for _, clause := range n.Body.List {
310 clause := clause.(*ast.CaseClause)
311 for _, caseval := range clause.List {
312 if k := st.expr(caseval); k != nil {
313 unique = append(unique, st.toExpr(k))
314 }
315 }
316 for _, stmt := range clause.Body {
317 st.stmt(stmt)
318 }
319 }
320 if unique != nil && !types.Identical(tagType.Underlying(), tBool) {
321 tname := st.any
322 if !types.IsInterface(tagType) {
323 tname = st.typename(tagType)
324 }
325 t := &ast.MapType{
326 Key: makeIdent(tname),
327 Value: makeIdent(st.int),
328 }
329 st.emitUnique(t, unique)
330 }
331 }
332 return true
333 })
334 }
335
336
337 func (st *falconState) fieldTypes(fields *ast.FieldList) {
338 if fields != nil {
339 for _, field := range fields.List {
340 _ = st.expr(field.Type)
341 }
342 }
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 func (st *falconState) expr(e ast.Expr) (res any) {
379 tv := st.info.Types[e]
380 if tv.Value != nil {
381
382 defer func() { res = tv }()
383 }
384
385 switch e := e.(type) {
386 case *ast.Ident:
387 if v, ok := st.info.Uses[e].(*types.Var); ok {
388 if _, ok := st.params[v]; ok && isBasic(v.Type(), types.IsConstType) {
389 return e
390 }
391 }
392
393
394 case *ast.BasicLit:
395
396
397 case *ast.ParenExpr:
398 return st.expr(e.X)
399
400 case *ast.FuncLit:
401 _ = st.expr(e.Type)
402 st.stmt(e.Body)
403
404
405 case *ast.CompositeLit:
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422 if e.Type != nil {
423 _ = st.expr(e.Type)
424 }
425 t := types.Unalias(typeparams.Deref(tv.Type))
426 ct := typeparams.CoreType(t)
427 var mapKeys []ast.Expr
428 for _, elt := range e.Elts {
429 if kv, ok := elt.(*ast.KeyValueExpr); ok {
430 if is[*types.Map](ct) {
431 if k := st.expr(kv.Key); k != nil {
432 mapKeys = append(mapKeys, st.toExpr(k))
433 }
434 }
435 _ = st.expr(kv.Value)
436 } else {
437 _ = st.expr(elt)
438 }
439 }
440 if len(mapKeys) > 0 {
441
442
443
444 t := ct.(*types.Map)
445 var typ ast.Expr
446 if types.IsInterface(t.Key()) {
447 typ = &ast.MapType{
448 Key: makeIdent(st.any),
449 Value: makeIdent(st.int),
450 }
451 } else {
452 typ = &ast.MapType{
453 Key: makeIdent(st.typename(t.Key())),
454 Value: makeIdent(st.int),
455 }
456 }
457 st.emitUnique(typ, mapKeys)
458 }
459
460
461 case *ast.SelectorExpr:
462 _ = st.expr(e.X)
463 _ = st.expr(e.Sel)
464
465
466
467
468 case *ast.IndexExpr:
469 if tv.IsType() {
470
471 _ = st.expr(e.X)
472 _ = st.expr(e.Index)
473 } else {
474
475
476
477
478
479
480
481
482
483
484
485 kX := st.expr(e.X)
486 kI := st.expr(e.Index)
487 if kI != nil && !is[*types.Map](st.info.TypeOf(e.X).Underlying()) {
488 if kI, ok := kI.(ast.Expr); ok {
489 st.emitNonNegative(kI)
490 }
491
492
493 var x ast.Expr
494 if kX != nil {
495
496 x = st.toExpr(kX)
497 } else if arr, ok := typeparams.CoreType(typeparams.Deref(st.info.TypeOf(e.X))).(*types.Array); ok {
498
499 x = &ast.CompositeLit{
500 Type: &ast.ArrayType{
501 Len: makeIntLit(arr.Len()),
502 Elt: makeIdent(st.int),
503 },
504 }
505 }
506 if x != nil {
507 st.emit(&ast.IndexExpr{
508 X: x,
509 Index: st.toExpr(kI),
510 })
511 }
512 }
513 }
514
515
516 case *ast.SliceExpr:
517
518
519
520
521
522
523
524 kX := st.expr(e.X)
525 var kLow, kHigh, kMax any
526 if e.Low != nil {
527 kLow = st.expr(e.Low)
528 if kLow != nil {
529 if kLow, ok := kLow.(ast.Expr); ok {
530 st.emitNonNegative(kLow)
531 }
532 }
533 }
534 if e.High != nil {
535 kHigh = st.expr(e.High)
536 if kHigh != nil {
537 if kHigh, ok := kHigh.(ast.Expr); ok {
538 st.emitNonNegative(kHigh)
539 }
540 if kLow != nil {
541 st.emitMonotonic(st.toExpr(kLow), st.toExpr(kHigh))
542 }
543 }
544 }
545 if e.Max != nil {
546 kMax = st.expr(e.Max)
547 if kMax != nil {
548 if kMax, ok := kMax.(ast.Expr); ok {
549 st.emitNonNegative(kMax)
550 }
551 if kHigh != nil {
552 st.emitMonotonic(st.toExpr(kHigh), st.toExpr(kMax))
553 }
554 }
555 }
556
557
558 var x ast.Expr
559 if kX != nil {
560
561 x = st.toExpr(kX)
562 } else if arr, ok := typeparams.CoreType(typeparams.Deref(st.info.TypeOf(e.X))).(*types.Array); ok {
563
564 x = &ast.CompositeLit{
565 Type: &ast.ArrayType{
566 Len: makeIntLit(arr.Len()),
567 Elt: makeIdent(st.int),
568 },
569 }
570 }
571 if x != nil {
572
573 high, max := st.toExpr(kHigh), st.toExpr(kMax)
574 if high == nil {
575 high = max
576 }
577 st.emit(&ast.SliceExpr{
578 X: x,
579 Low: st.toExpr(kLow),
580 High: high,
581 Max: max,
582 })
583 }
584
585
586 case *ast.TypeAssertExpr:
587 _ = st.expr(e.X)
588 if e.Type != nil {
589 _ = st.expr(e.Type)
590 }
591
592 case *ast.CallExpr:
593 _ = st.expr(e.Fun)
594 if tv, ok := st.info.Types[e.Fun]; ok && tv.IsType() {
595
596
597
598 kX := st.expr(e.Args[0])
599 if kX != nil && isBasic(tv.Type, types.IsConstType) {
600 conv := convert(makeIdent(st.typename(tv.Type)), st.toExpr(kX))
601 if is[ast.Expr](kX) {
602 st.emit(conv)
603 }
604 return conv
605 }
606 return nil
607 }
608
609
610
611 all := true
612 kArgs := make([]ast.Expr, len(e.Args))
613 for i, arg := range e.Args {
614 if kArg := st.expr(arg); kArg != nil {
615 kArgs[i] = st.toExpr(kArg)
616 } else {
617 all = false
618 }
619 }
620
621
622
623
624 if id, ok := e.Fun.(*ast.Ident); ok && all && tv.Value == nil {
625 if builtin, ok := st.info.Uses[id].(*types.Builtin); ok {
626 switch builtin.Name() {
627 case "len", "imag", "real", "complex", "min", "max":
628 return &ast.CallExpr{
629 Fun: id,
630 Args: kArgs,
631 Ellipsis: e.Ellipsis,
632 }
633 }
634 }
635 }
636
637 case *ast.StarExpr:
638 _ = st.expr(e.X)
639
640 case *ast.UnaryExpr:
641
642
643
644
645 kX := st.expr(e.X)
646 if kX != nil && !is[types.TypeAndValue](kX) {
647 if e.Op == token.SUB {
648 st.emit(&ast.UnaryExpr{
649 Op: e.Op,
650 X: st.toExpr(kX),
651 })
652 }
653
654 return &ast.UnaryExpr{
655 Op: e.Op,
656 X: st.toExpr(kX),
657 }
658 }
659
660 case *ast.BinaryExpr:
661 kX := st.expr(e.X)
662 kY := st.expr(e.Y)
663 switch e.Op {
664 case token.QUO, token.REM:
665
666
667
668
669
670 if kY != nil {
671 if kX == nil {
672 kX = makeIntLit(1)
673 }
674 st.emit(&ast.BinaryExpr{
675 Op: e.Op,
676 X: st.toExpr(kX),
677 Y: st.toExpr(kY),
678 })
679 }
680
681 case token.ADD, token.SUB, token.MUL:
682
683
684
685
686 if kX != nil && kY != nil {
687 st.emit(&ast.BinaryExpr{
688 Op: e.Op,
689 X: st.toExpr(kX),
690 Y: st.toExpr(kY),
691 })
692 }
693
694 case token.SHL, token.SHR:
695
696
697
698
699
700
701
702
703
704 if kX != nil || kY != nil {
705 x := st.toExpr(kX)
706 if x == nil {
707 x = makeIntLit(1)
708 }
709 y := st.toExpr(kY)
710 if y == nil {
711 y = makeIntLit(0)
712 }
713 st.emit(&ast.BinaryExpr{
714 Op: e.Op,
715 X: x,
716 Y: y,
717 })
718 }
719
720 case token.LSS, token.GTR, token.EQL, token.NEQ, token.LEQ, token.GEQ:
721
722
723
724
725
726
727
728
729
730
731 }
732 if kX != nil && kY != nil {
733 return &ast.BinaryExpr{
734 Op: e.Op,
735 X: st.toExpr(kX),
736 Y: st.toExpr(kY),
737 }
738 }
739
740
741
742
743
744
745
746
747
748
749
750
751 case *ast.IndexListExpr:
752 _ = st.expr(e.X)
753 for _, expr := range e.Indices {
754 _ = st.expr(expr)
755 }
756
757 case *ast.Ellipsis:
758 if e.Elt != nil {
759 _ = st.expr(e.Elt)
760 }
761
762 case *ast.ArrayType:
763 if e.Len != nil {
764 _ = st.expr(e.Len)
765 }
766 _ = st.expr(e.Elt)
767
768 case *ast.StructType:
769 st.fieldTypes(e.Fields)
770
771 case *ast.FuncType:
772 st.fieldTypes(e.TypeParams)
773 st.fieldTypes(e.Params)
774 st.fieldTypes(e.Results)
775
776 case *ast.InterfaceType:
777 st.fieldTypes(e.Methods)
778
779 case *ast.MapType:
780 _ = st.expr(e.Key)
781 _ = st.expr(e.Value)
782
783 case *ast.ChanType:
784 _ = st.expr(e.Value)
785 }
786 return
787 }
788
789
790
791
792 func (st *falconState) toExpr(x any) ast.Expr {
793 switch x := x.(type) {
794 case nil:
795 return nil
796
797 case types.TypeAndValue:
798 lit := makeLiteral(x.Value)
799 if !isBasic(x.Type, types.IsUntyped) {
800
801 lit = &ast.CallExpr{
802 Fun: makeIdent(st.typename(x.Type)),
803 Args: []ast.Expr{lit},
804 }
805 }
806 return lit
807
808 case ast.Expr:
809 return x
810
811 default:
812 panic(x)
813 }
814 }
815
816 func makeLiteral(v constant.Value) ast.Expr {
817 switch v.Kind() {
818 case constant.Bool:
819
820
821
822 op := token.EQL
823 if !constant.BoolVal(v) {
824 op = token.NEQ
825 }
826 return &ast.BinaryExpr{
827 Op: op,
828 X: makeIntLit(0),
829 Y: makeIntLit(0),
830 }
831
832 case constant.String:
833 return &ast.BasicLit{
834 Kind: token.STRING,
835 Value: v.ExactString(),
836 }
837
838 case constant.Int:
839 return &ast.BasicLit{
840 Kind: token.INT,
841 Value: v.ExactString(),
842 }
843
844 case constant.Float:
845 return &ast.BasicLit{
846 Kind: token.FLOAT,
847 Value: v.ExactString(),
848 }
849
850 case constant.Complex:
851
852 y := makeLiteral(constant.Imag(v))
853 y.(*ast.BasicLit).Value += "i"
854 if re := constant.Real(v); !consteq(re, kZeroInt) {
855
856 y = &ast.BinaryExpr{
857 Op: token.ADD,
858 X: makeLiteral(re),
859 Y: y,
860 }
861 }
862 return y
863
864 default:
865 panic(v.Kind())
866 }
867 }
868
869 func makeIntLit(x int64) *ast.BasicLit {
870 return &ast.BasicLit{
871 Kind: token.INT,
872 Value: strconv.FormatInt(x, 10),
873 }
874 }
875
876 func isBasic(t types.Type, info types.BasicInfo) bool {
877 basic, ok := t.Underlying().(*types.Basic)
878 return ok && basic.Info()&info != 0
879 }
880
View as plain text