Skip to content

Commit

Permalink
go/internal/gccgoimporter: additional V3 export data changes
Browse files Browse the repository at this point in the history
This patch merges in support for reading the most recent
incarnation of V3 export data (initial inline function bodies),
from the importer portions of https://golang.org/cl/150061 and
https://golang.org/cl/150067.

Updates #28961.

Change-Id: I34e837acbf48b8fd1a4896a1a977d2241adfb28d
Reviewed-on: https://go-review.googlesource.com/c/151557
Run-TryBot: Than McIntosh <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
Reviewed-by: Cherry Zhang <[email protected]>
  • Loading branch information
thanm committed Nov 29, 2018
1 parent 2b58ca6 commit 70a684c
Showing 1 changed file with 66 additions and 6 deletions.
72 changes: 66 additions & 6 deletions src/go/internal/gccgoimporter/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"strconv"
"strings"
"text/scanner"
"unicode/utf8"
)

type parser struct {
Expand All @@ -41,7 +42,7 @@ func (p *parser) init(filename string, src io.Reader, imports map[string]*types.
func (p *parser) initScanner(filename string, src io.Reader) {
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.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings
p.scanner.Whitespace = 1<<'\t' | 1<<' '
p.scanner.Filename = filename // for good error messages
p.next()
Expand Down Expand Up @@ -281,6 +282,15 @@ func (p *parser) parseConversion(pkg *types.Package) (val constant.Value, typ ty
// 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) {
// v3 changed to $false, $true, $convert, to avoid confusion
// with variable names in inline function bodies.
if p.tok == '$' {
p.next()
if p.tok != scanner.Ident {
p.errorf("expected identifer after '$', got %s (%q)", scanner.TokenString(p.tok), p.lit)
}
}

switch p.tok {
case scanner.String:
str := p.parseString()
Expand Down Expand Up @@ -443,7 +453,7 @@ func (p *parser) update(t types.Type, nlist []int) {

// NamedType = TypeName [ "=" ] Type { Method } .
// TypeName = ExportedName .
// Method = "func" "(" Param ")" Name ParamList ResultList ";" .
// Method = "func" "(" Param ")" Name ParamList ResultList [InlineBody] ";" .
func (p *parser) parseNamedType(nlist []int) types.Type {
pkg, name := p.parseExportedName()
scope := pkg.Scope()
Expand Down Expand Up @@ -508,6 +518,7 @@ func (p *parser) parseNamedType(nlist []int) types.Type {
name := p.parseName()
params, isVariadic := p.parseParamList(pkg)
results := p.parseResultList(pkg)
p.skipInlineBody()
p.expectEOL()

sig := types.NewSignature(receiver, params, results, isVariadic)
Expand Down Expand Up @@ -653,7 +664,11 @@ func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
switch p.tok {
case '<':
return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg)))
p.next()
if p.tok == scanner.Ident && p.lit == "inl" {
return nil
}
return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseTypeAfterAngle(pkg)))

case '(':
params, _ := p.parseParamList(pkg)
Expand All @@ -676,7 +691,7 @@ func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signa
return t
}

// Func = Name FunctionType .
// Func = Name FunctionType [InlineBody] .
func (p *parser) parseFunc(pkg *types.Package) *types.Func {
name := p.parseName()
if strings.ContainsRune(name, '$') {
Expand All @@ -685,7 +700,9 @@ func (p *parser) parseFunc(pkg *types.Package) *types.Func {
p.discardDirectiveWhileParsingTypes(pkg)
return nil
}
return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil))
f := types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil))
p.skipInlineBody()
return f
}

// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
Expand Down Expand Up @@ -823,8 +840,13 @@ func lookupBuiltinType(typ int) types.Type {
//
// parseType updates the type map to t for all type numbers n.
//
func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) {
func (p *parser) parseType(pkg *types.Package, n ...int) types.Type {
p.expect('<')
return p.parseTypeAfterAngle(pkg, n...)
}

// (*parser).Type after reading the "<".
func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...int) (t types.Type) {
p.expectKeyword("type")

switch p.tok {
Expand Down Expand Up @@ -863,6 +885,39 @@ func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) {
return
}

// InlineBody = "<inl:NN>" .{NN}
// Reports whether a body was skipped.
func (p *parser) skipInlineBody() {
// We may or may not have seen the '<' already, depending on
// whether the function had a result type or not.
if p.tok == '<' {
p.next()
p.expectKeyword("inl")
} else if p.tok != scanner.Ident || p.lit != "inl" {
return
} else {
p.next()
}

p.expect(':')
want := p.parseInt()
p.expect('>')

defer func(w uint64) {
p.scanner.Whitespace = w
}(p.scanner.Whitespace)
p.scanner.Whitespace = 0

got := 0
for got < want {
r := p.scanner.Next()
if r == scanner.EOF {
p.error("unexpected EOF")
}
got += utf8.RuneLen(r)
}
}

// Types = "types" maxp1 exportedp1 (offset length)* .
func (p *parser) parseTypes(pkg *types.Package) {
maxp1 := p.parseInt()
Expand All @@ -882,6 +937,11 @@ func (p *parser) parseTypes(pkg *types.Package) {
total += len
}

defer func(w uint64) {
p.scanner.Whitespace = w
}(p.scanner.Whitespace)
p.scanner.Whitespace = 0

// We should now have p.tok pointing to the final newline.
// The next runes from the scanner should be the type data.

Expand Down

0 comments on commit 70a684c

Please sign in to comment.