// ResolveQualifiedIdents resolves the selectors of qualified // identifiers by associating the correct ast.Object with them. // TODO(gri): Eventually, this functionality should be subsumed // by Check. // func ResolveQualifiedIdents(fset *token.FileSet, pkg *ast.Package) error { var errors scanner.ErrorList findObj := func(pkg *ast.Object, name *ast.Ident) *ast.Object { scope := pkg.Data.(*ast.Scope) obj := scope.Lookup(name.Name) if obj == nil { errors.Add(fset.Position(name.Pos()), fmt.Sprintf("no %s in package %s", name.Name, pkg.Name)) } return obj } ast.Inspect(pkg, func(n ast.Node) bool { if s, ok := n.(*ast.SelectorExpr); ok { if x, ok := s.X.(*ast.Ident); ok && x.Obj != nil && x.Obj.Kind == ast.Pkg { // find selector in respective package s.Sel.Obj = findObj(x.Obj, s.Sel) } return false } return true }) return errors.Err() }
func (c *compiler) VisitDecl(decl ast.Decl) Value { c.setDebugLine(decl.Pos()) // This is temporary. We'll return errors later, rather than panicking. if c.Logger != nil { c.Logger.Println("Compile declaration:", c.fileset.Position(decl.Pos())) } defer func() { if e := recover(); e != nil { elist := new(scanner.ErrorList) elist.Add(c.fileset.Position(decl.Pos()), fmt.Sprint(e)) panic(elist) } }() switch x := decl.(type) { case *ast.FuncDecl: return c.VisitFuncDecl(x) case *ast.GenDecl: c.VisitGenDecl(x) return nil } panic(fmt.Sprintf("Unhandled decl (%s) at %s\n", reflect.TypeOf(decl), c.fileset.Position(decl.Pos()))) }
func (p *Parser) Ast(fs *token.FileSet, path string, files []string, unsaved map[string]UnsavedDocument) (*ast.File, []*ast.File, error) { ret := make([]*ast.File, len(files)) var retf *ast.File var errors scanner.ErrorList for i, f := range files { f = CanonicalPath(f) var v *ast.File var err error if uns, ok := unsaved[f]; ok { v, err = parser.ParseFile(fs, f, uns.Data, parser.AllErrors) } else { v, err = p.fromCache(fs, f) } if v == nil { return nil, nil, err } ret[i] = v if path == f { retf = ret[i] if perr, ok := err.(scanner.ErrorList); ok { for _, e := range perr { errors.Add(e.Pos, e.Msg) } } } } errors.RemoveMultiples() errors.Sort() var err error if len(errors) != 0 { err = errors } return retf, ret, err }
func checkFiles(t *testing.T, testname string, testfiles []string) { // TODO(gri) Eventually all these different phases should be // subsumed into a single function call that takes // a set of files and creates a fully resolved and // type-checked AST. files, err := parseFiles(t, testname, testfiles) // we are expecting the following errors // (collect these after parsing the files so that // they are found in the file set) errors := expectedErrors(t, testname, files) // verify errors returned by the parser eliminate(t, errors, err) // verify errors returned after resolving identifiers pkg, err := ast.NewPackage(fset, files, GcImport, Universe) eliminate(t, errors, err) // verify errors returned by the typechecker var list scanner.ErrorList errh := func(pos token.Pos, msg string) { list.Add(fset.Position(pos), msg) } err = Check(fset, pkg, errh, nil) eliminate(t, errors, list) if *listErrors { scanner.PrintError(os.Stdout, err) return } // there should be no expected errors left if len(errors) > 0 { t.Errorf("%s: %d errors not reported:", testname, len(errors)) for pos, msg := range errors { t.Errorf("%s: %s\n", fset.Position(pos), msg) } } }
func processFile(filename string) ([]*prototype, error) { info, err := os.Stat(filename) if err != nil { return nil, err } src, err := ioutil.ReadFile(filename) if err != nil { return nil, err } // Scan file protos := make([]*prototype, 0) var errorList scanner.ErrorList var s scanner.Scanner fset := token.NewFileSet() file := fset.AddFile(filename, fset.Base(), int(info.Size())) s.Init(file, src, nil, scanner.ScanComments) for findPkg, isPkgToken := true, false; ; { _, tok, lit := s.Scan() if tok == token.EOF { break } // package name if findPkg { if tok == token.PACKAGE { isPkgToken = true continue } if isPkgToken { if PKG_NAME == "" { PKG_NAME = lit if PKG_NAME == "syscall" { SYSCALL_DOT = "" } } else if PKG_NAME != lit { return nil, errors.New("the files have different package name") } findPkg = false continue } } // scan comments if tok != token.COMMENT || !strings.HasPrefix(lit, PREFIX) { continue } lit = strings.Replace(lit, PREFIX, "", 1) if lit[0] != ' ' && lit[0] != '\t' { continue } lit = strings.TrimSpace(lit) proto, err := scanProtype([]byte(lit)) if err != nil { errorList.Add(err.Pos, err.Msg) continue } if errorList.Len() == 0 { protos = append(protos, proto) } } if errorList.Len() != 0 { return nil, errorList } return protos, nil }
func processFile(filename string, proto *prototype) error { info, err := os.Stat(filename) if err != nil { return err } src, err := ioutil.ReadFile(filename) if err != nil { return err } // Scan file var errorList scanner.ErrorList var s scanner.Scanner fset := token.NewFileSet() file := fset.AddFile(filename, fset.Base(), int(info.Size())) s.Init(file, src, nil, scanner.ScanComments) for findPkg, isPkgToken := true, false; ; { _, tok, lit := s.Scan() if tok == token.EOF { break } // package name if findPkg { if tok == token.PACKAGE { isPkgToken = true continue } if isPkgToken { if proto.pkgName == "" { (*proto).pkgName = lit } else if proto.pkgName != lit { return errors.New("the files have different package name") } findPkg = false continue } } // scan comments if tok != token.COMMENT || !strings.HasPrefix(lit, PREFIX) { continue } lit = strings.Replace(lit, PREFIX, "", 1) if lit[0] == '/' && lit[1] == '/' { proto.comment = lit continue } if lit[0] != ' ' && lit[0] != '\t' { continue } lit_ := strings.TrimSpace(lit) // multiple comments for { if lit[len(lit)-1] == ',' { // the line continues on the next one _, tok, lit = s.Scan() if tok == token.COMMENT { lit = strings.Replace(lit, "//", "", 1) lit = strings.TrimSpace(lit) lit_ += lit } else { break } } else { break } } err := scanProtype(proto, []byte(lit_)) if err != nil { errorList.Add(err.Pos, err.Msg) continue } } if errorList.Len() != 0 { return errorList } return nil }