package types import ( "git.smesh.lol/moxie/pkg/syntax" ) // TCTypeAndValue records the type and optional constant value for an expression. type TCTypeAndValue struct { Type Type Value ConstVal // nil for non-constant expressions mode exprMode } type exprMode uint8 const ( modeInvalid exprMode = iota modeVoid // no value (statement context) modeValue // an addressable or non-addressable value modeVar // addressable variable modeConst // constant expression modeType // a type expression modeBuiltin // a builtin identifier modePkg // a package name modeNil // the predeclared nil ) func (tv *TCTypeAndValue) IsValue() (ok bool) { return tv.mode == modeValue || tv.mode == modeVar || tv.mode == modeConst || tv.mode == modeNil } func (tv *TCTypeAndValue) IsType() (ok bool) { return tv.mode == modeType } func (tv *TCTypeAndValue) IsBuiltin() (ok bool) { return tv.mode == modeBuiltin } func (tv *TCTypeAndValue) IsConst() (ok bool) { return tv.mode == modeConst } func (tv *TCTypeAndValue) Addressable() (ok bool) { return tv.mode == modeVar } // Info holds the result of type-checking a set of Files. // Consumers access type info for each expression and identifier. type Info struct { // Types maps each expression to its type and value. Types map[syntax.Expr]TCTypeAndValue // Defs maps each identifier that declares something to the object it declares. Defs map[*syntax.Name]Object // Uses maps each identifier that is used (not declared) to the object it denotes. Uses map[*syntax.Name]Object // Implicits maps nodes to the object they implicitly declare. Implicits map[syntax.Node]Object // Scopes maps AST nodes to the scope they open. Scopes map[syntax.Node]*Scope // Selections maps selector expressions X.f to the selection. Selections map[*syntax.SelectorExpr]*Selection } // Selection describes a field or method selection X.f. type Selection struct { Kind SelectionKind Recv Type // type of X Obj Object // selected field or method Index []int32 // path of field indices (for embedded fields) Indir bool // true if recv contains a pointer indirection } type SelectionKind int32 const ( FieldVal SelectionKind = iota MethodVal MethodExpr ) func (s *Selection) Indirect() (ok bool) { return s.Indir } func (s *Selection) SelType() (t Type) { switch s.Kind { case FieldVal: return ObjectType(s.Obj) case MethodVal: sig := s.Obj.(*TCFunc).Signature() // bound method: drop the receiver parameter return NewSignature(nil, sig.Params, sig.Results, sig.Variadic) case MethodExpr: // unbound: receiver becomes first parameter return s.Obj.(*TCFunc).Signature() } return nil } func newInfo() (i *Info) { return &Info{ Types: map[syntax.Expr]TCTypeAndValue{}, Defs: map[*syntax.Name]Object{}, Uses: map[*syntax.Name]Object{}, Implicits: map[syntax.Node]Object{}, Scopes: map[syntax.Node]*Scope{}, Selections: map[*syntax.SelectorExpr]*Selection{}, } } func (info *Info) Release() { info.Types = nil info.Defs = nil info.Uses = nil info.Implicits = nil info.Scopes = nil info.Selections = nil } func (info *Info) TypeOf(e syntax.Expr) (t Type) { if tv, ok := info.Types[e]; ok { return tv.Type } return nil } // ObjectOf returns the object denoted by identifier id, or nil. func (info *Info) ObjectOf(id *syntax.Name) (o Object) { if obj, ok := info.Defs[id]; ok { return obj } return info.Uses[id] }