Example #1
0
File: types.go Project: spate/llgo
func (c *compiler) VisitFuncType(f *ast.FuncType) TypeValue {
	var fn_type types.Func

	if f.Params != nil && len(f.Params.List) > 0 {
		final_param_type := f.Params.List[len(f.Params.List)-1].Type
		if _, varargs := final_param_type.(*ast.Ellipsis); varargs {
			fn_type.IsVariadic = true
		}
		for i := 0; i < len(f.Params.List); i++ {
			namecount := len(f.Params.List[i].Names)
			typ := c.GetType(f.Params.List[i].Type)
			if namecount == 0 {
				arg := ast.NewObj(ast.Var, "_")
				arg.Type = typ
				fn_type.Params = append(fn_type.Params, arg)
			} else {
				args := make([]*ast.Object, namecount)
				for j := 0; j < namecount; j++ {
					ident := f.Params.List[i].Names[j]
					if ident != nil {
						args[j] = ident.Obj
					} else {
						args[j] = ast.NewObj(ast.Var, "_")
					}
					args[j].Type = typ
				}
				fn_type.Params = append(fn_type.Params, args...)
			}
		}
	}

	if f.Results != nil {
		for i := 0; i < len(f.Results.List); i++ {
			namecount := len(f.Results.List[i].Names)
			typ := c.GetType(f.Results.List[i].Type)
			if namecount > 0 {
				results := make([]*ast.Object, namecount)
				for j := 0; j < namecount; j++ {
					ident := f.Results.List[i].Names[j]
					if ident != nil {
						results[j] = ident.Obj
					} else {
						results[j] = ast.NewObj(ast.Var, "_")
					}
					results[j].Type = typ
				}
				fn_type.Results = append(fn_type.Results, results...)
			} else {
				result := ast.NewObj(ast.Var, "_")
				result.Type = typ
				fn_type.Results = append(fn_type.Results, result)
			}
		}
	}

	return TypeValue{&fn_type}
}
Example #2
0
// MethodOrEmbedSpec = Name [ Signature ] .
//
func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
	name := p.parseName()
	if p.tok == '(' {
		obj := ast.NewObj(ast.Fun, name)
		obj.Type = p.parseSignature()
		return obj
	}
	// TODO lookup name and return that type
	return ast.NewObj(ast.Typ, "_")
}
Example #3
0
// MethodOrEmbedSpec = Name [ Signature ] .
//
func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
	p.parseName()
	if p.tok == '(' {
		p.parseSignature()
		// TODO(gri) compute method object
		return ast.NewObj(ast.Fun, "_")
	}
	// TODO lookup name and return that type
	return ast.NewObj(ast.Typ, "_")
}
Example #4
0
func (p *parser) findIdent() *ast.Ident {
	pos := p.pos
	name := "_"
	var obj *ast.Object
	if p.tok == token.IDENT {
		name = string(p.lit)
		obj = p.funcScope.Lookup(name)
		p.next()
	} else {
		p.expect(token.IDENT) // use expect() error handling
	}
	if obj == nil {
		// No declaration found: either we are outside any function
		// (p.funcScope == nil) or the identifier is not declared
		// in any function. Try the file and package scope.
		obj = p.fileScope.Lookup(name) // file scope is nested in package scope
		if obj == nil {
			// No declaration found anywhere: track as
			// unresolved identifier in the package scope.
			obj = ast.NewObj(ast.Err, pos, name)
			p.pkgScope.Declare(obj)
		}
	}
	return &ast.Ident{pos, obj}
}
Example #5
0
File: parser.go Project: h12w/gombi
func (p *parser) declareShortVar(decl *ast.AssignStmt, list []ast.Expr) {
	// Go spec: A short variable declaration may redeclare variables
	// provided they were originally declared in the same block with
	// the same type, and at least one of the non-blank variables is new.
	n := 0 // number of new variables
	for _, x := range list {
		if ident, isIdent := x.(*ast.Ident); isIdent {
			assert(ident.Obj == nil, "identifier already declared or resolved")
			obj := ast.NewObj(ast.Var, ident.Name)
			// remember corresponding assignment for other tools
			obj.Decl = decl
			ident.Obj = obj
			if ident.Name != "_" {
				if alt := p.topScope.Insert(obj); alt != nil {
					ident.Obj = alt // redeclaration
				} else {
					n++ // new declaration
				}
			}
		} else {
			p.errorExpected(x.Pos(), "identifier on left side of :=")
		}
	}
	if n == 0 && p.mode&DeclarationErrors != 0 {
		p.error(list[0].Pos(), "no new variables on left side of :=")
	}
}
Example #6
0
// MethodDecl = "func" Receiver Name Signature .
// Receiver   = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ].
//
func (p *gcParser) parseMethodDecl() {
	// "func" already consumed
	p.expect('(')
	recv, _ := p.parseParameter() // receiver
	p.expect(')')

	// unexported method names in imports are qualified with their package.
	fn := ast.NewObj(ast.Fun, p.parseName())
	fnType := p.parseSignature()
	fnType.Recv = recv
	fn.Type = fnType

	var recvType *Name
	if ptr, isptr := recv.Type.(*Pointer); isptr {
		recvType = ptr.Base.(*Name)
	} else {
		recvType = recv.Type.(*Name)
	}
	recvType.Methods = append(recvType.Methods, fn)
	recvType.Methods.Sort()

	if p.tok == '{' {
		p.parseFuncBody()
	}
}
Example #7
0
// Declare inserts a named object of the given kind in scope.
func (p *gcParser) declare(scope *ast.Scope, kind ast.ObjKind, name string) *ast.Object {
	// a type may have been declared before - if it exists
	// already in the respective package scope, return that
	// type
	if kind == ast.Typ {
		if obj := scope.Lookup(name); obj != nil {
			assert(obj.Kind == ast.Typ)
			return obj
		}
	}

	// any other object must be a newly declared object -
	// create it and insert it into the package scope
	obj := ast.NewObj(kind, name)
	if scope.Insert(obj) != nil {
		p.errorf("already declared: %v %s", kind, obj.Name)
	}

	// a new type object is a named type and may be referred
	// to before the underlying type is known - set it up
	if kind == ast.Typ {
		obj.Type = &Name{Obj: obj}
	}

	return obj
}
Example #8
0
// collectMethods collects the method declarations from an AST File and
// returns a mapping from receiver types to their method FuncDecl's.
func (c *checker) collectMethods(file *ast.File) {
	for _, decl := range file.Decls {
		if funcdecl, ok := decl.(*ast.FuncDecl); ok && funcdecl.Recv != nil {
			recvField := funcdecl.Recv.List[0]
			var recv *ast.Ident
			switch typ := recvField.Type.(type) {
			case *ast.StarExpr:
				recv = typ.X.(*ast.Ident)
			case *ast.Ident:
				recv = typ
			case *ast.BadExpr:
				return
			}

			if recv.Obj == nil {
				// error reported elsewhere.
				return
			}

			if recv.Obj.Kind != ast.Typ {
				c.errorf(recv.Pos(), "%s is not a type", recv.Name)
				return
			}

			// The Obj field of the funcdecl wll be nil, so we'll have to
			// create a new one.
			funcdecl.Name.Obj = ast.NewObj(ast.Fun, funcdecl.Name.String())
			funcdecl.Name.Obj.Decl = funcdecl
			c.methods[recv.Obj] = append(c.methods[recv.Obj], funcdecl.Name.Obj)
		}
	}
}
Example #9
0
func define(kind ast.ObjKind, name string) *ast.Object {
	obj := ast.NewObj(kind, name)
	if scope.Insert(obj) != nil {
		panic("types internal error: double declaration")
	}
	return obj
}
Example #10
0
func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg == nil {
		// Guess the package name without importing it. Start with the last
		// element of the path.
		name := path[strings.LastIndex(path, "/")+1:]

		// Trim commonly used prefixes and suffixes containing illegal name
		// runes.
		name = strings.TrimSuffix(name, ".go")
		name = strings.TrimSuffix(name, "-go")
		name = strings.TrimPrefix(name, "go.")
		name = strings.TrimPrefix(name, "go-")
		name = strings.TrimPrefix(name, "biogo.")

		// It's also common for the last element of the path to contain an
		// extra "go" prefix, but not always. TODO: examine unresolved ids to
		// detect when trimming the "go" prefix is appropriate.

		pkg = ast.NewObj(ast.Pkg, name)
		pkg.Data = ast.NewScope(nil)
		imports[path] = pkg
	}
	return pkg, nil
}
Example #11
0
// ImportPath = string_lit .
//
func (p *gcParser) parsePkgId() *ast.Object {
	id, err := strconv.Unquote(p.expect(scanner.String))
	if err != nil {
		p.error(err)
	}

	switch id {
	case "":
		// id == "" stands for the imported package id
		// (only known at time of package installation)
		id = p.id
	case "unsafe":
		// package unsafe is not in the imports map - handle explicitly
		return Unsafe
	}

	pkg := p.imports[id]
	if pkg == nil {
		scope = ast.NewScope(nil)
		pkg = ast.NewObj(ast.Pkg, "")
		pkg.Data = scope
		p.imports[id] = pkg
	}

	return pkg
}
Example #12
0
// ExportedName = ImportPath "." dotIdentifier .
//
func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
	pkg := p.parsePkgId()
	p.expect('.')
	name := p.parseDotIdent()

	// a type may have been declared before - if it exists
	// already in the respective package scope, return that
	// type
	scope := pkg.Data.(*ast.Scope)
	if kind == ast.Typ {
		if obj := scope.Lookup(name); obj != nil {
			assert(obj.Kind == ast.Typ)
			return obj
		}
	}

	// any other object must be a newly declared object -
	// create it and insert it into the package scope
	obj := ast.NewObj(kind, name)
	if scope.Insert(obj) != nil {
		p.errorf("already declared: %s", obj.Name)
	}

	// a new type object is a named type and may be referred
	// to before the underlying type is known - set it up
	if kind == ast.Typ {
		obj.Type = &Name{Obj: obj}
	}

	return obj
}
Example #13
0
func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
	if p.trace {
		defer un(trace(p, "ImportSpec"))
	}

	var ident *ast.Ident
	if p.tok == token.PERIOD {
		ident = &ast.Ident{p.pos, ast.NewObj(ast.Pkg, p.pos, ".")}
		p.next()
	} else if p.tok == token.IDENT {
		ident = p.parseIdent(ast.Pkg)
		// TODO(gri) Make sure the ident is not already declared in the
		//           package scope. Also, cannot add the same name to
		//           the package scope later.
		p.declIdent(p.fileScope, ident)
	}

	var path *ast.BasicLit
	if p.tok == token.STRING {
		path = &ast.BasicLit{p.pos, p.tok, p.lit}
		p.next()
	} else {
		p.expect(token.STRING) // use expect() error handling
	}
	p.expectSemi()

	return &ast.ImportSpec{doc, ident, path, p.lineComment}
}
Example #14
0
// Export        = "PackageClause { Decl } "$$" .
// PackageClause = "package" identifier [ "safe" ] "\n" .
//
func (p *gcParser) parseExport() *ast.Object {
	p.expectKeyword("package")
	name := p.expect(scanner.Ident)
	if p.tok != '\n' {
		// A package is safe if it was compiled with the -u flag,
		// which disables the unsafe package.
		// TODO(gri) remember "safe" package
		p.expectKeyword("safe")
	}
	p.expect('\n')

	assert(p.imports[p.id] == nil)
	pkg := ast.NewObj(ast.Pkg, name)
	pkg.Data = ast.NewScope(nil)
	p.imports[p.id] = pkg

	for p.tok != '$' && p.tok != scanner.EOF {
		p.parseDecl()
	}

	if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
		// don't call next()/expect() since reading past the
		// export data may cause scanner errors (e.g. NUL chars)
		p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
	}

	if n := p.scanner.ErrorCount; n != 0 {
		p.errorf("expected no scanner errors, got %d", n)
	}

	return pkg
}
Example #15
0
func init() {
	scope = ast.NewScope(nil)
	Universe = scope

	Bool = defType("bool")
	defType("byte") // TODO(gri) should be an alias for uint8
	defType("complex64")
	Complex128 = defType("complex128")
	defType("float32")
	Float64 = defType("float64")
	defType("int8")
	defType("int16")
	defType("int32")
	defType("int64")
	String = defType("string")
	defType("uint8")
	defType("uint16")
	defType("uint32")
	defType("uint64")
	Int = defType("int")
	defType("uint")
	defType("uintptr")

	defConst("true")
	defConst("false")
	defConst("iota")
	defConst("nil")

	defFun("append")
	defFun("cap")
	defFun("close")
	defFun("complex")
	defFun("copy")
	defFun("delete")
	defFun("imag")
	defFun("len")
	defFun("make")
	defFun("new")
	defFun("panic")
	defFun("print")
	defFun("println")
	defFun("real")
	defFun("recover")

	scope = ast.NewScope(nil)
	Unsafe = ast.NewObj(ast.Pkg, "unsafe")
	Unsafe.Data = scope

	defType("Pointer")

	defFun("Alignof")
	defFun("New")
	defFun("NewArray")
	defFun("Offsetof")
	defFun("Reflect")
	defFun("Sizeof")
	defFun("Typeof")
	defFun("Unreflect")
}
// findField returns the object with the given name if visible in the type's scope.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
	// TODO(gri) This is simplistic at the moment and ignores anonymous fields.
	obj = typ.Scope.Lookup(name.Name)
	if obj == nil {
		tc.Errorf(name.Pos(), "%s not declared", name.Name)
		obj = ast.NewObj(ast.Bad, name.Name)
	}
	return
}
Example #17
0
func (p *parser) parseIdent(kind ast.ObjKind) *ast.Ident {
	obj := ast.NewObj(kind, p.pos, "_")
	if p.tok == token.IDENT {
		obj.Name = string(p.lit)
		p.next()
	} else {
		p.expect(token.IDENT) // use expect() error handling
	}
	return &ast.Ident{obj.Pos, obj}
}
Example #18
0
func importer(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg == nil {
		name := path[strings.LastIndex(path, "/")+1:]
		pkg = ast.NewObj(ast.Pkg, name)
		pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
		imports[path] = pkg
	}
	return pkg, nil
}
Example #19
0
// poorMansImporter returns a (dummy) package object named
// by the last path component of the provided package path
// (as is the convention for packages). This is sufficient
// to resolve package identifiers without doing an actual
// import. It never returns an error.
//
func poorMansImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
	pkg := imports[path]
	if pkg == nil {
		// note that strings.LastIndex returns -1 if there is no "/"
		pkg = ast.NewObj(ast.Pkg, path[strings.LastIndex(path, "/")+1:])
		pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
		imports[path] = pkg
	}
	return pkg, nil
}
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
// It returns the newly allocated object. If an object with the same name already exists in scope, an error
// is reported and the object is not inserted.
// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
	obj := ast.NewObj(kind, name.Name)
	obj.Decl = decl
	obj.N = n
	name.Obj = obj
	if alt := scope.Insert(obj); alt != obj {
		tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
	}
	return obj
}
Example #21
0
// collectFields collects struct fields tok = token.STRUCT), interface methods
// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
	if list != nil {
		for _, field := range list.List {
			ftype := field.Type
			if t, ok := ftype.(*ast.Ellipsis); ok {
				ftype = t.Elt
				isVariadic = true
			}
			typ := c.makeType(ftype, cycleOk)
			if isVariadic {
				typ = &Slice{Elt: typ}
			}
			tag := ""
			if field.Tag != nil {
				assert(field.Tag.Kind == token.STRING)
				tag, _ = strconv.Unquote(field.Tag.Value)
			}
			if len(field.Names) > 0 {
				// named fields
				for _, name := range field.Names {
					obj := name.Obj
					obj.Type = typ
					fields = append(fields, obj)
					if tok == token.STRUCT {
						tags = append(tags, tag)
					}
				}
			} else {
				// anonymous field
				switch tok {
				case token.STRUCT:
					tags = append(tags, tag)
					fallthrough
				case token.FUNC:
					obj := ast.NewObj(ast.Var, "")
					obj.Type = typ
					fields = append(fields, obj)
				case token.INTERFACE:
					utyp := Underlying(typ)
					if typ, ok := utyp.(*Interface); ok {
						// TODO(gri) This is not good enough. Check for double declarations!
						fields = append(fields, typ.Methods...)
					} else if _, ok := utyp.(*Bad); !ok {
						// if utyp is Bad, don't complain (the root cause was reported before)
						c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
					}
				default:
					panic("unreachable")
				}
			}
		}
	}
	return
}
// find returns the object with the given name if visible in the current scope hierarchy.
// If no such object is found, an error is reported and a bad object is returned instead.
func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
	for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
		obj = s.Lookup(name.Name)
	}
	if obj == nil {
		tc.Errorf(name.Pos(), "%s not declared", name.Name)
		obj = ast.NewObj(ast.Bad, name.Name)
	}
	name.Obj = obj
	return
}
Example #23
0
// MethodSpec = ( identifier | ExportedName )  Signature .
//
func (p *gcParser) parseMethodSpec() *ast.Object {
	if p.tok == scanner.Ident {
		p.expect(scanner.Ident)
	} else {
		p.parseExportedName()
	}
	p.parseSignature()

	// TODO(gri) compute method object
	return ast.NewObj(ast.Fun, "_")
}
Example #24
0
func init() {
	// Universe scope
	Universe = ast.NewScope(nil)

	// unsafe package and its scope
	unsafe = ast.NewScope(nil)
	Unsafe = ast.NewObj(ast.Pkg, "unsafe")
	Unsafe.Data = unsafe

	// predeclared types
	for _, t := range Typ {
		def(ast.Typ, t.Name).Type = t
	}
	for _, t := range aliases {
		def(ast.Typ, t.Name).Type = t
	}

	// error type
	{
		res := ast.NewObj(ast.Var, "")
		res.Type = Typ[String]
		err := ast.NewObj(ast.Fun, "Error")
		err.Type = &Signature{Results: ObjList{res}}
		obj := def(ast.Typ, "error")
		obj.Type = &NamedType{Underlying: &Interface{Methods: ObjList{err}}, Obj: obj}
	}

	// predeclared constants
	for _, t := range predeclaredConstants {
		obj := def(ast.Con, t.name)
		obj.Type = Typ[t.kind]
		obj.Data = t.val
	}

	// predeclared functions
	for _, f := range predeclaredFunctions {
		def(ast.Fun, f.name).Type = f
	}

	universeIota = Universe.Lookup("iota")
}
Example #25
0
// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
// It returns the newly allocated object. If an object with the same name already exists in scope, an error
// is reported and the object is not inserted.
func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
	obj := ast.NewObj(kind, name.Name)
	obj.Decl = decl
	//obj.N = n
	name.Obj = obj
	if name.Name != "_" {
		if alt := scope.Insert(obj); alt != nil {
			tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
		}
	}
	return obj
}
Example #26
0
func (v *refsSaver) importer() ast.Importer {
	return func(imports map[string]*ast.Object, pkgPath string) (*ast.Object, error) {
		if pkg, exists := imports[pkgPath]; exists {
			return pkg, nil
		}
		if !strings.HasPrefix(pkgPath, v.pkgPrefix) {
			return nil, errors.New("ignored")
		}
		pkg := ast.NewObj(ast.Pkg, path.Base(pkgPath))
		imports[pkgPath] = pkg
		return pkg, nil
	}
}
Example #27
0
func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
	idents := make([]*ast.Ident, list.Len())
	for i := 0; i < list.Len(); i++ {
		ident, isIdent := list.At(i).(*ast.Ident)
		if !isIdent {
			pos := list.At(i).(ast.Expr).Pos()
			p.errorExpected(pos, "identifier")
			idents[i] = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "")}
		}
		idents[i] = ident
	}
	return idents
}
Example #28
0
File: types.go Project: spate/llgo
func (c *compiler) VisitStructType(s *ast.StructType) TypeValue {
	var typ = new(types.Struct)
	if s.Fields != nil && s.Fields.List != nil {
		tags := make(map[*ast.Object]string)
		var i int = 0
		for _, field := range s.Fields.List {
			fieldtype := c.GetType(field.Type)
			if field.Names != nil {
				for _, name := range field.Names {
					obj := name.Obj
					if obj == nil {
						obj = ast.NewObj(ast.Var, "_")
					}
					obj.Type = fieldtype
					typ.Fields = append(typ.Fields, obj)
					if field.Tag != nil {
						tags[obj] = field.Tag.Value
					}
				}
				i += len(field.Names)
			} else {
				obj := ast.NewObj(ast.Var, "_")
				obj.Type = fieldtype
				typ.Fields = append(typ.Fields, obj)
				if field.Tag != nil {
					tags[obj] = field.Tag.Value
				}
				i++
			}
		}

		typ.Tags = make([]string, len(typ.Fields))
		for i, field := range typ.Fields {
			// TODO unquote string?
			typ.Tags[i] = tags[field]
		}
	}
	return TypeValue{typ}
}
Example #29
0
func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
	idents := make([]*ast.Ident, len(*list))
	for i, x := range *list {
		ident, isIdent := x.(*ast.Ident)
		if !isIdent {
			pos := x.(ast.Expr).Pos()
			p.errorExpected(pos, "identifier")
			ident = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "_")}
		}
		idents[i] = ident
	}
	return idents
}
Example #30
0
// NewTestFuncDecl creates a new FuncDecl for starndard testing
// without position.
func NewTestFuncDecl(name string) *ast.FuncDecl {

	ident := ast.NewIdent(name)
	ident.Obj = ast.NewObj(ast.Fun, name)

	identVarT := ast.NewIdent("t")
	identVarT.Obj = ast.NewObj(ast.Var, "t")

	// params are params for func
	params := &ast.FieldList{
		List: []*ast.Field{
			{
				// t
				Names: []*ast.Ident{
					identVarT,
				},

				// *testing.T
				Type: &ast.StarExpr{
					X: &ast.SelectorExpr{
						X:   ast.NewIdent("testing"),
						Sel: ast.NewIdent("T"),
					},
				},
			},
		},
	}

	funcType := &ast.FuncType{
		Params: params,
	}

	return &ast.FuncDecl{
		Name: ident,
		Type: funcType,
		Body: &ast.BlockStmt{},
	}
}