Beispiel #1
0
// 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()
}
Beispiel #2
0
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())))
}
Beispiel #3
0
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
}
Beispiel #4
0
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)
		}
	}
}
Beispiel #5
0
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
}
Beispiel #6
0
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
}