From 1e4cc1d4b097f346b4cda611782fe83eda0df18f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 26 Nov 2018 21:44:20 +0000 Subject: compiler: initial support for exporting function bodies Create a framework for putting function bodies in export data. At present only empty functions will be put there, and they will be ignored on import. Later patches will get this to the point of supporting inlining of (some) functions defined in other packages. Reviewed-on: https://go-review.googlesource.com/c/150061 From-SVN: r266490 --- libgo/go/go/internal/gccgoimporter/parser.go | 63 +++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'libgo') diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go index dc61e4c..c23002f 100644 --- a/libgo/go/go/internal/gccgoimporter/parser.go +++ b/libgo/go/go/internal/gccgoimporter/parser.go @@ -15,6 +15,7 @@ import ( "strconv" "strings" "text/scanner" + "unicode/utf8" ) type parser struct { @@ -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() @@ -393,7 +394,7 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const { // NamedType = TypeName [ "=" ] Type { Method } . // TypeName = ExportedName . -// Method = "func" "(" Param ")" Name ParamList ResultList ";" . +// Method = "func" "(" Param ")" Name ParamList ResultList [InlineBody] ";" . func (p *parser) parseNamedType(n int) types.Type { pkg, name := p.parseExportedName() scope := pkg.Scope() @@ -455,6 +456,7 @@ func (p *parser) parseNamedType(n 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) @@ -566,7 +568,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) @@ -584,7 +590,7 @@ func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature { return types.NewSignature(nil, params, results, isVariadic) } -// Func = Name FunctionType . +// Func = Name FunctionType [InlineBody] . func (p *parser) parseFunc(pkg *types.Package) *types.Func { name := p.parseName() if strings.ContainsRune(name, '$') { @@ -593,7 +599,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)) + f := types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg)) + p.skipInlineBody() + return f } // InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" . @@ -717,8 +725,13 @@ func lookupBuiltinType(typ int) types.Type { } // Type = "<" "type" ( "-" int | int [ TypeDefinition ] ) ">" . -func (p *parser) parseType(pkg *types.Package) (t types.Type) { +func (p *parser) parseType(pkg *types.Package) types.Type { p.expect('<') + return p.parseTypeAfterAngle(pkg) +} + +// (*parser).Type after reading the "<". +func (p *parser) parseTypeAfterAngle(pkg *types.Package) (t types.Type) { p.expectKeyword("type") switch p.tok { @@ -748,6 +761,39 @@ func (p *parser) parseType(pkg *types.Package) (t types.Type) { return } +// InlineBody = "" .{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 := int64(0) + for got < want { + r := p.scanner.Next() + if r == scanner.EOF { + p.error("unexpected EOF") + } + got += int64(utf8.RuneLen(r)) + } +} + // Types = "types" maxp1 exportedp1 (offset length)* . func (p *parser) parseTypes(pkg *types.Package) { maxp1 := p.parseInt() @@ -766,6 +812,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. -- cgit v1.1