Пример #1
0
func (pp *packageParser) tParseFuncType(t *ast.FuncType) (result *st.FunctionTypeSymbol) {
	res := st.MakeFunctionType(st.NO_NAME, pp.CurrentSymbolTable)
	if t.Params != nil {
		e_count := 0
		for _, field := range t.Params.List {
			ftype := pp.parseTypeSymbol(field.Type)
			if len(field.Names) == 0 { // unnamed parameter. separate names are given to distinct parameters in symbolTable
				res.Parameters.AddSymbol(st.MakeVariable("$unnamed"+strconv.Itoa(e_count), pp.CurrentSymbolTable, ftype))
				e_count += 1
			}
			for _, name := range field.Names {

				toAdd := st.MakeVariable(name.Name, res.Parameters, ftype)
				pp.registerIdent(toAdd, name)
				res.Parameters.AddSymbol(toAdd)
			}
		}
	}
	if t.Results != nil {
		e_count := 0
		for _, field := range t.Results.List {
			ftype := pp.parseTypeSymbol(field.Type)
			if len(field.Names) == 0 { //unnamed result
				res.Results.AddSymbol(st.MakeVariable("$unnamed"+strconv.Itoa(e_count), pp.CurrentSymbolTable, ftype))
				e_count += 1
			}
			for _, name := range field.Names {

				toAdd := st.MakeVariable(name.Name, res.Results, ftype)
				pp.registerIdent(toAdd, name)
				res.Results.AddSymbol(toAdd)
			}
		}
	}
	result = res
	return
}
Пример #2
0
func (pp *packageParser) tParseStructType(t *ast.StructType) (result *st.StructTypeSymbol) {

	res := st.MakeStructType(st.NO_NAME, pp.CurrentSymbolTable)
	for _, field := range t.Fields.List {
		ftype := pp.parseTypeSymbol(field.Type)
		if len(field.Names) == 0 { //Embedded field
			res.Fields.AddSymbol(ftype)
		}
		for _, name := range field.Names {

			toAdd := st.MakeVariable(name.Name, res.Fields, ftype)
			pp.registerIdent(toAdd, name)
			res.Fields.AddSymbol(toAdd)

		}
	}
	result = res
	return
}
Пример #3
0
func (pp *packageParser) openMethodsAndFields(sym st.Symbol) {

	if pp.checkIsVisited(sym) {
		return
	}
	// 	fmt.Printf("opening %s %T from %s\n", sym.Name(), sym, func(p *st.Package) string {
	// 		if p == nil {
	// 			return "nil"
	// 		}
	// 		return p.AstPackage.Name
	// 	}(sym.PackageFrom()))

	if st.IsPredeclaredIdentifier(sym.Name()) {
		return
	}

	switch t := sym.(type) {
	case *st.ArrayTypeSymbol:
		pp.openMethodsAndFields(t.ElemType)
	case *st.ChanTypeSymbol:
		pp.openMethodsAndFields(t.ValueType)
	case *st.FunctionTypeSymbol:
		if t.Parameters != nil {
			t.Parameters.ForEachNoLock(func(sym st.Symbol) {
				v := sym.(*st.VariableSymbol)
				pp.openMethodsAndFields(v.VariableType)
			})
		}
		if t.Results != nil {
			t.Results.ForEachNoLock(func(sym st.Symbol) {
				v := sym.(*st.VariableSymbol)
				pp.openMethodsAndFields(v.VariableType)
			})
		}
	case *st.InterfaceTypeSymbol:
		if t.Meths != nil {
			t.Meths.ForEachNoLock(func(sym st.Symbol) {
				if _, ok := sym.(*st.FunctionSymbol); !ok {
					//EmbeddedInterface
					pp.openMethodsAndFields(sym)

					ts := sym.(*st.InterfaceTypeSymbol)
					t.Meths.AddOpenedScope(ts.Meths)
					//Delete functionSymbol which is now useles from interface
					t.Meths.RemoveSymbol(sym.Name())
				}
			})
		}
	case *st.MapTypeSymbol:
		pp.openMethodsAndFields(t.KeyType)
		pp.openMethodsAndFields(t.ValueType)
	case *st.StructTypeSymbol:
		// 		if t.Name() == "Package" {
		// 			fmt.Printf("YEAHHH YEAHHH %p\n", t)
		// 		}
		t.Fields.ForEachNoLock(func(variable st.Symbol) {
			if _, ok := variable.(*st.VariableSymbol); !ok {

				ts := variable.(st.ITypeSymbol)
				pp.openMethodsAndFields(ts)
				//Methods
				if ts.Methods() != nil {
					t.Methods().AddOpenedScope(ts.Methods())
				}
				//Fields
				switch ttt := ts.(type) {
				case *st.StructTypeSymbol:
					t.Fields.AddOpenedScope(ttt.Fields)
				case *st.PointerTypeSymbol:
					t.Fields.AddOpenedScope(ttt.Fields)

				}
				//No longer need in type thumb, replace with var
				typeVar := st.MakeVariable(ts.Name(), t.Fields, ts)
				typeVar.Idents = ts.Identifiers()
				typeVar.Posits = ts.Positions()
				t.Fields.ReplaceSymbol(ts.Name(), typeVar) //replaces old one
			}

		})
	case *st.PointerTypeSymbol:
		//fmt.Printf("%v %T \n", t.BaseType.Name(), t.BaseType)
		pp.openMethodsAndFields(t.BaseType)
		switch str := t.BaseType.(type) {
		case *st.StructTypeSymbol:
			t.Fields = str.Fields
		case *st.PointerTypeSymbol:
			t.Fields = str.Fields
		}

		if _, cyc := st.GetBaseType(t); cyc {
			// 			fmt.Printf("%s from %s\n", t.Name(), t.PackageFrom().AstPackage.Name)
			panic("cycle, don't work with that")
		}

		if t.BaseType.Methods() != nil {
			t.Methods().AddOpenedScope(t.BaseType.Methods())
		}
		// 		if t.BaseType.Name() == "Package" {
		// 			fmt.Printf("YEAHHH YEAHHH %p %p\n", t, t.BaseType)
		// 			fmt.Println(*t.Methods().String());
		// 		}
		pp.openMethodsAndFields(t.BaseType)
	}
}
Пример #4
0
func (mv *methodsVisitor) Visit(node ast.Node) (w ast.Visitor) {
	w = mv
	switch f := node.(type) {
	case *ast.FuncDecl:

		fft, cyc := st.GetBaseType(mv.Parser.parseTypeSymbol(f.Type))
		if cyc {
			panic("unexpected cycle")
		}
		ft := fft.(*st.FunctionTypeSymbol)
		locals := st.NewSymbolTable(mv.Parser.Package)

		locals.AddOpenedScope(ft.Parameters)
		locals.AddOpenedScope(ft.Results)
		locals.AddOpenedScope(ft.Reciever)

		var basertype, rtype st.ITypeSymbol
		if f.Recv != nil {

			e_count := 0
			for _, field := range f.Recv.List {
				basertype = mv.Parser.parseTypeSymbol(field.Type)
				if prtype, ok := basertype.(*st.PointerTypeSymbol); ok {
					rtype = prtype.BaseType
				} else {
					rtype = basertype
				}

				if mv.Parser.Package.AstPackage.Name == "os" {
					// 					fmt.Printf("###@@@### (%s) %s\n", rtype.Name(), f.Name.Name)
				}
				if rtype.Methods() == nil {
					panic("ok, this is a test panic")
					rtype.SetMethods(st.NewSymbolTable(mv.Parser.Package))
				}

				if len(field.Names) == 0 {
					toAdd := st.MakeVariable("$unnamed receiver"+strconv.Itoa(e_count), ft.Reciever, basertype)
					ft.Reciever.AddSymbol(toAdd)
					e_count += 1
				}

				for _, name := range field.Names {

					toAdd := st.MakeVariable(name.Name, ft.Reciever, basertype)
					mv.Parser.registerIdent(toAdd, name)
					ft.Reciever.AddSymbol(toAdd)
				}
			}
		}

		toAdd := st.MakeFunction(f.Name.Name, nil, ft) // Scope is set 5 lines down
		toAdd.Locals = locals

		mv.Parser.registerIdent(toAdd, f.Name)

		if f.Recv != nil {
			rtype.AddMethod(toAdd)
			toAdd.Scope_ = rtype.Methods()
		} else {
			mv.Parser.RootSymbolTable.AddSymbol(toAdd)
			toAdd.Scope_ = mv.Parser.RootSymbolTable
		}
	}
	return
}
Пример #5
0
func implementInterface(programTree *program.Program, filename string, line int, column int, varFile string, varLine int, varColumn int, asPointer bool) (bool, *errors.GoRefactorError) {
	if ok, err := CheckImplementInterfaceParameters(filename, line, column, varFile, varLine, varColumn); !ok {
		return false, err
	}
	packInt, _ := programTree.FindPackageAndFileByFilename(filename)
	if packInt == nil {
		return false, errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'")
	}
	packType, fileType := programTree.FindPackageAndFileByFilename(varFile)
	if packType == nil {
		return false, errors.ArgumentError("filename", "Program packages don't contain file '"+varFile+"'")
	}
	symInt, err := programTree.FindSymbolByPosition(filename, line, column)
	if err != nil {
		return false, err
	}
	symType, err := programTree.FindSymbolByPosition(varFile, varLine, varColumn)
	if err != nil {
		return false, err
	}

	sI, ok := symInt.(*st.InterfaceTypeSymbol)
	if !ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "symbol, pointed as interface, is actually not a one"}
	}
	if _, ok := symType.(*st.InterfaceTypeSymbol); ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "interface can't implement methods"}
	}
	sT, ok := symType.(st.ITypeSymbol)
	if !ok {
		return false, &errors.GoRefactorError{ErrorType: "implement interface error", Message: "interface can be implemented only by a type"}
	}
	if asPointer {
		sT = programTree.GetPointerType(sT)
	}

	errors := make([]*errors.GoRefactorError, 0, 10)
	missedMethods := make(map[*st.FunctionSymbol]bool)
	checker := func(sym st.Symbol) {
		f := sym.(*st.FunctionSymbol)
		ok, err := containsMethod(f, sT)
		if err != nil {
			errors = append(errors, err)
		} else if !ok {
			missedMethods[f] = true
		}
	}
	sI.Methods().ForEachNoLock(checker)
	sI.Methods().ForEachOpenedScope(func(table *st.SymbolTable) {
		table.ForEachNoLock(checker)
	})

	println("missedMethods:")
	for s, _ := range missedMethods {
		list := make([]ast.Stmt, 1)
		list[0] = &ast.ExprStmt{&ast.CallExpr{ast.NewIdent("panic"), token.NoPos, []ast.Expr{&ast.BasicLit{token.NoPos, token.STRING, "\"not implemented yet\""}}, token.NoPos, token.NoPos}}
		fdecl := makeFuncDecl(s.Name(), list, s.FunctionType.(*st.FunctionTypeSymbol).Parameters, nil, s.FunctionType.(*st.FunctionTypeSymbol).Results, st.MakeVariable(st.NO_NAME, sT.Scope(), sT), packType, varFile)
		printer.Fprint(os.Stdout, token.NewFileSet(), fdecl)
		println()
		fileType.Decls = append(fileType.Decls, fdecl)
	}
	println()
	println("errors:")
	for _, err := range errors {
		println(err.String())
	}

	return true, nil
}
Пример #6
0
//ast.Visitor.Visit(). Looks for top-level ast.ValueSpec nodes of ast.Tree to register global vars
func (gv globalsVisitor) Visit(node ast.Node) ast.Visitor {

	switch t := node.(type) {
	case *ast.ValueSpec:

		ts := gv.Parser.parseTypeSymbol(t.Type)

		if ts == nil && t.Values == nil {
			ts = gv.iotaType
		}

		for i, n := range t.Names {

			// 			if gv.Parser.Package.AstPackage.Name == "unicode" {
			// 			fmt.Printf("%s:	Variable %s\n", gv.Parser.Package.AstPackage.Name, n.Name)
			// 			}
			var exprT st.ITypeSymbol

			if t.Values != nil {
				// 				fmt.Printf("%s\n",t.Values[i])
				exprT = gv.Parser.parseExpr(t.Values[i]).At(0).(st.ITypeSymbol)
				// 				if n.Name == "BothDir" {
				// 					fmt.Printf("((((( %p, %T\n", exprT, exprT)
				// 				}
			}
			if arrT, ok := ts.(*st.ArrayTypeSymbol); ok {
				if arrT.Len == st.ELLIPSIS {
					arrT.Len = exprT.(*st.ArrayTypeSymbol).Len
				}
			}
			if exprT != nil && ts == nil {
				ts = exprT
			}

			toAdd := st.MakeVariable(n.Name, gv.Parser.RootSymbolTable, ts)
			gv.Parser.registerIdent(toAdd, n)
			gv.Parser.RootSymbolTable.AddSymbol(toAdd)
		}

	case *ast.GenDecl:

		if len(t.Specs) > 0 {
			if vs, ok := t.Specs[0].(*ast.ValueSpec); ok {
				var ts st.ITypeSymbol

				ts = gv.Parser.parseTypeSymbol(vs.Type)

				if ts == nil {
					ts, _ = st.PredeclaredTypes["int"]
				}
				gv.iotaType = ts
			}
		}

	case *ast.ForStmt, *ast.FuncDecl, *ast.FuncLit, *ast.IfStmt, *ast.RangeStmt, *ast.SelectStmt, *ast.SwitchStmt, *ast.TypeSwitchStmt:
		//InnerScope, omitted
		gv.iotaType = nil
		return nil
	}
	return gv
}
Пример #7
0
func extractMethod(programTree *program.Program, filename string, lineStart int, colStart int, lineEnd int, colEnd int, methodName string, recieverVarLine int, recieverVarCol int) (bool, *errors.GoRefactorError) {

	if ok, err := CheckExtractMethodParameters(filename, lineStart, colStart, lineEnd, colEnd, methodName, recieverVarLine, recieverVarCol); !ok {
		return false, err
	}

	pack, file := programTree.FindPackageAndFileByFilename(filename)
	if pack == nil {
		return false, errors.ArgumentError("filename", "Program packages don't contain file '"+filename+"'")
	}
	fset := pack.FileSet

	recvSym, err := getRecieverSymbol(programTree, pack, filename, recieverVarLine, recieverVarCol)
	if err != nil {
		return false, err
	}

	if recvSym != nil {
		if recvSym.VariableType.Methods() != nil {
			if _, ok := recvSym.VariableType.Methods().LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a method with name "+methodName)
			}
		}
		switch t := recvSym.VariableType.(type) {
		case *st.StructTypeSymbol:
			if _, ok := t.Fields.LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a field with name "+methodName)
			}
		case *st.PointerTypeSymbol:
			if _, ok := t.Fields.LookUp(methodName, ""); ok {
				return false, errors.ArgumentError("methodName", "reciever already contains a field with name "+methodName)
			}
		}
	} else {
		if _, ok := pack.Symbols.LookUp(methodName, ""); ok {
			return false, errors.ArgumentError("methodName", "package already contains a symbol with name "+methodName)
		}
	}

	stmtList, nodeFrom, err := getExtractedStatementList(pack, file, filename, lineStart, colStart, lineEnd, colEnd)
	if err != nil {
		return false, err
	}
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())

	params, declared := getParametersAndDeclaredIn(pack, stmtList, programTree)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	if recvSym != nil {
		if _, found := params.LookUp(recvSym.Name(), ""); !found {
			return false, &errors.GoRefactorError{ErrorType: "extract method error", Message: "symbol, desired to be reciever, is not a parameter to extracted code"}
		}
		params.RemoveSymbol(recvSym.Name())
	}

	resultList := getResultList(programTree, pack, filename, stmtList)
	results := st.NewSymbolTable(pack)
	for _, r := range resultList {
		results.AddSymbol(st.MakeVariable(st.NO_NAME, results, r))
	}
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	pointerSymbols := getPointerPassedSymbols(stmtList, params, programTree.IdentMap)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	for s, depth := range pointerSymbols {
		println(s.Name(), depth)
	}

	applyPointerTransform(fset, file, stmtList, pointerSymbols, programTree.IdentMap)
	fmt.Printf("list pos,end = %d,%d\n", stmtList[0].Pos(), stmtList[len(stmtList)-1].End())
	fdecl := makeFuncDecl(methodName, stmtList, params, pointerSymbols, results, recvSym, pack, filename)

	if nodeFrom != nil {

		callExpr, callExprLen := makeCallExpr(methodName, params, pointerSymbols, stmtList[0].Pos(), recvSym, pack, filename)

		if ok, errs := checkScoping(nodeFrom, stmtList, declared, programTree.IdentMap); !ok {
			s := ""
			errs.ForEach(func(sym st.Symbol) {
				s += sym.Name() + " "
			})
			return false, &errors.GoRefactorError{ErrorType: "extract method error", Message: "extracted code declares symbols that are used in not-extracted code: " + s}
		}

		app := callExprLen - int(stmtList[len(stmtList)-1].End()-stmtList[0].Pos())
		if app > 0 {

			S, E := fset.Position(nodeFrom.Pos()), fset.Position(nodeFrom.End())
			poses, ends := make([]token.Position, len(stmtList)), make([]token.Position, len(stmtList))
			for i, stmt := range stmtList {
				poses[i], ends[i] = fset.Position(stmt.Pos()), fset.Position(stmt.End())
			}

			tfile := printerUtil.GetFileFromFileSet(fset, filename)
			baseMod := tfile.Base()
			fmt.Printf("app = %d,baseMod = %d\n", app, baseMod)
			fset, file = printerUtil.ReparseFile(file, filename, app, programTree.IdentMap)
			tfile = printerUtil.GetFileFromFileSet(fset, filename)
			lines := printerUtil.GetLines(tfile)
			tfile.SetLines(lines[:len(lines)-(app)])

			nodeFrom = printerUtil.FindNode(fset, file, S, E)
			if baseMod != 1 {
				for _, stmt := range stmtList {
					printerUtil.FixPositions(0, 1-baseMod, stmt, true)
				}
				printerUtil.FixPositions(0, 1-baseMod, callExpr, true)
				printerUtil.FixPositions(0, 1-baseMod, fdecl, true)
			}
			stmtList = make([]ast.Stmt, len(stmtList))
			for i, _ := range stmtList {
				stmtList[i] = printerUtil.FindNode(fset, file, poses[i], ends[i]).(ast.Stmt)
			}
		}

		list := getStmtList(nodeFrom)

		ind, found := getIndexOfStmt(stmtList[0], list)
		if !found {
			panic("didn't find replace origin")
		}
		fmt.Printf("stmtList length = %d\n", len(stmtList))
		if ok, err := printerUtil.DeleteNodeList(fset, filename, file, stmtList); !ok {
			return false, err
		}
		list = getStmtList(nodeFrom)
		newList := make([]ast.Stmt, len(list)+1)
		copy(newList, list[0:ind])
		newList[ind] = &ast.ExprStmt{callExpr}
		for i := ind; i < len(list); i++ {
			newList[i+1] = list[i]
		}
		printerUtil.AddLineForRange(fset, filename, callExpr.Pos(), callExpr.End())
		setStmtList(nodeFrom, newList)
		printerUtil.FixPositionsExcept(callExpr.Pos(), callExprLen, file, true, map[ast.Node]bool{callExpr: true})

	} else {

		//stmtList[0] = utils.CopyAstNode(stmtList[0]).(ast.Stmt)
		rs := stmtList[0].(*ast.ReturnStmt)

		callExpr, callExprLen := makeCallExpr(methodName, params, pointerSymbols, rs.Results[0].Pos(), recvSym, pack, filename)
		mod, baseMod := callExprLen-int(rs.Results[len(rs.Results)-1].End()-rs.Results[0].Pos()), 0
		fset, file, baseMod = printerUtil.ModifyLine(pack.FileSet, file, filename, programTree.IdentMap, callExpr.Pos(), mod)

		if baseMod != 1 {
			fmt.Printf("baseMod = %d\n", baseMod)
			printerUtil.FixPositions(0, 1-baseMod, callExpr, true)
			printerUtil.FixPositions(0, 1-baseMod, rs, true)
			printerUtil.FixPositions(0, 1-baseMod, fdecl, true)
		}
		fmt.Printf("results st,end = %d,%d, callExpr pos,end = %d,%d\n", rs.Results[0].Pos(), rs.Results[len(rs.Results)-1].End(), callExpr.Pos(), callExpr.End())
		errs := replaceExprList(fset.Position(rs.Results[0].Pos()), fset.Position(rs.Results[len(rs.Results)-1].End()), []ast.Expr{callExpr}, fset, file)
		if err, ok := errs[EXTRACT_METHOD]; ok {
			return false, err
		}

		fmt.Printf("mod = %d\n", mod)
		printerUtil.FixPositionsExcept(callExpr.Pos(), mod, file, true, map[ast.Node]bool{callExpr: true})
	}
	programTree.SaveFileExplicit(filename, fset, file)
	print("AAAAAA")
	if ok, fset, newF, err := printerUtil.AddDeclExplicit(fset, filename, file, fset, filename, file, fdecl, programTree.IdentMap); !ok {
		return false, err
	} else {
		print("BBBBBB")
		programTree.SaveFileExplicit(filename, fset, newF)
	}
	return true, nil

}
Пример #8
0
func (lv *innerScopeVisitor) parseStmt(node interface{}) (w ast.Visitor) {
	if node == nil {
		return nil
	}
	w = lv
	// 	fmt.Printf("ps %p %p %p %T ", lv.Parser.CurrentSymbolTable, lv.Current, lv.Method.Locals, node)
	// 	if id, ok := node.(*ast.Ident); ok {
	// 		fmt.Printf("%s ", id.Name)
	// 	}
	// 	println()
	temp := lv.Parser.CurrentSymbolTable
	lv.Parser.CurrentSymbolTable = lv.Current
	defer func() { lv.Parser.CurrentSymbolTable = temp }()
	switch s := node.(type) {

	case *ast.GenDecl:
		var IotaType st.ITypeSymbol = nil
		if len(s.Specs) > 0 {
			if vs, ok := s.Specs[0].(*ast.ValueSpec); ok {
				switch {
				case vs.Type != nil:
					ts := lv.Parser.parseTypeSymbol(vs.Type)
					if _, ok := ts.(*st.UnresolvedTypeSymbol); (ts == nil) || ok {
						panic("unresolved type at locals scope: " + ts.Name())
					}
					IotaType = ts
				case vs.Values != nil && len(vs.Values) > 0:
					ts := lv.Parser.parseExpr(vs.Values[0]).At(0).(st.ITypeSymbol)
					IotaType = ts
				default:
					panic("decl without either type or value????")
				}
			}
		}
		w = &innerScopeVisitor{lv.Method, lv.Current, lv.Parser, IotaType, lv.LabelsData}

	case *ast.ValueSpec: //Specify a new variable

		ts := lv.Parser.parseTypeSymbol(s.Type)

		if ts == nil {
			ts = lv.IotaType
		}
		valuesTypes := lv.getValuesTypesValSpec(s)
		for i, n := range s.Names {
			curTs := ts
			if ts == nil {
				curTs = valuesTypes.At(i).(st.ITypeSymbol)
			}
			toAdd := st.MakeVariable(n.Name, lv.Current, curTs)
			lv.Parser.registerIdent(toAdd, n)
			lv.Parser.CurrentSymbolTable.AddSymbol(toAdd)
		}

	case *ast.AssignStmt:
		valuesTypes := lv.getValuesTypesAss(s)
		switch s.Tok {
		case token.DEFINE: //Specify a new variable

			for i, nn := range s.Lhs {
				n := nn.(*ast.Ident)
				if n.Name != "_" {

					toAdd := st.MakeVariable(n.Name, lv.Current, valuesTypes.At(i).(st.ITypeSymbol))
					lv.Parser.registerIdent(toAdd, n)
					lv.Current.AddSymbol(toAdd)
					// 					fmt.Printf("DEFINED %s\n", toAdd.Name())
				}
			}
		case token.ASSIGN: //Pos
			for _, nn := range s.Lhs {
				// 				fmt.Printf("<!>")
				lv.Parser.parseExpr(nn)
			}
			w = nil
		}
	case *ast.TypeSpec: //Specify a new type
		ts := lv.Parser.parseTypeSymbol(s.Type)

		switch ts.(type) {
		case *st.PointerTypeSymbol, *st.ArrayTypeSymbol, *st.StructTypeSymbol, *st.InterfaceTypeSymbol, *st.MapTypeSymbol, *st.ChanTypeSymbol, *st.FunctionTypeSymbol:

			if ts.Name() == st.NO_NAME {
				//No such symbol in CurrentSymbolTable
				ts.SetName(s.Name.Name)
			} else {
				//There is an equal type symbol with different name => create alias
				ts = st.MakeAliasType(s.Name.Name, lv.Current, ts)
			}
			lv.Parser.registerIdent(ts, s.Name)
			lv.Current.AddSymbol(ts)
		default:
			panic("no type symbol returned")
		}
	case *ast.ExprStmt:
		lv.Parser.parseExpr(s.X)
	case *ast.DeferStmt:
		lv.Parser.parseExpr(s.Call)
	case *ast.GoStmt:
		lv.Parser.parseExpr(s.Call)
	case *ast.IncDecStmt:
		lv.Parser.parseExpr(s.X)
	//labels beg
	case *ast.LabeledStmt:
		l := st.MakeLabel(s.Label.Name, lv.Current)
		for id, _ := range lv.LabelsData {
			if id.Name == s.Label.Name {
				lv.Parser.registerIdent(l, id)
			}
		}
		for id, _ := range l.Idents {
			lv.LabelsData[id] = false, false
		}
		lv.Parser.registerIdent(l, s.Label)
		lv.Current.AddSymbol(l)
		ast.Walk(lv, s.Stmt)
		w = nil //prevent from usual ident registration
	case *ast.BranchStmt:
		if s.Label != nil {
			if l, ok := lv.Current.LookUpLabel(s.Label.Name); ok {
				lv.Parser.registerIdent(l, s.Label)
			} else {
				lv.LabelsData[s.Label] = true
			}
		}
		w = nil //prevent from usual ident registration
		//labels end
	case *ast.ReturnStmt:
		if s.Results != nil { //mb not needed
			for _, exp := range s.Results {
				lv.Parser.parseExpr(exp)
			}
		}
	case *ast.SendStmt:
		lv.Parser.parseExpr(s.Chan)
		lv.Parser.parseExpr(s.Value)
	case *ast.SwitchStmt, *ast.IfStmt, *ast.ForStmt, *ast.RangeStmt, *ast.FuncLit, *ast.SelectStmt, *ast.TypeSwitchStmt, *ast.CaseClause, *ast.CommClause:

		w = lv.parseBlockStmt(node)
	}
	return
}
Пример #9
0
func (lv *innerScopeVisitor) parseBlockStmt(node interface{}) (w ast.Visitor) {
	if node == nil {
		return nil
	}
	w = lv
	table := st.NewSymbolTable(lv.Parser.Package)
	// 	fmt.Printf(" %p %p %p \n", lv.Parser.CurrentSymbolTable, lv.Current, lv.Method.Locals)
	table.AddOpenedScope(lv.Current)
	ww := &innerScopeVisitor{lv.Method, table, lv.Parser, nil, lv.LabelsData}

	temp := lv.Parser.CurrentSymbolTable
	lv.Parser.CurrentSymbolTable = table
	defer func() { lv.Parser.CurrentSymbolTable = temp }()

	switch inNode := node.(type) {
	case *ast.ForStmt:
		ww.parseStmt(inNode.Init)
		ww.Parser.parseExpr(inNode.Cond)
		ww.parseStmt(inNode.Post)
		ast.Walk(ww, inNode.Body)
		w = nil
	case *ast.IfStmt:
		ww.parseStmt(inNode.Init)
		ww.Parser.parseExpr(inNode.Cond)
		ww1 := &innerScopeVisitor{lv.Method, st.NewSymbolTable(lv.Parser.Package), lv.Parser, nil, lv.LabelsData}
		ww2 := &innerScopeVisitor{lv.Method, st.NewSymbolTable(lv.Parser.Package), lv.Parser, nil, lv.LabelsData}
		ww1.Current.AddOpenedScope(ww.Current)
		ww2.Current.AddOpenedScope(ww.Current)
		ast.Walk(ww1, inNode.Body)
		ast.Walk(ww2, inNode.Else)
		w = nil
	case *ast.RangeStmt:
		rangeType := ww.Parser.parseExpr(inNode.X).At(0).(st.ITypeSymbol)
		// 		fmt.Printf("range type = %s, %T\n", rangeType.Name(), rangeType)
		switch inNode.Tok {
		case token.DEFINE:
			if rangeType, _ = st.GetBaseType(rangeType); rangeType == nil {
				panic("unexpected cycle")
			}

			var kT, vT st.ITypeSymbol
			switch rT := rangeType.(type) {
			case *st.ArrayTypeSymbol:
				kT = st.PredeclaredTypes["int"]
				vT = rT.ElemType
			case *st.MapTypeSymbol:
				kT = rT.KeyType
				vT = rT.ValueType
			case *st.BasicTypeSymbol: //string
				kT = st.PredeclaredTypes["int"]
				vT = st.PredeclaredTypes["byte"]
			case *st.ChanTypeSymbol:
				kT = rT.ValueType
			case *st.UnresolvedTypeSymbol:
				panic("unresolved at range")
			}
			iK := inNode.Key.(*ast.Ident)
			if iK.Name != "_" {

				toAdd := st.MakeVariable(iK.Name, ww.Current, kT)
				ww.Parser.registerIdent(toAdd, iK)
				ww.Current.AddSymbol(toAdd)

				// 				fmt.Printf("range key added %s %T\n", toAdd.Name(), toAdd)
			}
			if inNode.Value != nil { // not channel, two range vars
				iV := inNode.Value.(*ast.Ident)
				if iV.Name != "_" {
					toAdd := st.MakeVariable(iV.Name, ww.Current, vT)
					ww.Parser.registerIdent(toAdd, iV)
					ww.Current.AddSymbol(toAdd)
					// 					fmt.Printf("range value added %s %T\n", toAdd.Name(), toAdd)
				}
			}
		case token.ASSIGN:
			ww.Parser.parseExpr(inNode.Key)
			if inNode.Value != nil {
				ww.Parser.parseExpr(inNode.Value)
			}
		}
		ast.Walk(ww, inNode.Body)
		// 		fmt.Printf("end of range\n")
		w = nil
	case *ast.SelectStmt:
		w = ww
	case *ast.SwitchStmt:
		ww.parseStmt(inNode.Init)
		ww.Parser.parseExpr(inNode.Tag)
		ast.Walk(ww, inNode.Body)
		w = nil
	case *ast.TypeSwitchStmt:
		ww.parseStmt(inNode.Init)
		switch tsT := inNode.Assign.(type) {
		case *ast.AssignStmt:
			tsVar := tsT.Lhs[0].(*ast.Ident)
			tsTypeAss := tsT.Rhs[0].(*ast.TypeAssertExpr)
			tsType := ww.Parser.parseExpr(tsTypeAss.X).At(0).(st.ITypeSymbol)

			toAdd := st.MakeVariable(tsVar.Name, ww.Current, tsType)
			toAdd.IsTypeSwitchVar = true
			ww.Parser.registerIdent(toAdd, tsVar)
			ww.Current.AddSymbol(toAdd)
		case *ast.ExprStmt:
			tsTypeAss := tsT.X.(*ast.TypeAssertExpr)
			ww.Parser.parseExpr(tsTypeAss.X)
		}
		ast.Walk(ww, inNode.Body)
		w = nil
	case *ast.CaseClause:

		if inNode.List != nil {
			s := ww.Parser.parseExpr(inNode.List[0]).At(0)
			_, isTypeSwitch := s.(st.ITypeSymbol)

			if isTypeSwitch {
				switch {
				case len(inNode.List) == 1:
					tsType := ww.Parser.parseExpr(inNode.List[0]).At(0).(st.ITypeSymbol)
					if tsVar, ok := lv.Current.FindTypeSwitchVar(); ok {

						toAdd := st.MakeVariable(tsVar.Name(), ww.Current, tsType)
						toAdd.Idents = tsVar.Idents
						toAdd.Posits = tsVar.Posits
						//No position, just register symbol
						ww.Current.AddSymbol(toAdd)
					}
				case len(inNode.List) > 1:
					for _, t := range inNode.List {
						ww.Parser.parseExpr(t)
					}
				}
			} else {
				for _, v := range inNode.List {
					ww.Parser.parseExpr(v)
				}
			}
		}

		for _, stmt := range inNode.Body {
			ast.Walk(ww, stmt)
		}
		w = nil
	case *ast.CommClause:
		ww.parseStmt(inNode.Comm)

		for _, stmt := range inNode.Body {
			ast.Walk(ww, stmt)
		}
		w = nil
	case *ast.FuncLit:
		meth := st.MakeFunction("#", ww.Current, lv.Parser.parseTypeSymbol(inNode.Type))
		meth.Locals = st.NewSymbolTable(ww.Parser.Package)
		meth.Locals.AddOpenedScope(lv.Current)
		if meth.FunctionType.(*st.FunctionTypeSymbol).Parameters != nil {
			meth.Locals.AddOpenedScope(meth.FunctionType.(*st.FunctionTypeSymbol).Parameters)
		}
		if meth.FunctionType.(*st.FunctionTypeSymbol).Results != nil {
			meth.Locals.AddOpenedScope(meth.FunctionType.(*st.FunctionTypeSymbol).Results)
		}
		w = &innerScopeVisitor{meth, meth.Locals, lv.Parser, nil, lv.LabelsData}
	}
	return w
}