github.com/goplus/gop@v1.2.6/cl/recorder.go (about)

     1  /*
     2   * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cl
    18  
    19  import (
    20  	"go/types"
    21  	"strings"
    22  
    23  	"github.com/goplus/gogen"
    24  	"github.com/goplus/gop/ast"
    25  	"github.com/goplus/gop/ast/fromgo"
    26  	"github.com/goplus/gop/cl/internal/typesutil"
    27  	"github.com/goplus/gop/token"
    28  )
    29  
    30  type goxRecorder struct {
    31  	Recorder
    32  	types  map[ast.Expr]types.TypeAndValue
    33  	refers map[string][]*ast.Ident
    34  }
    35  
    36  func newRecorder(rec Recorder) *goxRecorder {
    37  	types := make(map[ast.Expr]types.TypeAndValue)
    38  	refers := make(map[string][]*ast.Ident)
    39  	return &goxRecorder{rec, types, refers}
    40  }
    41  
    42  // Refer maps identifiers to name for ast.OverloadFuncDecl.
    43  func (p *goxRecorder) Refer(ident *ast.Ident, name string) {
    44  	p.refers[name] = append(p.refers[name], ident)
    45  }
    46  
    47  // Complete computes the types record.
    48  func (p *goxRecorder) Complete(scope *types.Scope) {
    49  	for name, idents := range p.refers {
    50  		pos := strings.Index(name, ".")
    51  		if pos == -1 {
    52  			if obj := scope.Lookup(name); obj != nil {
    53  				for _, id := range idents {
    54  					p.Use(id, obj)
    55  				}
    56  			}
    57  			continue
    58  		}
    59  		if obj := scope.Lookup(name[:pos]); obj != nil {
    60  			if named, ok := obj.Type().(*types.Named); ok {
    61  				n := named.NumMethods()
    62  				for i := 0; i < n; i++ {
    63  					if m := named.Method(i); m.Name() == name[pos+1:] {
    64  						for _, id := range idents {
    65  							p.Use(id, m)
    66  						}
    67  						break
    68  					}
    69  				}
    70  			}
    71  		}
    72  	}
    73  	p.types = nil
    74  	p.refers = nil
    75  }
    76  
    77  // Member maps identifiers to the objects they denote.
    78  func (p *goxRecorder) Member(id ast.Node, obj types.Object) {
    79  	switch v := id.(type) {
    80  	case *ast.SelectorExpr:
    81  		sel := v.Sel
    82  		// TODO: record event for a Go ident
    83  		if _, ok := fromgo.CheckIdent(sel); !ok {
    84  			var tv types.TypeAndValue
    85  			// check v.X call result by value
    86  			if f, ok := obj.(*types.Var); ok && f.IsField() && p.checkExprByValue(v.X) {
    87  				tv = typesutil.NewTypeAndValueForValue(obj.Type(), nil, typesutil.Value)
    88  			} else {
    89  				tv = typesutil.NewTypeAndValueForObject(obj)
    90  			}
    91  			p.Use(sel, obj)
    92  			p.Type(v, tv)
    93  		}
    94  	case *ast.Ident: // it's in a classfile and impossible converted from Go
    95  		p.Use(v, obj)
    96  		p.Type(v, typesutil.NewTypeAndValueForObject(obj))
    97  	}
    98  }
    99  
   100  func (p *goxRecorder) Call(id ast.Node, obj types.Object) {
   101  	switch v := id.(type) {
   102  	case *ast.Ident:
   103  		p.Use(v, obj)
   104  		p.Type(v, typesutil.NewTypeAndValueForObject(obj))
   105  	case *ast.SelectorExpr:
   106  		p.Use(v.Sel, obj)
   107  		p.Type(v, typesutil.NewTypeAndValueForObject(obj))
   108  	case *ast.CallExpr:
   109  		switch id := v.Fun.(type) {
   110  		case *ast.Ident:
   111  			p.Use(id, obj)
   112  		case *ast.SelectorExpr:
   113  			p.Use(id.Sel, obj)
   114  		}
   115  		p.Type(v.Fun, typesutil.NewTypeAndValueForObject(obj))
   116  	}
   117  }
   118  
   119  func (rec *goxRecorder) checkExprByValue(v ast.Expr) bool {
   120  	if tv, ok := rec.types[v]; ok {
   121  		switch v.(type) {
   122  		case *ast.CallExpr:
   123  			if _, ok := tv.Type.(*types.Pointer); !ok {
   124  				return true
   125  			}
   126  		default:
   127  			if tv, ok := rec.types[v]; ok {
   128  				return !tv.Addressable()
   129  			}
   130  		}
   131  	}
   132  	return false
   133  }
   134  
   135  func (rec *goxRecorder) Type(expr ast.Expr, tv types.TypeAndValue) {
   136  	rec.types[expr] = tv
   137  	rec.Recorder.Type(expr, tv)
   138  }
   139  
   140  func (rec *goxRecorder) instantiate(expr ast.Expr, _, typ types.Type) {
   141  	// check gox TyOverloadNamed
   142  	if tv, ok := rec.types[expr]; ok {
   143  		tv.Type = typ
   144  		rec.Recorder.Type(expr, tv)
   145  	}
   146  	var ident *ast.Ident
   147  	switch id := expr.(type) {
   148  	case *ast.Ident:
   149  		ident = id
   150  	case *ast.SelectorExpr:
   151  		ident = id.Sel
   152  	}
   153  	if ident != nil {
   154  		if named, ok := typ.(*types.Named); ok {
   155  			rec.Use(ident, named.Obj())
   156  		}
   157  	}
   158  }
   159  
   160  func (rec *goxRecorder) recordTypeValue(ctx *blockCtx, expr ast.Expr, mode typesutil.OperandMode) {
   161  	e := ctx.cb.Get(-1)
   162  	t, _ := gogen.DerefType(e.Type)
   163  	rec.Type(expr, typesutil.NewTypeAndValueForValue(t, e.CVal, mode))
   164  }
   165  
   166  func (rec *goxRecorder) indexExpr(ctx *blockCtx, expr *ast.IndexExpr) {
   167  	if tv, ok := rec.types[expr.X]; ok {
   168  		switch tv.Type.(type) {
   169  		case *types.Map:
   170  			rec.recordTypeValue(ctx, expr, typesutil.MapIndex)
   171  			return
   172  		case *types.Slice:
   173  			rec.recordTypeValue(ctx, expr, typesutil.Variable)
   174  			return
   175  		}
   176  	}
   177  	op := typesutil.Variable
   178  	switch e := expr.X.(type) {
   179  	case *ast.CompositeLit:
   180  		op = typesutil.Value
   181  	case *ast.SelectorExpr:
   182  		if rec.checkExprByValue(e.X) {
   183  			op = typesutil.Value
   184  		}
   185  	}
   186  	rec.recordTypeValue(ctx, expr, op)
   187  }
   188  
   189  func (rec *goxRecorder) unaryExpr(ctx *blockCtx, expr *ast.UnaryExpr) {
   190  	switch expr.Op {
   191  	case token.ARROW:
   192  		rec.recordTypeValue(ctx, expr, typesutil.CommaOK)
   193  	default:
   194  		rec.recordTypeValue(ctx, expr, typesutil.Value)
   195  	}
   196  }
   197  
   198  func (rec *goxRecorder) recordCallExpr(ctx *blockCtx, v *ast.CallExpr, fnt types.Type) {
   199  	e := ctx.cb.Get(-1)
   200  	if _, ok := rec.types[v.Fun]; !ok {
   201  		rec.Type(v.Fun, typesutil.NewTypeAndValueForValue(fnt, nil, typesutil.Value))
   202  	}
   203  	rec.Type(v, typesutil.NewTypeAndValueForCallResult(e.Type, e.CVal))
   204  }
   205  
   206  func (rec *goxRecorder) recordCompositeLit(v *ast.CompositeLit, typ types.Type) {
   207  	rec.Type(v.Type, typesutil.NewTypeAndValueForType(typ))
   208  	rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil, typesutil.Value))
   209  }
   210  
   211  func (rec *goxRecorder) recordFuncLit(v *ast.FuncLit, typ types.Type) {
   212  	rec.Type(v.Type, typesutil.NewTypeAndValueForType(typ))
   213  	rec.Type(v, typesutil.NewTypeAndValueForValue(typ, nil, typesutil.Value))
   214  }
   215  
   216  func (rec *goxRecorder) recordType(typ ast.Expr, t types.Type) {
   217  	rec.Type(typ, typesutil.NewTypeAndValueForType(t))
   218  }
   219  
   220  func (rec *goxRecorder) recordIdent(ident *ast.Ident, obj types.Object) {
   221  	rec.Use(ident, obj)
   222  	rec.Type(ident, typesutil.NewTypeAndValueForObject(obj))
   223  }
   224  
   225  func (rec *goxRecorder) recordExpr(ctx *blockCtx, expr ast.Expr, _ bool) {
   226  	switch v := expr.(type) {
   227  	case *ast.Ident:
   228  	case *ast.BasicLit:
   229  		rec.recordTypeValue(ctx, v, typesutil.Value)
   230  	case *ast.CallExpr:
   231  	case *ast.SelectorExpr:
   232  		if _, ok := rec.types[v]; !ok {
   233  			rec.recordTypeValue(ctx, v, typesutil.Variable)
   234  		}
   235  	case *ast.BinaryExpr:
   236  		rec.recordTypeValue(ctx, v, typesutil.Value)
   237  	case *ast.UnaryExpr:
   238  		rec.unaryExpr(ctx, v)
   239  	case *ast.FuncLit:
   240  	case *ast.CompositeLit:
   241  	case *ast.SliceLit:
   242  	case *ast.RangeExpr:
   243  	case *ast.IndexExpr:
   244  		rec.indexExpr(ctx, v)
   245  	case *ast.IndexListExpr:
   246  	case *ast.SliceExpr:
   247  		rec.recordTypeValue(ctx, v, typesutil.Value)
   248  	case *ast.StarExpr:
   249  		rec.recordTypeValue(ctx, v, typesutil.Variable)
   250  	case *ast.ArrayType:
   251  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   252  	case *ast.MapType:
   253  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   254  	case *ast.StructType:
   255  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   256  	case *ast.ChanType:
   257  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   258  	case *ast.InterfaceType:
   259  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   260  	case *ast.ComprehensionExpr:
   261  	case *ast.TypeAssertExpr:
   262  		rec.recordTypeValue(ctx, v, typesutil.CommaOK)
   263  	case *ast.ParenExpr:
   264  		rec.recordTypeValue(ctx, v, typesutil.Value)
   265  	case *ast.ErrWrapExpr:
   266  	case *ast.FuncType:
   267  		rec.recordTypeValue(ctx, v, typesutil.TypExpr)
   268  	case *ast.Ellipsis:
   269  	case *ast.KeyValueExpr:
   270  	default:
   271  	}
   272  }