github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/go/parser/package.go (about)

     1  /* For license and copyright information please see the LEGAL file in the code repository */
     2  
     3  package parser
     4  
     5  import (
     6  	"go/ast"
     7  	"go/parser"
     8  	"go/token"
     9  	"path"
    10  	"strings"
    11  )
    12  
    13  // Package :
    14  type Package struct {
    15  	Name         string
    16  	DependencyID [16]byte             //
    17  	FSPath       string               // Folder location in FileSystems
    18  	Files        map[string]*File     // Name
    19  	Imports      map[string]*Import   // UsageName
    20  	Functions    map[string]*Function // Name
    21  	Types        map[string]*Type     // Name
    22  	Dependencies map[string]*Package  // Name
    23  }
    24  
    25  // Init initialize the object.
    26  func (p *Package) Init() {
    27  	p.Files = make(map[string]*File)
    28  	p.Imports = make(map[string]*Import)
    29  	p.Functions = make(map[string]*Function)
    30  	p.Types = make(map[string]*Type)
    31  	p.Dependencies = make(map[string]*Package)
    32  }
    33  
    34  // AddFile use to add file to Package
    35  func (p *Package) AddFile(f *File) {
    36  	p.Files[f.Name] = f
    37  }
    38  
    39  // Parse use to add new file & parsed FileData and add to repo object!
    40  func (p *Package) Parse(FileName string, FileData []byte) (err error) {
    41  	// Parsed FileData
    42  	var (
    43  		file    = File{Name: FileName, Data: FileData}
    44  		fileSet = token.NewFileSet()
    45  	)
    46  	p.Files[FileName] = &file
    47  
    48  	// Just parsed needed file!
    49  	if strings.HasSuffix(FileName, ".go") ||
    50  		!strings.HasSuffix(FileName, "_test.go") {
    51  
    52  		file.Parsed, err = parser.ParseFile(fileSet, "", FileData, parser.ParseComments)
    53  		if err != nil {
    54  			return
    55  		}
    56  
    57  		// Set package name
    58  		p.Name = file.Parsed.Name.Name
    59  
    60  		err = p.parseFile(&file)
    61  		if err != nil {
    62  			return
    63  		}
    64  	}
    65  
    66  	return nil
    67  }
    68  
    69  func (p *Package) parseFile(file *File) (err error) {
    70  	for _, imp := range file.Parsed.Imports {
    71  		var impor = Import{
    72  			FSPath:     imp.Path.Value[1 : len(imp.Path.Value)-1],
    73  			ImportSpec: imp,
    74  		}
    75  		if imp.Name != nil {
    76  			impor.UsageName = imp.Name.Name
    77  			impor.PackageName = path.Base(imp.Path.Value[1 : len(imp.Path.Value)-1])
    78  		} else {
    79  			impor.UsageName = path.Base(imp.Path.Value[1 : len(imp.Path.Value)-1])
    80  			impor.PackageName = path.Base(imp.Path.Value[1 : len(imp.Path.Value)-1])
    81  		}
    82  
    83  		p.Imports[impor.UsageName] = &impor
    84  	}
    85  
    86  	for _, decl := range file.Parsed.Decls {
    87  		switch d := decl.(type) {
    88  		case *ast.GenDecl:
    89  			for _, gDecl := range d.Specs {
    90  				switch gd := gDecl.(type) {
    91  				case *ast.ImportSpec:
    92  					// Check this before in file.Parsed.Imports!!!! WHY go WHY!!!? duplicate data!!!???
    93  				case *ast.ValueSpec:
    94  					// Don't need this so far!
    95  				case *ast.TypeSpec:
    96  					t := p.parseType(gd.Type)
    97  					t.Name = gd.Name.Name
    98  					t.Exported = gd.Name.IsExported()
    99  					t.File = file
   100  
   101  					p.Types[t.Name] = &t
   102  				}
   103  			}
   104  
   105  		case *ast.FuncDecl:
   106  			// Just exported function use in chaparkhane generation!
   107  			if !d.Name.IsExported() {
   108  				continue
   109  			}
   110  
   111  			function := Function{
   112  				Name: d.Name.Name,
   113  				File: file,
   114  				Decl: d,
   115  			}
   116  
   117  			if d.Type != nil && d.Type.Params != nil {
   118  				if len(d.Type.Params.List) != 2 {
   119  					continue
   120  				}
   121  				fp := p.parseType(d.Type.Params.List[0].Type)
   122  				fp.Name = d.Type.Params.List[0].Names[0].Name
   123  				fp.Exported = d.Type.Params.List[0].Names[0].IsExported()
   124  				fp.File = file
   125  				function.Parameter = &fp
   126  			}
   127  
   128  			if d.Type != nil && d.Type.Results != nil {
   129  				if len(d.Type.Params.List) > 2 {
   130  					continue
   131  				}
   132  
   133  				for _, rField := range d.Type.Results.List {
   134  					for _, name := range rField.Names {
   135  						fr := p.parseType(rField.Type)
   136  						fr.Name = name.Name
   137  						fr.Exported = name.IsExported()
   138  						fr.File = file
   139  						if fr.Type == "error" {
   140  							function.Err = &fr
   141  						} else {
   142  							function.Result = &fr
   143  						}
   144  					}
   145  				}
   146  			}
   147  
   148  			p.Functions[function.Name] = &function
   149  		}
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func (p *Package) parseType(expr ast.Expr) (ft Type) {
   156  	switch v := expr.(type) {
   157  	case *ast.StarExpr:
   158  		ft = p.parseType(v.X)
   159  		ft.Pointer = true
   160  	case *ast.SelectorExpr:
   161  		if imp, ok := p.Imports[v.X.(*ast.Ident).Name]; ok {
   162  			ft.Package = imp
   163  		}
   164  		ft.Type = v.Sel.Name
   165  	case *ast.ArrayType:
   166  		//ft.Type = "[" + repo.parseType(v.Len).Type + "]" + repo.parseType(v.Elt).Type
   167  	case *ast.MapType:
   168  		//"map[" + parseType(v.Key) + "]" + parseType(v.Value)
   169  	case *ast.InterfaceType:
   170  		//"interface{}"
   171  		// interface type forbidden
   172  	case *ast.Ident:
   173  		if v.Obj != nil {
   174  			switch obj := v.Obj.Decl.(type) {
   175  			case *ast.TypeSpec:
   176  				innerFT := p.parseType(obj.Type)
   177  				for _, each := range innerFT.InnerType {
   178  					ft.InnerType = append(ft.InnerType, each)
   179  				}
   180  			}
   181  		}
   182  		ft.Type = v.Name
   183  	case *ast.StructType:
   184  		for _, field := range v.Fields.List {
   185  			if field.Names == nil {
   186  				// embedded struct forbidden
   187  			}
   188  			for _, innerField := range field.Names {
   189  				innerFT := p.parseType(field.Type)
   190  				innerFT.Name = innerField.Name
   191  				innerFT.ID = len(ft.InnerType)
   192  				ft.InnerType = append(ft.InnerType, &innerFT)
   193  			}
   194  		}
   195  	case *ast.BasicLit:
   196  		// embedded basic type forbidden
   197  		// type test struct {
   198  		// 	 string
   199  		// }
   200  	}
   201  
   202  	return ft
   203  }