997 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			997 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2013 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| // This is a verbatim copy of $GOROOT/src/go/internal/gccgoimporter/parser.go
 | |
| // with a small modification in parseInterface to support older Go versions.
 | |
| 
 | |
| package gccgoimporter
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"go/constant"
 | |
| 	"go/token"
 | |
| 	"go/types"
 | |
| 	"io"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"text/scanner"
 | |
| )
 | |
| 
 | |
| type parser struct {
 | |
| 	scanner  scanner.Scanner
 | |
| 	version  string                    // format version
 | |
| 	tok      rune                      // current token
 | |
| 	lit      string                    // literal string; only valid for Ident, Int, String tokens
 | |
| 	pkgpath  string                    // package path of imported package
 | |
| 	pkgname  string                    // name of imported package
 | |
| 	pkg      *types.Package            // reference to imported package
 | |
| 	imports  map[string]*types.Package // package path -> package object
 | |
| 	typeList []types.Type              // type number -> type
 | |
| 	initdata InitData                  // package init priority data
 | |
| }
 | |
| 
 | |
| func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
 | |
| 	p.scanner.Init(src)
 | |
| 	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
 | |
| 	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
 | |
| 	p.scanner.Whitespace = 1<<'\t' | 1<<'\n' | 1<<' '
 | |
| 	p.scanner.Filename = filename // for good error messages
 | |
| 	p.next()
 | |
| 	p.imports = imports
 | |
| 	p.typeList = make([]types.Type, 1 /* type numbers start at 1 */, 16)
 | |
| }
 | |
| 
 | |
| type importError struct {
 | |
| 	pos scanner.Position
 | |
| 	err error
 | |
| }
 | |
| 
 | |
| func (e importError) Error() string {
 | |
| 	return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
 | |
| }
 | |
| 
 | |
| func (p *parser) error(err interface{}) {
 | |
| 	if s, ok := err.(string); ok {
 | |
| 		err = errors.New(s)
 | |
| 	}
 | |
| 	// panic with a runtime.Error if err is not an error
 | |
| 	panic(importError{p.scanner.Pos(), err.(error)})
 | |
| }
 | |
| 
 | |
| func (p *parser) errorf(format string, args ...interface{}) {
 | |
| 	p.error(fmt.Errorf(format, args...))
 | |
| }
 | |
| 
 | |
| func (p *parser) expect(tok rune) string {
 | |
| 	lit := p.lit
 | |
| 	if p.tok != tok {
 | |
| 		p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
 | |
| 	}
 | |
| 	p.next()
 | |
| 	return lit
 | |
| }
 | |
| 
 | |
