Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support function instruction #894

Merged
merged 3 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 2 additions & 90 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ package ast

import (
"go/ast"
"strings"

"github.com/goplus/gop/token"
)
Expand Down Expand Up @@ -56,99 +55,12 @@ type Decl interface {
// Comments

// A Comment node represents a single //-style 、#-style or /*-style comment.
type Comment struct {
Slash token.Pos // position of "/" or # starting the comment
Text string // comment text (excluding '\n' for //-style comments)
}

// Pos returns position of first character belonging to the node.
func (c *Comment) Pos() token.Pos { return c.Slash }

// End returns position of first character immediately after the node.
func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
type Comment = ast.Comment

// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
//
type CommentGroup struct {
List []*Comment // len(List) > 0
}

// Pos returns position of first character belonging to the node.
func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }

// End returns position of first character immediately after the node.
func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }

func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' }

func stripTrailingWhitespace(s string) string {
i := len(s)
for i > 0 && isWhitespace(s[i-1]) {
i--
}
return s[0:i]
}

// Text returns the text of the comment.
// Comment markers (//, /*, and */), the first space of a line comment, and
// leading and trailing empty lines are removed. Multiple empty lines are
// reduced to one, and trailing space on lines is trimmed. Unless the result
// is empty, it is newline-terminated.
//
func (g *CommentGroup) Text() string {
if g == nil {
return ""
}
comments := make([]string, len(g.List))
for i, c := range g.List {
comments[i] = c.Text
}

lines := make([]string, 0, 10) // most comments are less than 10 lines
for _, c := range comments {
// Remove comment markers.
// The parser has given us exactly the comment text.
switch c[1] {
case '/':
//-style comment (no newline at the end)
c = c[2:]
// strip first space - required for Example tests
if len(c) > 0 && c[0] == ' ' {
c = c[1:]
}
case '*':
/*-style comment */
c = c[2 : len(c)-2]
}

// Split on newlines.
cl := strings.Split(c, "\n")

// Walk lines, stripping trailing white space and adding to list.
for _, l := range cl {
lines = append(lines, stripTrailingWhitespace(l))
}
}

// Remove leading blank lines; convert runs of
// interior blank lines to a single blank line.
n := 0
for _, line := range lines {
if line != "" || n > 0 && lines[n-1] != "" {
lines[n] = line
n++
}
}
lines = lines[0:n]

// Add final "" entry to get trailing newline from Join.
if n > 0 && lines[n-1] != "" {
lines = append(lines, "")
}

return strings.Join(lines, "\n")
}
type CommentGroup = ast.CommentGroup

