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 }
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 }
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) } }
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 }
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 }
//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 }
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 }
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 }
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 }