| func (p *parser) expectKeyword(keyword string) {
 | |
| 	lit := p.expect(scanner.Ident)
 | |
| 	if lit != keyword {
 | |
| 		p.errorf("expected keyword %s, got %q", keyword, lit)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (p *parser) parseString() string {
 | |
| 	str, err := strconv.Unquote(p.expect(scanner.String))
 | |
| 	if err != nil {
 | |
| 		p.error(err)
 | |
| 	}
 | |
| 	return str
 | |
| }
 | |
| 
 | |
| // unquotedString     = { unquotedStringChar } .
 | |
| // unquotedStringChar = <neither a whitespace nor a ';' char> .
 | |
| func (p *parser) parseUnquotedString() string {
 | |
| 	if p.tok == scanner.EOF {
 | |
| 		p.error("unexpected EOF")
 | |
| 	}
 | |
| 	var buf bytes.Buffer
 | |
| 	buf.WriteString(p.scanner.TokenText())
 | |
| 	// This loop needs to examine each character before deciding whether to consume it. If we see a semicolon,
 | |
| 	// we need to let it be consumed by p.next().
 | |
| 	for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
 | |
| 		buf.WriteRune(ch)
 | |
| 		p.scanner.Next()
 | |
| 	}
 | |
| 	p.next()
 | |
| 	return buf.String()
 | |
| }
 | |
| 
 | |
| func (p *parser) next() {
 | |
| 	p.tok = p.scanner.Scan()
 | |
| 	switch p.tok {
 | |
| 	case scanner.Ident, scanner.Int, scanner.Float, scanner.String, '·':
 | |
| 		p.lit = p.scanner.TokenText()
 | |
| 	default:
 | |
| 		p.lit = ""
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (p *parser) parseQualifiedName() (path, name string) {
 | |
| 	return p.parseQualifiedNameStr(p.parseString())
 | |
| }
 | |
| 
 | |
| func (p *parser) parseUnquotedQualifiedName() (path, name string) {
 | |
| 	return p.parseQualifiedNameStr(p.parseUnquotedString())
 | |
| }
 | |
| 
 | |
| // qualifiedName = [ ["."] unquotedString "." ] unquotedString .
 | |
| //
 | |
| // The above production uses greedy matching.
 | |
| func (p *parser) parseQualifiedNameStr(unquotedName string) (pkgpath, name string) {
 | |
| 	parts := strings.Split(unquotedName, ".")
 | |
| 	if parts[0] == "" {
 | |
| 		parts = parts[1:]
 | |
| 	}
 | |
| 
 | |
| 	switch len(parts) {
 | |
| 	case 0:
 | |
| 		p.errorf("malformed qualified name: %q", unquotedName)
 | |
| 	case 1:
 | |
| 		// unqualified name
 | |
| 		pkgpath = p.pkgpath
 | |
| 		name = parts[0]
 | |
| 	default:
 | |
| 		// qualified name, which may contain periods
 | |
| 		pkgpath = strings.Join(parts[0:len(parts)-1], ".")
 | |
| 		name = parts[len(parts)-1]
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // getPkg returns the package for a given path. If the package is
 | |
| // not found but we have a package name, create the package and
 | |
| // add it to the p.imports map.
 | |
| //
 | |
| func (p *parser) getPkg(pkgpath, name string) *types.Package {
 | |
| 	// package unsafe is not in the imports map - handle explicitly
 | |
| 	if pkgpath == "unsafe" {
 | |
| 		return types.Unsafe
 | |
| 	}
 | |
| 	pkg := p.imports[pkgpath]
 | |
| 	if pkg == nil && name != "" {
 | |
| 		pkg = types.NewPackage(pkgpath, name)
 | |
| 		p.imports[pkgpath] = pkg
 | |
| 	}
 | |
| 	return pkg
 | |
| }
 | |
| 
 | |
| // parseExportedName is like parseQualifiedName, but
 | |
| // the package path is resolved to an imported *types.Package.
 | |
| //
 | |
| // ExportedName = string [string] .
 | |
| func (p *parser) parseExportedName() (pkg *types.Package, name string) {
 | |
| 	path, name := p.parseQualifiedName()
 | |
| 	var pkgname string
 | |
| 	if p.tok == scanner.String {
 | |
| 		pkgname = p.parseString()
 | |
| 	}
 | |
| 	pkg = p.getPkg(path, pkgname)
 | |
| 	if pkg == nil {
 | |
| 		p.errorf("package %s (path = %q) not found", name, path)
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Name = QualifiedName | "?" .
 | |
| func (p *parser) parseName() string {
 | |
| 	if p.tok == '?' {
 | |
| 		// Anonymous.
 | |
| 		p.next()
 | |
| 		return ""
 | |
| 	}
 | |
| 	// The package path is redundant for us. Don't try to parse it.
 | |
| 	_, name := p.parseUnquotedQualifiedName()
 | |
| 	return name
 | |
| }
 | |
| 
 | |
| func deref(typ types.Type) types.Type {
 | |
| 	if p, _ := typ.(*types.Pointer); p != nil {
 | |
| 		typ = p.Elem()
 | |
| 	}
 | |
| 	return typ
 | |
| }
 | |
| 
 | |
| // Field = Name Type [string] .
 | |
| func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
 | |
| 	name := p.parseName()
 | |
| 	typ := p.parseType(pkg)
 | |
| 	anon := false
 | |
| 	if name == "" {
 | |
| 		anon = true
 | |
| 		switch typ := deref(typ).(type) {
 | |
| 		case *types.Basic:
 | |
| 			name = typ.Name()
 | |
| 		case *types.Named:
 | |
| 			name = typ.Obj().Name()
 | |
| 		default:
 | |
| 			p.error("anonymous field expected")
 | |
| 		}
 | |
| 	}
 | |
| 	field = types.NewField(token.NoPos, pkg, name, typ, anon)
 | |
| 	if p.tok == scanner.String {
 | |
| 		tag = p.parseString()
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Param = Name ["..."] Type .
 | |
| func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) {
 | |
| 	name := p.parseName()
 | |
| 	if p.tok == '<' && p.scanner.Peek() == 'e' {
 | |
| 		// EscInfo = "<esc:" int ">" . (optional and ignored)
 | |
| 		p.next()
 | |
| 		p.expectKeyword("esc")
 | |
| 		p.expect(':')
 | |
| 		p.expect(scanner.Int)
 | |
| 		p.expect('>')
 | |
| 	}
 | |
| 	if p.tok == '.' {
 | |
| 		p.next()
 | |
| 		p.expect('.')
 | |
| 		p.expect('.')
 | |
| 		isVariadic = true
 | |
| 	}
 | |
| 	typ := p.parseType(pkg)
 | |
| 	if isVariadic {
 | |
| 		typ = types.NewSlice(typ)
 | |
| 	}
 | |
| 	param = types.NewParam(token.NoPos, pkg, name, typ)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Var = Name Type .
 | |
| func (p *parser) parseVar(pkg *types.Package) *types.Var {
 | |
| 	name := p.parseName()
 | |
| 	return types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
 | |
| }
 | |
| 
 | |
| // Conversion = "convert" "(" Type "," ConstValue ")" .
 | |
| func (p *parser) parseConversion(pkg *types.Package) (val constant.Value, typ types.Type) {
 | |
| 	p.expectKeyword("convert")
 | |
| 	p.expect('(')
 | |
| 	typ = p.parseType(pkg)
 | |
| 	p.expect(',')
 | |
| 	val, _ = p.parseConstValue(pkg)
 | |
| 	p.expect(')')
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // ConstValue     = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) | Conversion .
 | |
| // FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
 | |
| func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ types.Type) {
 | |
| 	switch p.tok {
 | |
| 	case scanner.String:
 | |
| 		str := p.parseString()
 | |
| 		val = constant.MakeString(str)
 | |
| 		typ = types.Typ[types.UntypedString]
 | |
| 		return
 | |
| 
 | |
| 	case scanner.Ident:
 | |
| 		b := false
 | |
| 		switch p.lit {
 | |
| 		case "false":
 | |
| 		case "true":
 | |
| 			b = true
 | |
| 
 | |
| 		case "convert":
 | |
| 			return p.parseConversion(pkg)
 | |
| 
 | |
| 		default:
 | |
| 			p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
 | |
| 		}
 | |
| 
 | |
| 		p.next()
 | |
| 		val = constant.MakeBool(b)
 | |
| 		typ = types.Typ[types.UntypedBool]
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	sign := ""
 | |
| 	if p.tok == '-' {
 | |
| 		p.next()
 | |
| 		sign = "-"
 | |
| 	}
 | |
| 
 | |
| 	switch p.tok {
 | |
| 	case scanner.Int:
 | |
| 		val = constant.MakeFromLiteral(sign+p.lit, token.INT, 0)
 | |
| 		if val == nil {
 | |
| 			p.error("could not parse integer literal")
 | |
| 		}
 | |
| 
 | |
| 		p.next()
 | |
| 		if p.tok == '\'' {
 | |
| 			p.next()
 | |
| 			typ = types.Typ[types.UntypedRune]
 | |
| 		} else {
 | |
| 			typ = types.Typ[types.UntypedInt]
 | |
| 		}
 | |
| 
 | |
| 	case scanner.Float:
 | |
| 		re := sign + p.lit
 | |
| 		p.next()
 | |
| 
 | |
| 		var im string
 | |
| 		switch p.tok {
 | |
| 		case '+':
 | |
| 			p.next()
 | |
| 			im = p.expect(scanner.Float)
 | |
| 
 | |
| 		case '-':
 | |
| 			p.next()
 | |
| 			im = "-" + p.expect(scanner.Float)
 | |
| 
 | |
| 		case scanner.Ident:
 | |
| 			// re is in fact the imaginary component. Expect "i" below.
 | |
| 			im = re
 | |
| 			re = "0"
 | |
| 
 | |
| 		default:
 | |
| 			val = constant.MakeFromLiteral(re, token.FLOAT, 0)
 | |
| 			if val == nil {
 | |
| 				p.error("could not parse float literal")
 | |
| 			}
 | |
| 			typ = types.Typ[types.UntypedFloat]
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		p.expectKeyword("i")
 | |
| 		reval := constant.MakeFromLiteral(re, token.FLOAT, 0)
 | |
| 		if reval == nil {
 | |
| 			p.error("could not parse real component of complex literal")
 | |
| 		}
 | |
| 		imval := constant.MakeFromLiteral(im+"i", token.IMAG, 0)
 | |
| 		if imval == nil {
 | |
| 			p.error("could not parse imag component of complex literal")
 | |
| 		}
 | |
| 		val = constant.BinaryOp(reval, token.ADD, imval)
 | |
| 		typ = types.Typ[types.UntypedComplex]
 | |
| 
 | |
| 	default:
 | |
| 		p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
 | |
| 	}
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Const = Name [Type] "=" ConstValue .
 | |
| func (p *parser) parseConst(pkg *types.Package) *types.Const {
 | |
| 	name := p.parseName()
 | |
| 	var typ types.Type
 | |
| 	if p.tok == '<' {
 | |
| 		typ = p.parseType(pkg)
 | |
| 	}
 | |
| 	p.expect('=')
 | |
| 	val, vtyp := p.parseConstValue(pkg)
 | |
| 	if typ == nil {
 | |
| 		typ = vtyp
 | |
| 	}
 | |
| 	return types.NewConst(token.NoPos, pkg, name, typ, val)
 | |
| }
 | |
| 
 | |
| // reserved is a singleton type used to fill type map slots that have
 | |
| // been reserved (i.e., for which a type number has been parsed) but
 | |
| // which don't have their actual type yet. When the type map is updated,
 | |
| // the actual type must replace a reserved entry (or we have an internal
 | |
| // error). Used for self-verification only - not required for correctness.
 | |
| var reserved = new(struct{ types.Type })
 | |
| 
 | |
| // reserve reserves the type map entry n for future use.
 | |
| func (p *parser) reserve(n int) {
 | |
| 	if n != len(p.typeList) {
 | |
| 		p.errorf("invalid type number %d (out of sync)", n)
 | |
| 	}
 | |
| 	p.typeList = append(p.typeList, reserved)
 | |
| }
 | |
| 
 | |
| // update sets the type map entries for the given type numbers nlist to t.
 | |
| func (p *parser) update(t types.Type, nlist []int) {
 | |
| 	for _, n := range nlist {
 | |
| 		if p.typeList[n] != reserved {
 | |
| 			p.errorf("typeMap[%d] not reserved", n)
 | |
| 		}
 | |
| 		p.typeList[n] = t
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NamedType = TypeName [ "=" ] Type { Method } .
 | |
| // TypeName  = ExportedName .
 | |
| // Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
 | |
| func (p *parser) parseNamedType(nlist []int) types.Type {
 | |
| 	pkg, name := p.parseExportedName()
 | |
| 	scope := pkg.Scope()
 | |
| 	obj := scope.Lookup(name)
 | |
| 	if obj != nil && obj.Type() == nil {
 | |
| 		p.errorf("%v has nil type", obj)
 | |
| 	}
 | |
| 
 | |
| 	// type alias
 | |
| 	if p.tok == '=' {
 | |
| 		p.next()
 | |
| 		if obj != nil {
 | |
| 			// use the previously imported (canonical) type
 | |
| 			t := obj.Type()
 | |
| 			p.update(t, nlist)
 | |
| 			p.parseType(pkg) // discard
 | |
| 			return t
 | |
| 		}
 | |
| 		t := p.parseType(pkg, nlist...)
 | |
| 		obj = types.NewTypeName(token.NoPos, pkg, name, t)
 | |
| 		scope.Insert(obj)
 | |
| 		return t
 | |
| 	}
 | |
| 
 | |
| 	// defined type
 | |
| 	if obj == nil {
 | |
| 		// A named type may be referred to before the underlying type
 | |
| 		// is known - set it up.
 | |
| 		tname := types.NewTypeName(token.NoPos, pkg, name, nil)
 | |
| 		types.NewNamed(tname, nil, nil)
 | |
| 		scope.Insert(tname)
 | |
| 		obj = tname
 | |
| 	}
 | |
| 
 | |
| 	// use the previously imported (canonical), or newly created type
 | |
| 	t := obj.Type()
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	nt, ok := t.(*types.Named)
 | |
| 	if !ok {
 | |
| 		// This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
 | |
| 		pt := p.parseType(pkg)
 | |
| 		if pt != t {
 | |
| 			p.error("unexpected underlying type for non-named TypeName")
 | |
| 		}
 | |
| 		return t
 | |
| 	}
 | |
| 
 | |
| 	underlying := p.parseType(pkg)
 | |
| 	if nt.Underlying() == nil {
 | |
| 		nt.SetUnderlying(underlying.Underlying())
 | |
| 	}
 | |
| 
 | |
| 	// collect associated methods
 | |
| 	for p.tok == scanner.Ident {
 | |
| 		p.expectKeyword("func")
 | |
| 		p.expect('(')
 | |
| 		receiver, _ := p.parseParam(pkg)
 | |
| 		p.expect(')')
 | |
| 		name := p.parseName()
 | |
| 		params, isVariadic := p.parseParamList(pkg)
 | |
| 		results := p.parseResultList(pkg)
 | |
| 		p.expect(';')
 | |
| 
 | |
| 		sig := types.NewSignature(receiver, params, results, isVariadic)
 | |
| 		nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
 | |
| 	}
 | |
| 
 | |
| 	return nt
 | |
| }
 | |
| 
 | |
| func (p *parser) parseInt64() int64 {
 | |
| 	lit := p.expect(scanner.Int)
 | |
| 	n, err := strconv.ParseInt(lit, 10, 64)
 | |
| 	if err != nil {
 | |
| 		p.error(err)
 | |
| 	}
 | |
| 	return n
 | |
| }
 | |
| 
 | |
| func (p *parser) parseInt() int {
 | |
| 	lit := p.expect(scanner.Int)
 | |
| 	n, err := strconv.ParseInt(lit, 10, 0 /* int */)
 | |
| 	if err != nil {
 | |
| 		p.error(err)
 | |
| 	}
 | |
| 	return int(n)
 | |
| }
 | |
| 
 | |
| // ArrayOrSliceType = "[" [ int ] "]" Type .
 | |
| func (p *parser) parseArrayOrSliceType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expect('[')
 | |
| 	if p.tok == ']' {
 | |
| 		p.next()
 | |
| 
 | |
| 		t := new(types.Slice)
 | |
| 		p.update(t, nlist)
 | |
| 
 | |
| 		*t = *types.NewSlice(p.parseType(pkg))
 | |
| 		return t
 | |
| 	}
 | |
| 
 | |
| 	t := new(types.Array)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	len := p.parseInt64()
 | |
| 	p.expect(']')
 | |
| 
 | |
| 	*t = *types.NewArray(p.parseType(pkg), len)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // MapType = "map" "[" Type "]" Type .
 | |
| func (p *parser) parseMapType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expectKeyword("map")
 | |
| 
 | |
| 	t := new(types.Map)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	p.expect('[')
 | |
| 	key := p.parseType(pkg)
 | |
| 	p.expect(']')
 | |
| 	elem := p.parseType(pkg)
 | |
| 
 | |
| 	*t = *types.NewMap(key, elem)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // ChanType = "chan" ["<-" | "-<"] Type .
 | |
| func (p *parser) parseChanType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expectKeyword("chan")
 | |
| 
 | |
| 	t := new(types.Chan)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	dir := types.SendRecv
 | |
| 	switch p.tok {
 | |
| 	case '-':
 | |
| 		p.next()
 | |
| 		p.expect('<')
 | |
| 		dir = types.SendOnly
 | |
| 
 | |
| 	case '<':
 | |
| 		// don't consume '<' if it belongs to Type
 | |
| 		if p.scanner.Peek() == '-' {
 | |
| 			p.next()
 | |
| 			p.expect('-')
 | |
| 			dir = types.RecvOnly
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	*t = *types.NewChan(dir, p.parseType(pkg))
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // StructType = "struct" "{" { Field } "}" .
 | |
| func (p *parser) parseStructType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expectKeyword("struct")
 | |
| 
 | |
| 	t := new(types.Struct)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	var fields []*types.Var
 | |
| 	var tags []string
 | |
| 
 | |
| 	p.expect('{')
 | |
| 	for p.tok != '}' && p.tok != scanner.EOF {
 | |
| 		field, tag := p.parseField(pkg)
 | |
| 		p.expect(';')
 | |
| 		fields = append(fields, field)
 | |
| 		tags = append(tags, tag)
 | |
| 	}
 | |
| 	p.expect('}')
 | |
| 
 | |
| 	*t = *types.NewStruct(fields, tags)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // ParamList = "(" [ { Parameter "," } Parameter ] ")" .
 | |
| func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
 | |
| 	var list []*types.Var
 | |
| 	isVariadic := false
 | |
| 
 | |
| 	p.expect('(')
 | |
| 	for p.tok != ')' && p.tok != scanner.EOF {
 | |
| 		if len(list) > 0 {
 | |
| 			p.expect(',')
 | |
| 		}
 | |
| 		par, variadic := p.parseParam(pkg)
 | |
| 		list = append(list, par)
 | |
| 		if variadic {
 | |
| 			if isVariadic {
 | |
| 				p.error("... not on final argument")
 | |
| 			}
 | |
| 			isVariadic = true
 | |
| 		}
 | |
| 	}
 | |
| 	p.expect(')')
 | |
| 
 | |
| 	return types.NewTuple(list...), isVariadic
 | |
| }
 | |
| 
 | |
| // ResultList = Type | ParamList .
 | |
| func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
 | |
| 	switch p.tok {
 | |
| 	case '<':
 | |
| 		return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg)))
 | |
| 
 | |
| 	case '(':
 | |
| 		params, _ := p.parseParamList(pkg)
 | |
| 		return params
 | |
| 
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // FunctionType = ParamList ResultList .
 | |
| func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signature {
 | |
| 	t := new(types.Signature)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	params, isVariadic := p.parseParamList(pkg)
 | |
| 	results := p.parseResultList(pkg)
 | |
| 
 | |
| 	*t = *types.NewSignature(nil, params, results, isVariadic)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // Func = Name FunctionType .
 | |
| func (p *parser) parseFunc(pkg *types.Package) *types.Func {
 | |
| 	name := p.parseName()
 | |
| 	if strings.ContainsRune(name, '$') {
 | |
| 		// This is a Type$equal or Type$hash function, which we don't want to parse,
 | |
| 		// except for the types.
 | |
| 		p.discardDirectiveWhileParsingTypes(pkg)
 | |
| 		return nil
 | |
| 	}
 | |
| 	return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil))
 | |
| }
 | |
| 
 | |
| // InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
 | |
| func (p *parser) parseInterfaceType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expectKeyword("interface")
 | |
| 
 | |
| 	t := new(types.Interface)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	var methods []*types.Func
 | |
| 	var embeddeds []types.Type
 | |
| 
 | |
| 	p.expect('{')
 | |
| 	for p.tok != '}' && p.tok != scanner.EOF {
 | |
| 		if p.tok == '?' {
 | |
| 			p.next()
 | |
| 			embeddeds = append(embeddeds, p.parseType(pkg))
 | |
| 		} else {
 | |
| 			method := p.parseFunc(pkg)
 | |
| 			methods = append(methods, method)
 | |
| 		}
 | |
| 		p.expect(';')
 | |
| 	}
 | |
| 	p.expect('}')
 | |
| 
 | |
| 	*t = *newInterface(methods, embeddeds)
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // PointerType = "*" ("any" | Type) .
 | |
| func (p *parser) parsePointerType(pkg *types.Package, nlist []int) types.Type {
 | |
| 	p.expect('*')
 | |
| 	if p.tok == scanner.Ident {
 | |
| 		p.expectKeyword("any")
 | |
| 		t := types.Typ[types.UnsafePointer]
 | |
| 		p.update(t, nlist)
 | |
| 		return t
 | |
| 	}
 | |
| 
 | |
| 	t := new(types.Pointer)
 | |
| 	p.update(t, nlist)
 | |
| 
 | |
| 	*t = *types.NewPointer(p.parseType(pkg))
 | |
| 
 | |
| 	return t
 | |
| }
 | |
| 
 | |
| // TypeSpec = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType .
 | |
| func (p *parser) parseTypeSpec(pkg *types.Package, nlist []int) types.Type {
 | |
| 	switch p.tok {
 | |
| 	case scanner.String:
 | |
| 		return p.parseNamedType(nlist)
 | |
| 
 | |
| 	case scanner.Ident:
 | |
| 		switch p.lit {
 | |
| 		case "map":
 | |
| 			return p.parseMapType(pkg, nlist)
 | |
| 
 | |
| 		case "chan":
 | |
| 			return p.parseChanType(pkg, nlist)
 | |
| 
 | |
| 		case "struct":
 | |
| 			return p.parseStructType(pkg, nlist)
 | |
| 
 | |
| 		case "interface":
 | |
| 			return p.parseInterfaceType(pkg, nlist)
 | |
| 		}
 | |
| 
 | |
| 	case '*':
 | |
| 		return p.parsePointerType(pkg, nlist)
 | |
| 
 | |
| 	case '[':
 | |
| 		return p.parseArrayOrSliceType(pkg, nlist)
 | |
| 
 | |
| 	case '(':
 | |
| 		return p.parseFunctionType(pkg, nlist)
 | |
| 	}
 | |
| 
 | |
| 	p.errorf("expected type name or literal, got %s", scanner.TokenString(p.tok))
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// From gofrontend/go/export.h
 | |
| 	// Note that these values are negative in the gofrontend and have been made positive
 | |
| 	// in the gccgoimporter.
 | |
| 	gccgoBuiltinINT8       = 1
 | |
| 	gccgoBuiltinINT16      = 2
 | |
| 	gccgoBuiltinINT32      = 3
 | |
| 	gccgoBuiltinINT64      = 4
 | |
| 	gccgoBuiltinUINT8      = 5
 | |
| 	gccgoBuiltinUINT16     = 6
 | |
| 	gccgoBuiltinUINT32     = 7
 | |
| 	gccgoBuiltinUINT64     = 8
 | |
| 	gccgoBuiltinFLOAT32    = 9
 | |
| 	gccgoBuiltinFLOAT64    = 10
 | |
| 	gccgoBuiltinINT        = 11
 | |
| 	gccgoBuiltinUINT       = 12
 | |
| 	gccgoBuiltinUINTPTR    = 13
 | |
| 	gccgoBuiltinBOOL       = 15
 | |
| 	gccgoBuiltinSTRING     = 16
 | |
| 	gccgoBuiltinCOMPLEX64  = 17
 | |
| 	gccgoBuiltinCOMPLEX128 = 18
 | |
| 	gccgoBuiltinERROR      = 19
 | |
| 	gccgoBuiltinBYTE       = 20
 | |
| 	gccgoBuiltinRUNE       = 21
 | |
| )
 | |
| 
 | |
| func lookupBuiltinType(typ int) types.Type {
 | |
| 	return [...]types.Type{
 | |
| 		gccgoBuiltinINT8:       types.Typ[types.Int8],
 | |
| 		gccgoBuiltinINT16:      types.Typ[types.Int16],
 | |
| 		gccgoBuiltinINT32:      types.Typ[types.Int32],
 | |
| 		gccgoBuiltinINT64:      types.Typ[types.Int64],
 | |
| 		gccgoBuiltinUINT8:      types.Typ[types.Uint8],
 | |
| 		gccgoBuiltinUINT16:     types.Typ[types.Uint16],
 | |
| 		gccgoBuiltinUINT32:     types.Typ[types.Uint32],
 | |
| 		gccgoBuiltinUINT64:     types.Typ[types.Uint64],
 | |
| 		gccgoBuiltinFLOAT32:    types.Typ[types.Float32],
 | |
| 		gccgoBuiltinFLOAT64:    types.Typ[types.Float64],
 | |
| 		gccgoBuiltinINT:        types.Typ[types.Int],
 | |
| 		gccgoBuiltinUINT:       types.Typ[types.Uint],
 | |
| 		gccgoBuiltinUINTPTR:    types.Typ[types.Uintptr],
 | |
| 		gccgoBuiltinBOOL:       types.Typ[types.Bool],
 | |
| 		gccgoBuiltinSTRING:     types.Typ[types.String],
 | |
| 		gccgoBuiltinCOMPLEX64:  types.Typ[types.Complex64],
 | |
| 		gccgoBuiltinCOMPLEX128: types.Typ[types.Complex128],
 | |
| 		gccgoBuiltinERROR:      types.Universe.Lookup("error").Type(),
 | |
| 		gccgoBuiltinBYTE:       types.Universe.Lookup("byte").Type(),
 | |
| 		gccgoBuiltinRUNE:       types.Universe.Lookup("rune").Type(),
 | |
| 	}[typ]
 | |
| }
 | |
| 
 | |
| // Type = "<" "type" ( "-" int | int [ TypeSpec ] ) ">" .
 | |
| //
 | |
| // parseType updates the type map to t for all type numbers n.
 | |
| //
 | |
| func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) {
 | |
| 	p.expect('<')
 | |
| 	p.expectKeyword("type")
 | |
| 
 | |
| 	switch p.tok {
 | |
| 	case scanner.Int:
 | |
| 		n1 := p.parseInt()
 | |
| 		if p.tok == '>' {
 | |
| 			t = p.typeList[n1]
 | |
| 			if t == reserved {
 | |
| 				p.errorf("invalid type cycle, type %d not yet defined", n1)
 | |
| 			}
 | |
| 			p.update(t, n)
 | |
| 		} else {
 | |
| 			p.reserve(n1)
 | |
| 			t = p.parseTypeSpec(pkg, append(n, n1))
 | |
| 		}
 | |
| 
 | |
| 	case '-':
 | |
| 		p.next()
 | |
| 		n1 := p.parseInt()
 | |
| 		t = lookupBuiltinType(n1)
 | |
| 		p.update(t, n)
 | |
| 
 | |
| 	default:
 | |
| 		p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit)
 | |
| 	}
 | |
| 
 | |
| 	p.expect('>')
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // PackageInit = unquotedString unquotedString int .
 | |
| func (p *parser) parsePackageInit() PackageInit {
 | |
| 	name := p.parseUnquotedString()
 | |
| 	initfunc := p.parseUnquotedString()
 | |
| 	priority := -1
 | |
| 	if p.version == "v1" {
 | |
| 		priority = p.parseInt()
 | |
| 	}
 | |
| 	return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
 | |
| }
 | |
| 
 | |
| // Throw away tokens until we see a ';'. If we see a '<', attempt to parse as a type.
 | |
| func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
 | |
| 	for {
 | |
| 		switch p.tok {
 | |
| 		case ';':
 | |
| 			return
 | |
| 		case '<':
 | |
| 			p.parseType(pkg)
 | |
| 		case scanner.EOF:
 | |
| 			p.error("unexpected EOF")
 | |
| 		default:
 | |
| 			p.next()
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Create the package if we have parsed both the package path and package name.
 | |
| func (p *parser) maybeCreatePackage() {
 | |
| 	if p.pkgname != "" && p.pkgpath != "" {
 | |
| 		p.pkg = p.getPkg(p.pkgpath, p.pkgname)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // InitDataDirective = ( "v1" | "v2" ) ";" |
 | |
| //                     "priority" int ";" |
 | |
| //                     "init" { PackageInit } ";" |
 | |
| //                     "checksum" unquotedString ";" .
 | |
| func (p *parser) parseInitDataDirective() {
 | |
| 	if p.tok != scanner.Ident {
 | |
| 		// unexpected token kind; panic
 | |
| 		p.expect(scanner.Ident)
 | |
| 	}
 | |
| 
 | |
| 	switch p.lit {
 | |
| 	case "v1", "v2":
 | |
| 		p.version = p.lit
 | |
| 		p.next()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "priority":
 | |
| 		p.next()
 | |
| 		p.initdata.Priority = p.parseInt()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "init":
 | |
| 		p.next()
 | |
| 		for p.tok != ';' && p.tok != scanner.EOF {
 | |
| 			p.initdata.Inits = append(p.initdata.Inits, p.parsePackageInit())
 | |
| 		}
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "init_graph":
 | |
| 		p.next()
 | |
| 		// The graph data is thrown away for now.
 | |
| 		for p.tok != ';' && p.tok != scanner.EOF {
 | |
| 			p.parseInt64()
 | |
| 			p.parseInt64()
 | |
| 		}
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "checksum":
 | |
| 		// Don't let the scanner try to parse the checksum as a number.
 | |
| 		defer func(mode uint) {
 | |
| 			p.scanner.Mode = mode
 | |
| 		}(p.scanner.Mode)
 | |
| 		p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats
 | |
| 		p.next()
 | |
| 		p.parseUnquotedString()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	default:
 | |
| 		p.errorf("unexpected identifier: %q", p.lit)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Directive = InitDataDirective |
 | |
| //             "package" unquotedString [ unquotedString ] [ unquotedString ] ";" |
 | |
| //             "pkgpath" unquotedString ";" |
 | |
| //             "prefix" unquotedString ";" |
 | |
| //             "import" unquotedString unquotedString string ";" |
 | |
| //             "func" Func ";" |
 | |
| //             "type" Type ";" |
 | |
| //             "var" Var ";" |
 | |
| //             "const" Const ";" .
 | |
| func (p *parser) parseDirective() {
 | |
| 	if p.tok != scanner.Ident {
 | |
| 		// unexpected token kind; panic
 | |
| 		p.expect(scanner.Ident)
 | |
| 	}
 | |
| 
 | |
| 	switch p.lit {
 | |
| 	case "v1", "v2", "priority", "init", "init_graph", "checksum":
 | |
| 		p.parseInitDataDirective()
 | |
| 
 | |
| 	case "package":
 | |
| 		p.next()
 | |
| 		p.pkgname = p.parseUnquotedString()
 | |
| 		p.maybeCreatePackage()
 | |
| 		if p.version == "v2" && p.tok != ';' {
 | |
| 			p.parseUnquotedString()
 | |
| 			p.parseUnquotedString()
 | |
| 		}
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "pkgpath":
 | |
| 		p.next()
 | |
| 		p.pkgpath = p.parseUnquotedString()
 | |
| 		p.maybeCreatePackage()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "prefix":
 | |
| 		p.next()
 | |
| 		p.pkgpath = p.parseUnquotedString()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "import":
 | |
| 		p.next()
 | |
| 		pkgname := p.parseUnquotedString()
 | |
| 		pkgpath := p.parseUnquotedString()
 | |
| 		p.getPkg(pkgpath, pkgname)
 | |
| 		p.parseString()
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "func":
 | |
| 		p.next()
 | |
| 		fun := p.parseFunc(p.pkg)
 | |
| 		if fun != nil {
 | |
| 			p.pkg.Scope().Insert(fun)
 | |
| 		}
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "type":
 | |
| 		p.next()
 | |
| 		p.parseType(p.pkg)
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "var":
 | |
| 		p.next()
 | |
| 		v := p.parseVar(p.pkg)
 | |
| 		p.pkg.Scope().Insert(v)
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	case "const":
 | |
| 		p.next()
 | |
| 		c := p.parseConst(p.pkg)
 | |
| 		p.pkg.Scope().Insert(c)
 | |
| 		p.expect(';')
 | |
| 
 | |
| 	default:
 | |
| 		p.errorf("unexpected identifier: %q", p.lit)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Package = { Directive } .
 | |
| func (p *parser) parsePackage() *types.Package {
 | |
| 	for p.tok != scanner.EOF {
 | |
| 		p.parseDirective()
 | |
| 	}
 | |
| 	for _, typ := range p.typeList {
 | |
| 		if it, ok := typ.(*types.Interface); ok {
 | |
| 			it.Complete()
 | |
| 		}
 | |
| 	}
 | |
| 	p.pkg.MarkComplete()
 | |
| 	return p.pkg
 | |
| }
 |