// ----------------------------------------------------------------------------
// Expressions and types
Expand Down
3 changes: 3 additions & 0 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,9 @@ func loadFunc(ctx *blockCtx, recv *types.Var, d *ast.FuncDecl) {
ctx.handleErr(err)
return
}
if d.Doc != nil {
fn.SetComments(d.Doc)
}
if body := d.Body; body != nil {
if recv != nil {
ctx.inits = append(ctx.inits, func() { // interface issue: #795
Expand Down
16 changes: 15 additions & 1 deletion cl/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func gopClTest(t *testing.T, gopcode, expected string, cachefile ...string) {
defer cl.SetDisableRecover(false)

fs := parsertest.NewSingleFileFS("/foo", "bar.gop", gopcode)
pkgs, err := parser.ParseFSDir(gblFset, fs, "/foo", nil, 0)
pkgs, err := parser.ParseFSDir(gblFset, fs, "/foo", nil, parser.ParseComments)
if err != nil {
scanner.PrintError(os.Stderr, err)
t.Fatal("ParseFSDir:", err)
Expand Down Expand Up @@ -3211,3 +3211,17 @@ func main() {
}
`)
}

func TestGoInstr(t *testing.T) {
gopClTest(t, `package main

//go:noinline
Copy link

@tandr tandr Nov 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you are testing the parser, it might be a good idea to add a case where go:something is not at the beginning for the comment, like // followed by the space // go:something, or end of the line comment with a:=0 //go:something, or it is a the beginning of /* comment

/*go:something
*/
func dummy() {}

etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx

//go:uintptrescapes
func test(s string, p, q uintptr, rest ...uintptr) int {
}`, `package main
//go:noinline
//go:uintptrescapes
func test(s string, p uintptr, q uintptr, rest ...uintptr) int {
}
`)
}
2 changes: 1 addition & 1 deletion cmd/gengo/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func (p *Runner) GenGoPkg(pkgDir string, base *cl.Config) (err error) {
if conf.Fset == nil {
conf.Fset = token.NewFileSet()
}
pkgs, err := parser.ParseDir(conf.Fset, pkgDir, nil, 0)
pkgs, err := parser.ParseDir(conf.Fset, pkgDir, nil, parser.ParseComments)
if err != nil {
return p.addError(pkgDir, "parse", err)
}
Expand Down
9 changes: 3 additions & 6 deletions cmd/goptestgo/goptestgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,11 @@ var (
"issue15071.dir": {}, // dir
"issue29612.dir": {},
"issue31959.dir": {},
"issue24491a.go": {}, // instruction
"issue24491b.go": {},
"issue29504.go": {},
"issue17381.go": {},
"issue29504.go": {}, // line
"issue18149.go": {},
"issue22662.go": {},
"issue27201.go": {},
"issue40954.go": {},
"issue40954.go": {}, // type instruction
"nilptr_aix.go": {},
"inline_literal.go": {},
"returntype.go": {}, // not a problem
Expand Down Expand Up @@ -99,7 +96,7 @@ func gopTestRunGo(dir string) {
return nil
}
log.Println("==> gop run -gop -v", file)
RunGopCmd("", "run", "-nr", "-gop", file)
RunGopCmd("", "run", "-nr", "-rtoe", "-gop", file)
return nil
})
}
Expand Down
22 changes: 20 additions & 2 deletions cmd/internal/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ var (
flagQuiet = flag.Bool("quiet", false, "don't generate any compiling stage log")
flagDebug = flag.Bool("debug", false, "set log level to debug")
flagNorun = flag.Bool("nr", false, "don't run if no change")
flagRTOE = flag.Bool("rtoe", false, "remove tempfile on error")
flagGop = flag.Bool("gop", false, "parse a .go file as a .gop file")
flagProf = flag.Bool("prof", false, "do profile and generate profile report")
)

const (
parserMode = parser.ParseComments
)

func init() {
Cmd.Run = runCmd
}
Expand Down Expand Up @@ -132,12 +137,13 @@ func runCmd(cmd *base.Command, args []string) {
var isDirty bool
var srcDir, file, gofile string
var pkgs map[string]*ast.Package
onExit = nil
if isDir {
srcDir = src
gofile = src + "/gop_autogen.go"
isDirty = true // TODO: check if code changed
if isDirty {
pkgs, err = parser.ParseDir(fset, src, nil, 0)
pkgs, err = parser.ParseDir(fset, src, nil, parserMode)
} else if *flagNorun {
return
}
Expand All @@ -149,6 +155,11 @@ func runCmd(cmd *base.Command, args []string) {
dir := os.Getenv("HOME") + "/.gop/run"
os.MkdirAll(dir, 0755)
gofile = dir + "/g" + base64.RawURLEncoding.EncodeToString(hash[:]) + file
if *flagRTOE { // remove tempfile on error
onExit = func() {
os.Remove(gofile)
}
}
} else if hasMultiFiles(srcDir, ".gop") {
gofile = filepath.Join(srcDir, "gop_autogen_"+file+".go")
} else {
Expand All @@ -160,7 +171,7 @@ func runCmd(cmd *base.Command, args []string) {
fmt.Println("==> GenGo to", gofile)
}
if *flagGop {
pkgs, err = parser.Parse(fset, src, nil, 0)
pkgs, err = parser.Parse(fset, src, nil, parserMode)
} else {
pkgs, err = parser.Parse(fset, src, nil, 0) // TODO: only to check dependencies
}
Expand Down Expand Up @@ -213,6 +224,10 @@ func fileIsDirty(fi os.FileInfo, gofile string) bool {
return fi.ModTime().After(fiDest.ModTime())
}

var (
onExit func()
)

func goRun(file string, args []string) {
goArgs := make([]string, len(args)+2)
goArgs[0] = "run"
Expand All @@ -225,6 +240,9 @@ func goRun(file string, args []string) {
cmd.Env = os.Environ()
err := cmd.Run()
if err != nil {
if onExit != nil {
onExit()
}
switch e := err.(type) {
case *exec.ExitError:
os.Exit(e.ExitCode())
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/goplus/gop
go 1.16

require (
github.com/goplus/gox v1.7.13
github.com/goplus/gox v1.7.14
github.com/qiniu/x v1.11.5
golang.org/x/mod v0.5.1
golang.org/x/tools v0.1.7
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/goplus/gox v1.7.13 h1:w8l/77j3Dj/jOQOSu3DixXuYuBqZx3m7k0BMEWjNsdA=
github.com/goplus/gox v1.7.13/go.mod h1:orZ6Mr9qqB4BVaVCMp/cypMtkn0Fp5XUE7e5uqjZATA=
github.com/goplus/gox v1.7.14 h1:Y1SRmPm+Xlv8DZkf7Q0d9umvVtGcC6m0K6w8GvSC+Kg=
github.com/goplus/gox v1.7.14/go.mod h1:orZ6Mr9qqB4BVaVCMp/cypMtkn0Fp5XUE7e5uqjZATA=
github.com/qiniu/x v1.11.5 h1:TYr5cl4g2yoHAZeDK4MTjKF6CMoG+IHlCDvvM5qym6U=
github.com/qiniu/x v1.11.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
Expand Down
6 changes: 6 additions & 0 deletions parser/_testdata/funcdoc/funcdoc.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package foo

//go:noinline
//go:uintptrescapes
func test(s string, p, q uintptr, rest ...uintptr) int {
}
53 changes: 53 additions & 0 deletions parser/_testdata/funcdoc/parser.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package foo

file funcdoc.gop
ast.FuncDecl:
Doc:
ast.CommentGroup:
List:
ast.Comment:
Text: //go:noinline
ast.Comment:
Text: //go:uintptrescapes
Name:
ast.Ident:
Name: test
Type:
ast.FuncType:
Params:
ast.FieldList:
List:
ast.Field:
Names:
ast.Ident:
Name: s
Type:
ast.Ident:
Name: string
ast.Field:
Names:
ast.Ident:
Name: p
ast.Ident:
Name: q
Type:
ast.Ident:
Name: uintptr
ast.Field:
Names:
ast.Ident:
Name: rest
Type:
ast.Ellipsis:
Elt:
ast.Ident:
Name: uintptr
Results:
ast.FieldList:
List:
ast.Field:
Type:
ast.Ident:
Name: int
Body:
ast.BlockStmt: