github.com/goplus/gop@v1.2.6/ast/scope.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  // This file implements scopes and the objects they contain.
    18  
    19  package ast
    20  
    21  import (
    22  	"bytes"
    23  	"fmt"
    24  
    25  	"github.com/goplus/gop/token"
    26  )
    27  
    28  // A Scope maintains the set of named language entities declared
    29  // in the scope and a link to the immediately surrounding (outer)
    30  // scope.
    31  type Scope struct {
    32  	Outer   *Scope
    33  	Objects map[string]*Object
    34  }
    35  
    36  // NewScope creates a new scope nested in the outer scope.
    37  func NewScope(outer *Scope) *Scope {
    38  	const n = 4 // initial scope capacity
    39  	return &Scope{outer, make(map[string]*Object, n)}
    40  }
    41  
    42  // Lookup returns the object with the given name if it is
    43  // found in scope s, otherwise it returns nil. Outer scopes
    44  // are ignored.
    45  func (s *Scope) Lookup(name string) *Object {
    46  	return s.Objects[name]
    47  }
    48  
    49  // Insert attempts to insert a named object obj into the scope s.
    50  // If the scope already contains an object alt with the same name,
    51  // Insert leaves the scope unchanged and returns alt. Otherwise
    52  // it inserts obj and returns nil.
    53  func (s *Scope) Insert(obj *Object) (alt *Object) {
    54  	if alt = s.Objects[obj.Name]; alt == nil {
    55  		s.Objects[obj.Name] = obj
    56  	}
    57  	return
    58  }
    59  
    60  // Debugging support
    61  func (s *Scope) String() string {
    62  	var buf bytes.Buffer
    63  	fmt.Fprintf(&buf, "scope %p {", s)
    64  	if s != nil && len(s.Objects) > 0 {
    65  		fmt.Fprintln(&buf)
    66  		for _, obj := range s.Objects {
    67  			fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
    68  		}
    69  	}
    70  	fmt.Fprintf(&buf, "}\n")
    71  	return buf.String()
    72  }
    73  
    74  // ----------------------------------------------------------------------------
    75  // Objects
    76  
    77  // An Object describes a named language entity such as a package,
    78  // constant, type, variable, function (incl. methods), or label.
    79  //
    80  // The Data fields contains object-specific data:
    81  //
    82  //	Kind    Data type         Data value
    83  //	Pkg     *Scope            package scope
    84  //	Con     int               iota for the respective declaration
    85  type Object struct {
    86  	Kind ObjKind
    87  	Name string      // declared name
    88  	Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
    89  	Data interface{} // object-specific data; or nil
    90  	Type interface{} // placeholder for type information; may be nil
    91  }
    92  
    93  // NewObj creates a new object of a given kind and name.
    94  func NewObj(kind ObjKind, name string) *Object {
    95  	return &Object{Kind: kind, Name: name}
    96  }
    97  
    98  // Pos computes the source position of the declaration of an object name.
    99  // The result may be an invalid position if it cannot be computed
   100  // (obj.Decl may be nil or not correct).
   101  func (obj *Object) Pos() token.Pos {
   102  	name := obj.Name
   103  	switch d := obj.Decl.(type) {
   104  	case *Field:
   105  		for _, n := range d.Names {
   106  			if n.Name == name {
   107  				return n.Pos()
   108  			}
   109  		}
   110  	case *ImportSpec:
   111  		if d.Name != nil && d.Name.Name == name {
   112  			return d.Name.Pos()
   113  		}
   114  		return d.Path.Pos()
   115  	case *ValueSpec:
   116  		for _, n := range d.Names {
   117  			if n.Name == name {
   118  				return n.Pos()
   119  			}
   120  		}
   121  	case *TypeSpec:
   122  		if d.Name.Name == name {
   123  			return d.Name.Pos()
   124  		}
   125  	case *FuncDecl:
   126  		if d.Name.Name == name {
   127  			return d.Name.Pos()
   128  		}
   129  	case *LabeledStmt:
   130  		if d.Label.Name == name {
   131  			return d.Label.Pos()
   132  		}
   133  	case *AssignStmt:
   134  		for _, x := range d.Lhs {
   135  			if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
   136  				return ident.Pos()
   137  			}
   138  		}
   139  	case *Scope:
   140  		// predeclared object - nothing to do for now
   141  	}
   142  	return token.NoPos
   143  }
   144  
   145  // ObjKind describes what an object represents.
   146  type ObjKind int
   147  
   148  // The list of possible Object kinds.
   149  const (
   150  	Bad ObjKind = iota // for error handling
   151  	Pkg                // package
   152  	Con                // constant
   153  	Typ                // type
   154  	Var                // variable
   155  	Fun                // function or method
   156  	Lbl                // label
   157  )
   158  
   159  var objKindStrings = [...]string{
   160  	Bad: "bad",
   161  	Pkg: "package",
   162  	Con: "const",
   163  	Typ: "type",
   164  	Var: "var",
   165  	Fun: "func",
   166  	Lbl: "label",
   167  }
   168  
   169  func (kind ObjKind) String() string { return objKindStrings[kind] }