diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-02-14 13:23:51 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-02-14 13:23:51 +0100 |
commit | 758ff64c69e34965f8af5b2d6ffd65e8d7ab2150 (patch) | |
tree | 6d6b34f8c678862fe9b56c945a7b63f68502c245 | |
parent | 3e45412327a2654a77944249962b3652e6142299 (diff) | |
download | golang-758ff64c69e34965f8af5b2d6ffd65e8d7ab2150.tar.gz |
Imported Upstream version 2011-02-01.1upstream/2011-02-01.1
535 files changed, 18187 insertions, 9125 deletions
@@ -27,10 +27,11 @@ Ben Olive <sionide21@gmail.com> Benny Siegert <bsiegert@gmail.com> Caine Tighe <arctanofyourface@gmail.com> Charles L. Dorian <cldorian@gmail.com> -Chris Jones <chris@cjones.org> <chris.jones.yar@gmail.com> +Chris Jones <chris@cjones.org> Chris Lennert <calennert@gmail.com> Christian Himpel <chressie@googlemail.com> Christopher Wedgwood <cw@f00f.org> +Clement Skau <clementskau@gmail.com> Conrad Meyer <cemeyer@cs.washington.edu> Corey Thomasson <cthom.lists@gmail.com> Dan Sinclair <dan.sinclair@gmail.com> @@ -47,7 +48,7 @@ Eric Eisner <eric.d.eisner@gmail.com> Evan Shaw <chickencha@gmail.com> Fazlul Shahriar <fshahriar@gmail.com> Firmansyah Adiputra <frm.adiputra@gmail.com> -Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de> +Florian Uekermann <florian@uekermann-online.de> Giles Lean <giles.lean@pobox.com> Google Inc. Graham Miller <graham.miller@gmail.com> @@ -62,9 +63,11 @@ James Toy <nil@opensesame.st> James Whitehead <jnwhiteh@gmail.com> Jan H. Hosang <jan.hosang@gmail.com> Jan Mercl <befelemepeseveze@gmail.com> +Jeff R. Allen <jra@nella.org> Jim McGrath <jimmc2@gmail.com> Joe Poirier <jdpoirier@gmail.com> Jonathan Wills <runningwild@gmail.com> +Jose Luis Vázquez González <josvazg@gmail.com> Josh Goebel <dreamer3@gmail.com> Jukka-Pekka Kekkonen <karatepekka@gmail.com> Kai Backman <kaib@golang.org> @@ -81,8 +84,9 @@ Mathieu Lonjaret <mathieu.lonjaret@gmail.com> Micah Stetson <micah.stetson@gmail.com> Michael Elkins <michael.elkins@gmail.com> Michael Hoisie <hoisie@gmail.com> +Miek Gieben <miek@miek.nl> Mikio Hara <mikioh.mikioh@gmail.com> -Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com> +Mikkel Krautz <mikkel@krautz.dk> Moriyoshi Koizumi <mozo@mozo.jp> Môshe van der Sterre <moshevds@gmail.com> Nicholas Waples <nwaples@gmail.com> @@ -93,6 +97,7 @@ Petar Maymounkov <petarm@gmail.com> Peter Froehlich <peter.hans.froehlich@gmail.com> Peter Mundy <go.peter.90@gmail.com> Peter Williams <pwil3058@gmail.com> +Pieter Droogendijk <pieter@binky.org.uk> Raif S. Naffah <go@naffah-raif.name> Risto Jaakko Saarelma <rsaarelm@gmail.com> Roger Peppe <rogpeppe@gmail.com> diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 317cb525b..769a5b10e 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -51,10 +51,11 @@ Arvindh Rajesh Tamilmani <art@a-30.net> Austin Clements <aclements@csail.mit.edu> Balazs Lecz <leczb@google.com> Ben Eitzen <eitzenb@golang.org> +Ben Lynn <benlynn@gmail.com> Ben Olive <sionide21@gmail.com> Benny Siegert <bsiegert@gmail.com> Bill Neubauer <wcn@golang.org> <wcn@google.com> -Brad Fitzpatrick <brad@danga.com> <bradfitz@gmail.com> +Brad Fitzpatrick <bradfitz@golang.org> <bradfitz@gmail.com> Brendan O'Dea <bod@golang.org> Caine Tighe <arctanofyourface@gmail.com> Cary Hull <chull@google.com> @@ -63,6 +64,7 @@ Chris Jones <chris@cjones.org> <chris.jones.yar@gmail.com> Chris Lennert <calennert@gmail.com> Christian Himpel <chressie@googlemail.com> <chressie@gmail.com> Christopher Wedgwood <cw@f00f.org> +Clement Skau <clementskau@gmail.com> Conrad Meyer <cemeyer@cs.washington.edu> Corey Thomasson <cthom.lists@gmail.com> Dan Sinclair <dan.sinclair@gmail.com> @@ -70,6 +72,7 @@ Daniel Fleischman <danielfleischman@gmail.com> Daniel Nadasi <dnadasi@google.com> Berengar Lehr <Berengar.Lehr@gmx.de> Daniel Theophanes <kardianos@gmail.com> +David Anderson <danderson@google.com> David G. Andersen <dave.andersen@gmail.com> David Symonds <dsymonds@golang.org> David Titarenco <david.titarenco@gmail.com> @@ -102,9 +105,12 @@ James Whitehead <jnwhiteh@gmail.com> Jamie Gennis <jgennis@google.com> Jan H. Hosang <jan.hosang@gmail.com> Jan Mercl <befelemepeseveze@gmail.com> +Jeff R. Allen <jra@nella.org> <jeff.allen@gmail.com> Jim McGrath <jimmc2@gmail.com> Joe Poirier <jdpoirier@gmail.com> Jonathan Wills <runningwild@gmail.com> +Jos Visser <josv@google.com> +Jose Luis Vázquez González <josvazg@gmail.com> Josh Goebel <dreamer3@gmail.com> Jukka-Pekka Kekkonen <karatepekka@gmail.com> Kai Backman <kaib@golang.org> @@ -115,7 +121,7 @@ Ken Thompson <ken@golang.org> Kevin Ballard <kevin@sb.org> Kirklin McDonald <kirklin.mcdonald@gmail.com> Kyle Consalus <consalus@gmail.com> -Kyle Lemons <kyle@kylelemons.net> +Kyle Lemons <kyle@kylelemons.net> <etherealflaim@gmail.com> Larry Hosken <lahosken@golang.org> Lorenzo Stoakes <lstoakes@gmail.com> Luuk van Dijk <lvd@golang.org> <lvd@google.com> @@ -127,6 +133,7 @@ Maxim Ushakov <ushakov@google.com> Micah Stetson <micah.stetson@gmail.com> Michael Elkins <michael.elkins@gmail.com> Michael Hoisie <hoisie@gmail.com> +Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com> Mikio Hara <mikioh.mikioh@gmail.com> Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com> Moriyoshi Koizumi <mozo@mozo.jp> @@ -143,6 +150,7 @@ Peter Mundy <go.peter.90@gmail.com> Péter Szabó <pts@google.com> Peter Williams <pwil3058@gmail.com> Phil Pennock <pdp@golang.org> +Pieter Droogendijk <pieter@binky.org.uk> Raif S. Naffah <go@naffah-raif.name> Risto Jaakko Saarelma <rsaarelm@gmail.com> Rob Pike <r@golang.org> diff --git a/doc/all.css b/doc/all.css index f70ef1599..b1d55cf25 100644 --- a/doc/all.css +++ b/doc/all.css @@ -157,6 +157,10 @@ h1#title { pre.ebnf, pre.grammar { background: #FFFFE0; } +span.ln { + font-size: 80%; + color: #777777; +} span.comment { color: #002090; } diff --git a/doc/codelab/wiki/Makefile b/doc/codelab/wiki/Makefile index e0549fc8e..0d948ed4b 100644 --- a/doc/codelab/wiki/Makefile +++ b/doc/codelab/wiki/Makefile @@ -13,12 +13,13 @@ CLEANFILES+=index.html srcextract.bin htmlify.bin index.html: srcextract.bin htmlify.bin awk '/^!/{system(substr($$0,2)); next} {print}' "$$@" < wiki.html > index.html -test: final.bin - ./test.sh - rm -f final.6 final.bin +test: get.bin + bash ./test.sh + rm -f get.6 get.bin %.bin: %.$O $(LD) -o $@ $< -%.$O: + +%.$O: %.go $(GC) $*.go diff --git a/doc/codelab/wiki/edit.html b/doc/codelab/wiki/edit.html index 71a919496..7a5768ce9 100644 --- a/doc/codelab/wiki/edit.html +++ b/doc/codelab/wiki/edit.html @@ -1,6 +1,6 @@ -<h1>Editing {title}</h1> +<h1>Editing {Title}</h1> -<form action="/save/{title}" method="POST"> -<div><textarea name="body" rows="20" cols="80">{body|html}</textarea></div> +<form action="/save/{Title}" method="POST"> +<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div> <div><input type="submit" value="Save"></div> </form> diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go index 2f48565ca..99121f298 100644 --- a/doc/codelab/wiki/final-noclosure.go +++ b/doc/codelab/wiki/final-noclosure.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request) { @@ -47,7 +47,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { } p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } @@ -58,7 +58,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { return } body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err = p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -67,7 +67,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, err := template.ParseFile(tmpl+".html", nil) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/final-noerror.go b/doc/codelab/wiki/final-noerror.go index cf4852265..0f18912d2 100644 --- a/doc/codelab/wiki/final-noerror.go +++ b/doc/codelab/wiki/final-noerror.go @@ -7,23 +7,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -32,7 +32,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } t, _ := template.ParseFile("edit.html", nil) t.Execute(p, w) diff --git a/doc/codelab/wiki/final-parsetemplate.go b/doc/codelab/wiki/final-parsetemplate.go index f02d116b2..ea8977601 100644 --- a/doc/codelab/wiki/final-parsetemplate.go +++ b/doc/codelab/wiki/final-parsetemplate.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -39,14 +39,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -55,7 +55,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request, title string) { http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, err := template.ParseFile(tmpl+".html", nil) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/final-template.go b/doc/codelab/wiki/final-template.go index 0bb133d3a..4d6a2cfab 100644 --- a/doc/codelab/wiki/final-template.go +++ b/doc/codelab/wiki/final-template.go @@ -7,23 +7,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -32,7 +32,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } @@ -46,12 +46,12 @@ func viewHandler(w http.ResponseWriter, r *http.Request) { func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, _ := template.ParseFile(tmpl+".html", nil) t.Execute(p, w) } diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go index 0c0206bc0..8ecd97d74 100644 --- a/doc/codelab/wiki/final.go +++ b/doc/codelab/wiki/final.go @@ -8,23 +8,23 @@ import ( "template" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func viewHandler(w http.ResponseWriter, r *http.Request, title string) { @@ -39,14 +39,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -63,7 +63,7 @@ func init() { } } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { err := templates[tmpl].Execute(p, w) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/get.go b/doc/codelab/wiki/get.go new file mode 100644 index 000000000..342831416 --- /dev/null +++ b/doc/codelab/wiki/get.go @@ -0,0 +1,50 @@ +package main + +import ( + "http" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" +) + +var ( + post = flag.String("post", "", "urlencoded form data to POST") + addr = flag.Bool("addr", false, "find open address and print to stdout") +) + +func main() { + flag.Parse() + if *addr { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatal(err) + } + defer l.Close() + fmt.Print(l.Addr()) + return + } + url := flag.Arg(0) + if url == "" { + log.Fatal("no url supplied") + } + var r *http.Response + var err os.Error + if *post != "" { + b := strings.NewReader(*post) + r, err = http.Post(url, "application/x-www-form-urlencoded", b) + } else { + r, _, err = http.Get(url) + } + if err != nil { + log.Fatal(err) + } + defer r.Body.Close() + _, err = io.Copy(os.Stdout, r.Body) + if err != nil { + log.Fatal(err) + } +} diff --git a/doc/codelab/wiki/htmlify.go b/doc/codelab/wiki/htmlify.go index 4a52e077f..456d06fd5 100644 --- a/doc/codelab/wiki/htmlify.go +++ b/doc/codelab/wiki/htmlify.go @@ -8,5 +8,5 @@ import ( func main() { b, _ := ioutil.ReadAll(os.Stdin) - template.HTMLFormatter(os.Stdout, b, "") + template.HTMLFormatter(os.Stdout, "", b) } diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html index c494a3ced..fe99c32d1 100644 --- a/doc/codelab/wiki/index.html +++ b/doc/codelab/wiki/index.html @@ -71,14 +71,14 @@ declaration. <p> Let's start by defining the data structures. A wiki consists of a series of interconnected pages, each of which has a title and a body (the page content). -Here, we define <code>page</code> as a struct with two fields representing +Here, we define <code>Page</code> as a struct with two fields representing the title and body. </p> <pre> -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } </pre> @@ -86,33 +86,33 @@ type page struct { The type <code>[]byte</code> means "a <code>byte</code> slice". (See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a> for more on slices.) -The <code>body</code> element is a <code>[]byte</code> rather than +The <code>Body</code> element is a <code>[]byte</code> rather than <code>string</code> because that is the type expected by the <code>io</code> libraries we will use, as you'll see below. </p> <p> -The <code>page</code> struct describes how page data will be stored in memory. +The <code>Page</code> struct describes how page data will be stored in memory. But what about persistent storage? We can address that by creating a -<code>save</code> method on <code>page</code>: +<code>save</code> method on <code>Page</code>: </p> <pre> -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } </pre> <p> This method's signature reads: "This is a method named <code>save</code> that -takes as its receiver <code>p</code>, a pointer to <code>page</code> . It takes +takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes no parameters, and returns a value of type <code>os.Error</code>." </p> <p> -This method will save the <code>page</code>'s <code>body</code> to a text -file. For simplicity, we will use the <code>title</code> as the file name. +This method will save the <code>Page</code>'s <code>Body</code> to a text +file. For simplicity, we will use the <code>Title</code> as the file name. </p> <p> @@ -120,7 +120,7 @@ The <code>save</code> method returns an <code>os.Error</code> value because that is the return type of <code>WriteFile</code> (a standard library function that writes a byte slice to a file). The <code>save</code> method returns the error value, to let the application handle it should anything go wrong while -writing the file. If all goes well, <code>page.save()</code> will return +writing the file. If all goes well, <code>Page.save()</code> will return <code>nil</code> (the zero-value for pointers, interfaces, and some other types). </p> @@ -137,17 +137,17 @@ We will want to load pages, too: </p> <pre> -func loadPage(title string) *page { +func loadPage(title string) *Page { filename := title + ".txt" body, _ := ioutil.ReadFile(filename) - return &page{title: title, body: body} + return &Page{Title: title, Body: body} } </pre> <p> The function <code>loadPage</code> constructs the file name from -<code>title</code>, reads the file's contents into a new -<code>page</code>, and returns a pointer to that new <code>page</code>. +<code>Title</code>, reads the file's contents into a new +<code>Page</code>, and returns a pointer to that new <code>page</code>. </p> <p> @@ -161,23 +161,23 @@ error return value (in essence, assigning the value to nothing). <p> But what happens if <code>ReadFile</code> encounters an error? For example, the file might not exist. We should not ignore such errors. Let's modify the -function to return <code>*page</code> and <code>os.Error</code>. +function to return <code>*Page</code> and <code>os.Error</code>. </p> <pre> -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } </pre> <p> Callers of this function can now check the second parameter; if it is -<code>nil</code> then it has successfully loaded a page. If not, it will be an +<code>nil</code> then it has successfully loaded a Page. If not, it will be an <code>os.Error</code> that can be handled by the caller (see the <a href="http://golang.org/pkg/os/#Error">os package documentation</a> for details). @@ -191,17 +191,17 @@ written: <pre> func main() { - p1 := &page{title: "TestPage", body: []byte("This is a sample page.")} + p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} p1.save() p2, _ := loadPage("TestPage") - fmt.Println(string(p2.body)) + fmt.Println(string(p2.Body)) } </pre> <p> After compiling and executing this code, a file named <code>TestPage.txt</code> would be created, containing the contents of <code>p1</code>. The file would -then be read into the struct <code>p2</code>, and its <code>body</code> element +then be read into the struct <code>p2</code>, and its <code>Body</code> element printed to the screen. </p> @@ -317,7 +317,7 @@ const lenPath = len("/view/") func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, _ := loadPage(title) - fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body) + fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) } </pre> @@ -377,7 +377,7 @@ href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code should show a page titled "test" containing the words "Hello world". </p> -<h2>Editing pages</h2> +<h2>Editing Pages</h2> <p> A wiki is not a wiki without the ability to edit pages. Let's create two new @@ -401,7 +401,7 @@ func main() { <p> The function <code>editHandler</code> loads the page -(or, if it doesn't exist, create an empty <code>page</code> struct), +(or, if it doesn't exist, create an empty <code>Page</code> struct), and displays an HTML form. </p> @@ -410,14 +410,14 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } fmt.Fprintf(w, "<h1>Editing %s</h1>"+ "<form action=\"/save/%s\" method=\"POST\">"+ "<textarea name=\"body\">%s</textarea><br>"+ "<input type=\"submit\" value=\"Save\">"+ "</form>", - p.title, p.title, p.body) + p.Title, p.Title, p.Body) } </pre> @@ -454,10 +454,10 @@ Open a new file named <code>edit.html</code>, and add the following lines: </p> <pre> -<h1>Editing {title}</h1> +<h1>Editing {Title}</h1> -<form action="/save/{title}" method="POST"> -<div><textarea name="body" rows="20" cols="80">{body|html}</textarea></div> +<form action="/save/{Title}" method="POST"> +<div><textarea name="body" rows="20" cols="80">{Body|html}</textarea></div> <div><input type="submit" value="Save"></div> </form> </pre> @@ -472,7 +472,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } t, _ := template.ParseFile("edit.html", nil) t.Execute(p, w) @@ -486,15 +486,15 @@ The function <code>template.ParseFile</code> will read the contents of <p> The method <code>t.Execute</code> replaces all occurrences of -<code>{title}</code> and <code>{body}</code> with the values of -<code>p.title</code> and <code>p.body</code>, and writes the resultant +<code>{Title}</code> and <code>{Body}</code> with the values of +<code>p.Title</code> and <code>p.Body</code>, and writes the resultant HTML to the <code>http.ResponseWriter</code>. </p> <p> -Note that we've used <code>{body|html}</code> in the above template. +Note that we've used <code>{Body|html}</code> in the above template. The <code>|html</code> part asks the template engine to pass the value -<code>body</code> through the <code>html</code> formatter before outputting it, +<code>Body</code> through the <code>html</code> formatter before outputting it, which escapes HTML characters (such as replacing <code>></code> with <code>&gt;</code>). This will prevent user data from corrupting the form HTML. @@ -511,11 +511,11 @@ While we're working with templates, let's create a template for our </p> <pre> -<h1>{title}</h1> +<h1>{Title}</h1> -<p>[<a href="/edit/{title}">edit</a>]</p> +<p>[<a href="/edit/{Title}">edit</a>]</p> -<div>{body}</div> +<div>{Body}</div> </pre> <p> @@ -548,12 +548,12 @@ func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, _ := template.ParseFile(tmpl+".html", nil) t.Execute(p, w) } @@ -568,8 +568,8 @@ The handlers are now shorter and simpler. <p> What if you visit <code>/view/APageThatDoesntExist</code>? The program will crash. This is because it ignores the error return value from -<code>loadPage</code>. Instead, if the requested page doesn't exist, it should -redirect the client to the edit page so the content may be created: +<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should +redirect the client to the edit Page so the content may be created: </p> <pre> @@ -589,7 +589,7 @@ The <code>http.Redirect</code> function adds an HTTP status code of header to the HTTP response. </p> -<h2>Saving pages</h2> +<h2>Saving Pages</h2> <p> The function <code>saveHandler</code> will handle the form submission. @@ -599,7 +599,7 @@ The function <code>saveHandler</code> will handle the form submission. func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} p.save() http.Redirect(w, r, "/view/"+title, http.StatusFound) } @@ -607,7 +607,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { <p> The page title (provided in the URL) and the form's only field, -<code>body</code>, are stored in a new <code>page</code>. +<code>Body</code>, are stored in a new <code>Page</code>. The <code>save()</code> method is then called to write the data to a file, and the client is redirected to the <code>/view/</code> page. </p> @@ -615,7 +615,7 @@ and the client is redirected to the <code>/view/</code> page. <p> The value returned by <code>FormValue</code> is of type <code>string</code>. We must convert that value to <code>[]byte</code> before it will fit into -the <code>page</code> struct. We use <code>[]byte(body)</code> to perform +the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform the conversion. </p> @@ -634,7 +634,7 @@ First, let's handle the errors in <code>renderTemplate</code>: </p> <pre> -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { t, err := template.ParseFile(tmpl+".html", nil) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -660,7 +660,7 @@ Now let's fix up <code>saveHandler</code>: <pre> func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -725,7 +725,7 @@ the <code>Execute</code> method on the appropriate <code>Template</code> from <code>templates</code>: <pre> -func renderTemplate(w http.ResponseWriter, tmpl string, p *page) { +func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { err := templates[tmpl].Execute(p, w) if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -747,7 +747,6 @@ Then we can create a global variable to store our validation regexp: </p> <pre> -var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$") </pre> <p> @@ -761,7 +760,7 @@ the expression compilation fails, while <code>Compile</code> returns an <p> Now, let's write a function that extracts the title string from the request -URL, and tests it against our <code>titleValidator</code> expression: +URL, and tests it against our <code>TitleValidator</code> expression: </p> <pre> @@ -807,7 +806,7 @@ func editHandler(w http.ResponseWriter, r *http.Request) { } p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } @@ -818,7 +817,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) { return } body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err = p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) @@ -895,7 +894,7 @@ The closure returned by <code>makeHandler</code> is a function that takes an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other words, an <code>http.HandlerFunc</code>). The closure extracts the <code>title</code> from the request path, and -validates it with the <code>titleValidator</code> regexp. If the +validates it with the <code>TitleValidator</code> regexp. If the <code>title</code> is invalid, an error will be written to the <code>ResponseWriter</code> using the <code>http.NotFound</code> function. If the <code>title</code> is valid, the enclosed handler function @@ -936,14 +935,14 @@ func viewHandler(w http.ResponseWriter, r *http.Request, title string) { func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") - p := &page{title: title, body: []byte(body)} + p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.String(), http.StatusInternalServerError) diff --git a/doc/codelab/wiki/notemplate.go b/doc/codelab/wiki/notemplate.go index c1f952c83..9cbe9ad76 100644 --- a/doc/codelab/wiki/notemplate.go +++ b/doc/codelab/wiki/notemplate.go @@ -7,23 +7,23 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -31,21 +31,21 @@ const lenPath = len("/view/") func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, _ := loadPage(title) - fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body) + fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) } func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, err := loadPage(title) if err != nil { - p = &page{title: title} + p = &Page{Title: title} } fmt.Fprintf(w, "<h1>Editing %s</h1>"+ "<form action=\"/save/%s\" method=\"POST\">"+ "<textarea name=\"body\">%s</textarea><br>"+ "<input type=\"submit\" value=\"Save\">"+ "</form>", - p.title, p.title, p.body) + p.Title, p.Title, p.Body) } func main() { diff --git a/doc/codelab/wiki/part1-noerror.go b/doc/codelab/wiki/part1-noerror.go index 39e8331e3..14cfc321a 100644 --- a/doc/codelab/wiki/part1-noerror.go +++ b/doc/codelab/wiki/part1-noerror.go @@ -6,25 +6,25 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) *page { +func loadPage(title string) *Page { filename := title + ".txt" body, _ := ioutil.ReadFile(filename) - return &page{title: title, body: body} + return &Page{Title: title, Body: body} } func main() { - p1 := &page{title: "TestPage", body: []byte("This is a sample page.")} + p1 := &Page{Title: "TestPage", Body: []byte("This is a sample page.")} p1.save() p2 := loadPage("TestPage") - fmt.Println(string(p2.body)) + fmt.Println(string(p2.Body)) } diff --git a/doc/codelab/wiki/part1.go b/doc/codelab/wiki/part1.go index f3678baa5..4b0654f8b 100644 --- a/doc/codelab/wiki/part1.go +++ b/doc/codelab/wiki/part1.go @@ -6,28 +6,28 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } func main() { - p1 := &page{title: "TestPage", body: []byte("This is a sample page.")} + p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} p1.save() p2, _ := loadPage("TestPage") - fmt.Println(string(p2.body)) + fmt.Println(string(p2.Body)) } diff --git a/doc/codelab/wiki/part2.go b/doc/codelab/wiki/part2.go index 8d4454a74..d57c3a01f 100644 --- a/doc/codelab/wiki/part2.go +++ b/doc/codelab/wiki/part2.go @@ -7,23 +7,23 @@ import ( "os" ) -type page struct { - title string - body []byte +type Page struct { + Title string + Body []byte } -func (p *page) save() os.Error { - filename := p.title + ".txt" - return ioutil.WriteFile(filename, p.body, 0600) +func (p *Page) save() os.Error { + filename := p.Title + ".txt" + return ioutil.WriteFile(filename, p.Body, 0600) } -func loadPage(title string) (*page, os.Error) { +func loadPage(title string) (*Page, os.Error) { filename := title + ".txt" body, err := ioutil.ReadFile(filename) if err != nil { return nil, err } - return &page{title: title, body: body}, nil + return &Page{Title: title, Body: body}, nil } const lenPath = len("/view/") @@ -31,7 +31,7 @@ const lenPath = len("/view/") func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[lenPath:] p, _ := loadPage(title) - fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body) + fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.Title, p.Body) } func main() { diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go index 0addc61c4..cab092f58 100644 --- a/doc/codelab/wiki/srcextract.go +++ b/doc/codelab/wiki/srcextract.go @@ -6,6 +6,7 @@ import ( "go/parser" "go/printer" "go/ast" + "go/token" "log" "os" ) @@ -25,9 +26,10 @@ func main() { os.Exit(2) } // load file - file, err := parser.ParseFile(*srcFn, nil, 0) + fs := token.NewFileSet() + file, err := parser.ParseFile(fs, *srcFn, nil, 0) if err != nil { - log.Exit(err) + log.Fatal(err) } // create printer p := &printer.Config{ @@ -47,7 +49,7 @@ func main() { os.Exit(1) } b := new(bytes.Buffer) - p.Fprint(b, file) + p.Fprint(b, fs, file) // drop package declaration if !*showPkg { for { diff --git a/doc/codelab/wiki/test.sh b/doc/codelab/wiki/test.sh index 5b752fe3c..95ff145b9 100755 --- a/doc/codelab/wiki/test.sh +++ b/doc/codelab/wiki/test.sh @@ -1,24 +1,27 @@ -#1/bin/bash - -./final.bin & -wiki_pid=$! +#!/usr/bin/env bash +set -e +wiki_pid= cleanup() { kill $wiki_pid - rm -f test_*.out Test.txt - exit ${1:-1} + rm -f test_*.out Test.txt final-test.bin final-test.go } -trap cleanup INT +trap cleanup 0 INT -sleep 1 +gomake get.bin +addr=$(./get.bin -addr) +sed s/:8080/$addr/ < final.go > final-test.go +gomake final-test.bin +./final-test.bin & +wiki_pid=$! -curl -s -o test_edit.out http://localhost:8080/edit/Test -cmp test_edit.out test_edit.good || cleanup 1 -curl -s -o /dev/null -d body=some%20content http://localhost:8080/save/Test -cmp Test.txt test_Test.txt.good || cleanup 1 -curl -s -o test_view.out http://localhost:8080/view/Test -cmp test_view.out test_view.good || cleanup 1 +sleep 1 -echo "Passed" -cleanup 0 +./get.bin http://$addr/edit/Test > test_edit.out +diff -u test_edit.out test_edit.good +./get.bin -post=body=some%20content http://$addr/save/Test +diff -u Test.txt test_Test.txt.good +./get.bin http://$addr/view/Test > test_view.out +diff -u test_view.out test_view.good +echo PASS diff --git a/doc/codelab/wiki/view.html b/doc/codelab/wiki/view.html index a46622d01..ca2ffc20b 100644 --- a/doc/codelab/wiki/view.html +++ b/doc/codelab/wiki/view.html @@ -1,5 +1,5 @@ -<h1>{title}</h1> +<h1>{Title}</h1> -<p>[<a href="/edit/{title}">edit</a>]</p> +<p>[<a href="/edit/{Title}">edit</a>]</p> -<div>{body}</div> +<div>{Body}</div> diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html index 919385edf..ff2c3088b 100644 --- a/doc/codelab/wiki/wiki.html +++ b/doc/codelab/wiki/wiki.html @@ -71,27 +71,27 @@ declaration. <p> Let's start by defining the data structures. A wiki consists of a series of interconnected pages, each of which has a title and a body (the page content). -Here, we define <code>page</code> as a struct with two fields representing +Here, we define <code>Page</code> as a struct with two fields representing the title and body. </p> <pre> -!./srcextract.bin -src=part1.go -name=page +!./srcextract.bin -src=part1.go -name=Page </pre> <p> The type <code>[]byte</code> means "a <code>byte</code> slice". (See <a href="http://golang.org/doc/effective_go.html#slices">Effective Go</a> for more on slices.) -The <code>body</code> element is a <code>[]byte</code> rather than +The <code>Body</code> element is a <code>[]byte</code> rather than <code>string</code> because that is the type expected by the <code>io</code> libraries we will use, as you'll see below. </p> <p> -The <code>page</code> struct describes how page data will be stored in memory. +The <code>Page</code> struct describes how page data will be stored in memory. But what about persistent storage? We can address that by creating a -<code>save</code> method on <code>page</code>: +<code>save</code> method on <code>Page</code>: </p> <pre> @@ -100,13 +100,13 @@ But what about persistent storage? We can address that by creating a <p> This method's signature reads: "This is a method named <code>save</code> that -takes as its receiver <code>p</code>, a pointer to <code>page</code> . It takes +takes as its receiver <code>p</code>, a pointer to <code>Page</code> . It takes no parameters, and returns a value of type <code>os.Error</code>." </p> <p> -This method will save the <code>page</code>'s <code>body</code> to a text -file. For simplicity, we will use the <code>title</code> as the file name. +This method will save the <code>Page</code>'s <code>Body</code> to a text +file. For simplicity, we will use the <code>Title</code> as the file name. </p> <p> @@ -114,7 +114,7 @@ The <code>save</code> method returns an <code>os.Error</code> value because that is the return type of <code>WriteFile</code> (a standard library function that writes a byte slice to a file). The <code>save</code> method returns the error value, to let the application handle it should anything go wrong while -writing the file. If all goes well, <code>page.save()</code> will return +writing the file. If all goes well, <code>Page.save()</code> will return <code>nil</code> (the zero-value for pointers, interfaces, and some other types). </p> @@ -136,8 +136,8 @@ We will want to load pages, too: <p> The function <code>loadPage</code> constructs the file name from -<code>title</code>, reads the file's contents into a new -<code>page</code>, and returns a pointer to that new <code>page</code>. +<code>Title</code>, reads the file's contents into a new +<code>Page</code>, and returns a pointer to that new <code>page</code>. </p> <p> @@ -151,7 +151,7 @@ error return value (in essence, assigning the value to nothing). <p> But what happens if <code>ReadFile</code> encounters an error? For example, the file might not exist. We should not ignore such errors. Let's modify the -function to return <code>*page</code> and <code>os.Error</code>. +function to return <code>*Page</code> and <code>os.Error</code>. </p> <pre> @@ -160,7 +160,7 @@ function to return <code>*page</code> and <code>os.Error</code>. <p> Callers of this function can now check the second parameter; if it is -<code>nil</code> then it has successfully loaded a page. If not, it will be an +<code>nil</code> then it has successfully loaded a Page. If not, it will be an <code>os.Error</code> that can be handled by the caller (see the <a href="http://golang.org/pkg/os/#Error">os package documentation</a> for details). @@ -179,7 +179,7 @@ written: <p> After compiling and executing this code, a file named <code>TestPage.txt</code> would be created, containing the contents of <code>p1</code>. The file would -then be read into the struct <code>p2</code>, and its <code>body</code> element +then be read into the struct <code>p2</code>, and its <code>Body</code> element printed to the screen. </p> @@ -334,7 +334,7 @@ href="http://localhost:8080/view/test">http://localhost:8080/view/test</a></code should show a page titled "test" containing the words "Hello world". </p> -<h2>Editing pages</h2> +<h2>Editing Pages</h2> <p> A wiki is not a wiki without the ability to edit pages. Let's create two new @@ -353,7 +353,7 @@ First, we add them to <code>main()</code>: <p> The function <code>editHandler</code> loads the page -(or, if it doesn't exist, create an empty <code>page</code> struct), +(or, if it doesn't exist, create an empty <code>Page</code> struct), and displays an HTML form. </p> @@ -413,15 +413,15 @@ The function <code>template.ParseFile</code> will read the contents of <p> The method <code>t.Execute</code> replaces all occurrences of -<code>{title}</code> and <code>{body}</code> with the values of -<code>p.title</code> and <code>p.body</code>, and writes the resultant +<code>{Title}</code> and <code>{Body}</code> with the values of +<code>p.Title</code> and <code>p.Body</code>, and writes the resultant HTML to the <code>http.ResponseWriter</code>. </p> <p> -Note that we've used <code>{body|html}</code> in the above template. +Note that we've used <code>{Body|html}</code> in the above template. The <code>|html</code> part asks the template engine to pass the value -<code>body</code> through the <code>html</code> formatter before outputting it, +<code>Body</code> through the <code>html</code> formatter before outputting it, which escapes HTML characters (such as replacing <code>></code> with <code>&gt;</code>). This will prevent user data from corrupting the form HTML. @@ -472,8 +472,8 @@ The handlers are now shorter and simpler. <p> What if you visit <code>/view/APageThatDoesntExist</code>? The program will crash. This is because it ignores the error return value from -<code>loadPage</code>. Instead, if the requested page doesn't exist, it should -redirect the client to the edit page so the content may be created: +<code>loadPage</code>. Instead, if the requested Page doesn't exist, it should +redirect the client to the edit Page so the content may be created: </p> <pre> @@ -486,7 +486,7 @@ The <code>http.Redirect</code> function adds an HTTP status code of header to the HTTP response. </p> -<h2>Saving pages</h2> +<h2>Saving Pages</h2> <p> The function <code>saveHandler</code> will handle the form submission. @@ -498,7 +498,7 @@ The function <code>saveHandler</code> will handle the form submission. <p> The page title (provided in the URL) and the form's only field, -<code>body</code>, are stored in a new <code>page</code>. +<code>Body</code>, are stored in a new <code>Page</code>. The <code>save()</code> method is then called to write the data to a file, and the client is redirected to the <code>/view/</code> page. </p> @@ -506,7 +506,7 @@ and the client is redirected to the <code>/view/</code> page. <p> The value returned by <code>FormValue</code> is of type <code>string</code>. We must convert that value to <code>[]byte</code> before it will fit into -the <code>page</code> struct. We use <code>[]byte(body)</code> to perform +the <code>Page</code> struct. We use <code>[]byte(body)</code> to perform the conversion. </p> @@ -610,7 +610,7 @@ Then we can create a global variable to store our validation regexp: </p> <pre> -!./srcextract.bin -src=final-noclosure.go -name=titleValidator +!./srcextract.bin -src=final-noclosure.go -name=TitleValidator </pre> <p> @@ -624,7 +624,7 @@ the expression compilation fails, while <code>Compile</code> returns an <p> Now, let's write a function that extracts the title string from the request -URL, and tests it against our <code>titleValidator</code> expression: +URL, and tests it against our <code>TitleValidator</code> expression: </p> <pre> @@ -708,7 +708,7 @@ The closure returned by <code>makeHandler</code> is a function that takes an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other words, an <code>http.HandlerFunc</code>). The closure extracts the <code>title</code> from the request path, and -validates it with the <code>titleValidator</code> regexp. If the +validates it with the <code>TitleValidator</code> regexp. If the <code>title</code> is invalid, an error will be written to the <code>ResponseWriter</code> using the <code>http.NotFound</code> function. If the <code>title</code> is valid, the enclosed handler function diff --git a/doc/devel/release.html b/doc/devel/release.html index ecf125953..f965b5cad 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -5,6 +5,220 @@ <p>This page summarizes the changes between tagged releases of Go. For full details, see the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>.</p> +<h3 id="2011-02-01">2011-02-01</h3> + +<pre> +This release includes significant changes to channel operations and minor +changes to the log package. Your code will require modification if it uses +channels in non-blocking communications or the log package's Exit functions. + +Non-blocking channel operations have been removed from the language. +The equivalent operations have always been possible using a select statement +with a default clause. If a default clause is present in a select, that clause +will execute (only) if no other is ready, which allows one to avoid blocking on +a communication. + +For example, the old non-blocking send operation, + + if ch <- v { + // sent + } else { + // not sent + } + +should be rewritten as, + + select { + case ch <- v: + // sent + default: + // not sent + } + +Similarly, this receive, + + v, ok := <-ch + if ok { + // received + } else { + // not received + } + +should be rewritten as, + + select { + case v := <-ch: + // received + default: + // not received + } + +This change is a prelude to redefining the 'comma-ok' syntax for a receive. +In a later release, a receive expression will return the received value and an +optional boolean indicating whether the channel has been closed. These changes +are being made in two stages to prevent this semantic change from silently +breaking code that uses 'comma-ok' with receives. +There are no plans to have a boolean expression form for sends. + +Sends to a closed channel will panic immediately. Previously, an unspecified +number of sends would fail silently before causing a panic. + +The log package's Exit, Exitf, and Exitln functions have been renamed Fatal, +Fatalf, and Fatalln respectively. This brings them in line with the naming of +the testing package. + +The port to the "tiny" operating system has been removed. It is unmaintained +and untested. It was a toy to show that Go can run on raw hardware and it +served its purpose. The source code will of course remain in the repository +history, so it could be brought back if needed later. + +This release also changes some of the internal structure of the memory +allocator in preparation for other garbage collector changes. +If you run into problems, please let us know. +There is one known issue that we are aware of but have not debugged yet: + http://code.google.com/p/go/issues/detail?id=1464&. + +Other changes in this release: +* 5l: document -F, force it on old ARMs (software floating point emulation) +* 6g: fix registerization of temporaries (thanks Eoghan Sherry), + fix uint64(uintptr(unsafe.Pointer(&x))). +* 6l: Relocate CMOV* instructions (thanks Gustavo Niemeyer), + windows/amd64 port (thanks Wei Guangjing). +* 8l: add PE dynexport, emit DWARF in Windows PE, and + code generation fixes (thanks Wei Guangjing). +* bufio: make Flush a no-op when the buffer is empty. +* bytes: Add Buffer.ReadBytes, Buffer.ReadString (thanks Evan Shaw). +* cc: mode to generate go-code for types and variables. +* cgo: define CGO_CFLAGS and CGO_LDFLAGS in Go files (thanks Gustavo Niemeyer), + windows/386 port (thanks Wei Guangjing). +* codereview: fix windows (thanks Hector Chu), + handle file patterns better, + more ASCII vs. Unicode nonsense. +* crypto/dsa: add support for DSA. +* crypto/openpgp: add s2k. +* crypto/rand: use defer to unlock mutex (thanks Anschel Schaffer-Cohen). +* crypto/rsa: correct docstring for SignPKCS1v15. +* crypto: add package, a common place to store identifiers for hash functions. +* doc/codelab/wiki: update to work with template changes, add to run.bash. +* doc/spec: clarify address operators. +* ebnflint: exit with non-zero status on error. +* encoding/base32: new package (thanks Miek Gieben). +* encoding/line: make it an io.Reader too. +* exec: use custom error for LookPath (thanks Gustavo Niemeyer). +* fmt/doc: define width and precision for strings. +* gc: clearer error for struct == struct, + fix send precedence, + handle invalid name in type switch, + special case code for single-op blocking and non-blocking selects. +* go/scanner: fix build (adjust scanner EOF linecount). +* gob: better debugging, commentary, + make nested interfaces work, + report an error when encoding a non-empty struct with no public fields. +* godoc: full text index for whitelisted non-Go files, + show line numbers for non-go files (bug fix). +* gofmt -r: match(...) arguments may be nil; add missing guards. +* govet: add Panic to the list of functions. +* http: add host patterns (thanks Jose Luis Vázquez González), + follow relative redirect in Get. +* json: handle capital floating point exponent (1E100) (thanks Pieter Droogendijk). +* ld: add -I option to set ELF interpreter, + more robust decoding of reflection type info in generating dwarf. +* lib9: update to Unicode 6.0.0. +* make.bash: stricter selinux test (don't complain unless it is enabled). +* misc/vim: Import/Drop commands (thanks Gustavo Niemeyer), + set 'syntax sync' to a large value (thanks Yasuhiro Matsumoto). +* net: fix race condition in test, + return cname in LookupHost. +* netchan: avoid race condition in test, + fixed documentation for import (thanks Anschel Schaffer-Cohen). +* os: add ETIMEDOUT (thanks Albert Strasheim). +* runtime: generate Go defs for C types, + implementation of callback functions for windows (thanks Alex Brainman), + make Walk web browser example work (thanks Hector Chu), + make select fairer, + prefer fixed stack allocator over general memory allocator, + simpler heap map, memory allocation. +* scanner: fix Position returned by Scan, Pos, + don't read ahead in Init. +* suffixarray: use binary search for both ends of Lookup (thanks Eric Eisner). +* syscall: add missing network interface constants (thanks Mikio Hara). +* template: treat map keys as zero, not non-existent (thanks Roger Peppe). +* time: allow cancelling of After events (thanks Roger Peppe), + support Solaris zoneinfo directory. +* token/position: added SetLinesForContent. +* unicode: update to unicode 6.0.0. +* unsafe: add missing case to doc for Pointer. +</pre> + +<h3 id="2011-01-20">2011-01-20</h3> + +<pre> +This release removes the float and complex types from the language. + +The default type for a floating point literal is now float64, and +the default type for a complex literal is now complex128. + +Existing code that uses float or complex must be rewritten to +use explicitly sized types. + +The two-argument constructor cmplx is now spelled complex. +</pre> + +<h3 id="2011-01-19">2011-01-19</h3> + +<pre> +The 5g (ARM) compiler now has registerization enabled. If you discover it +causes bugs, use 5g -N to disable the registerizer and please let us know. + +The xml package now allows the extraction of nested XML tags by specifying +struct tags of the form "parent>child". See the XML documentation for an +example: http://golang.org/pkg/xml/ + +* 5a, 5l, 6a, 6l, 8a, 8l: handle out of memory, large allocations (thanks Jeff R. Allen). +* 8l: pe changes (thanks Alex Brainman). +* arm: fixes and improvements. +* cc: fix vlong condition. +* cgo: add complex float, complex double (thanks Sebastien Binet), + in _cgo_main.c define all provided symbols as functions. +* codereview: don't mail change lists with no files (thanks Ryan Hitchman). +* crypto/cipher: add OFB mode. +* expvar: add Float. +* fmt: document %X of string, []byte. +* gc, runtime: make range on channel safe for multiple goroutines. +* gc: fix typed constant declarations (thanks Anthony Martin). +* go spec: adjust language for constant typing. +* go/scanner: Make Init take a *token.File instead of a *token.FileSet. +* godoc: bring back "indexing in progress" message, + don't double HTML-escape search result snippets, + enable qualified identifiers ("math.Sin") as query strings again, + peephole optimization for generated HTML, + remove tab before formatted section. +* gofmt, go/printer: do not insert extra line breaks where they may break the code. +* http: fix Content-Range and Content-Length in response (thanks Clement Skau), + fix scheme-relative URL parsing; add ParseRequestURL, + handle HEAD requests correctly, + support for relative URLs. +* math: handle denormalized numbers in Frexp, Ilogb, Ldexp, and Logb (thanks Eoghan Sherry). +* net, syscall: return source address in Recvmsg (thanks Albert Strasheim). +* net: add LookupAddr (thanks Kyle Lemons), + add unixpacket (thanks Albert Strasheim), + avoid nil dereference if /etc/services can't be opened (thanks Corey Thomasson), + implement windows timeout (thanks Wei Guangjing). +* netchan: do not block sends; implement flow control (thanks Roger Peppe). +* regexp: reject bare '?'. (thanks Ben Lynn) +* runtime/cgo: don't define crosscall2 in dummy _cgo_main.c. +* runtime/debug: new package for printing stack traces from a running goroutine. +* runtime: add per-pause gc stats, + fix arm reflect.call boundary case, + print signal information during panic. +* spec: specify that int and uint have the same size. +* syscall: correct WSTOPPED on OS X, + correct length of GNU/Linux abstract Unix domain sockaddr, + correct length of SockaddrUnix. +* tutorial: make stdin, stdout, stderr work on Windows. +* windows: implement exception handling (thanks Hector Chu). +</pre> + <h3 id="2011-01-12">2011-01-12</h3> <pre> @@ -118,16 +332,16 @@ outstanding cgo issues were resolved. <pre> Package crypto/cipher has been started, to replace crypto/block. -As part of the changes, rc4.Cipher’s XORKeyStream method signature has changed from +As part of the changes, rc4.Cipher's XORKeyStream method signature has changed from XORKeyStream(buf []byte) to XORKeyStream(dst, src []byte) -to implement the cipher.Stream interface. If you use crypto/block, you’ll need +to implement the cipher.Stream interface. If you use crypto/block, you'll need to switch to crypto/cipher once it is complete. -Package smtp’s StartTLS now takes a *tls.Config argument. +Package smtp's StartTLS now takes a *tls.Config argument. -Package reflect’s ArrayCopy has been renamed to Copy. There are new functions +Package reflect's ArrayCopy has been renamed to Copy. There are new functions Append and AppendSlice. The print/println bootstrapping functions now write to standard error. @@ -261,7 +475,7 @@ will fail to compile rather than behave erroneously. The bytes package has changed. Its Add and AddByte functions have been removed, as their functionality is provided by the recently-introduced built-in function -“append”. Any code that uses them will need to be changed: +"append". Any code that uses them will need to be changed: s = bytes.Add(s, b) -> s = append(s, b...) s = bytes.AddByte(b, c) -> s = append(s, b) s = bytes.Add(nil, c) -> append([]byte(nil), c) @@ -286,8 +500,8 @@ or and the fields are passed as successive arguments to the formatter, by analogy to fmt.Print. -The utf8 package has changed. The order of EncodeRune’s arguments has been -reversed to satisfy the convention of “destination first”. +The utf8 package has changed. The order of EncodeRune's arguments has been +reversed to satisfy the convention of "destination first". Any code that uses EncodeRune will need to be updated. Other changes: @@ -425,12 +639,12 @@ to address both of these deficiencies. The syntax for arrays, slices, and maps of composite literals has been simplified. Within a composite literal of array, slice, or map type, elements that are themselves composite literals may elide the type if it is identical to -the outer literal’s element type. For example, these expressions: +the outer literal's element type. For example, these expressions: [][]int{[]int{1, 2, 3}, []int{4, 5}} - map[string]Point{“x”: Point{1.5, -3.5}, “y”: Point{0, 0}} + map[string]Point{"x": Point{1.5, -3.5}, "y": Point{0, 0}} can be simplified to: [][]int{{1, 2, 3}, {4, 5}} - map[string]Point{“x”: {1.5, -3.5}, “y”: {0, 0}} + map[string]Point{"x": {1.5, -3.5}, "y": {0, 0}} Gofmt can make these simplifications mechanically when invoked with the new -s flag. @@ -446,8 +660,8 @@ The gob package can now encode and decode interface values containing types registered ahead of time with the new Register function. These changes required a backwards-incompatible change to the wire format. Data written with the old version of the package will not be readable with the new one, and vice versa. -(Steps were made in this change to make sure this doesn’t happen again.) -We don’t know of anyone using gobs to create permanent data, but if you do this +(Steps were made in this change to make sure this doesn't happen again.) +We don't know of anyone using gobs to create permanent data, but if you do this and need help converting, please let us know, and do not update to this release yet. We will help you convert your data. @@ -543,7 +757,7 @@ For full details, see the change description: The language change is that uses of pointers to interface values no longer automatically dereference the pointer. A pointer to an interface value is more -often a beginner’s bug than correct code. +often a beginner's bug than correct code. The package exp/iterable has been removed. It was an interesting experiment, but it encourages writing inefficient code and has outlived its utility. diff --git a/doc/devel/roadmap.html b/doc/devel/roadmap.html index 021ed6478..9a3c4eaba 100644 --- a/doc/devel/roadmap.html +++ b/doc/devel/roadmap.html @@ -58,8 +58,6 @@ Implement goto restrictions. <li> Improved optimization. <li> -5g: Better floating point support. -<li> Use escape analysis to keep more data on stack. </ul> @@ -106,5 +104,6 @@ Public continuous build and benchmark infrastructure (gobuilder). Package manager (goinstall). <li> A means of recovering from a panic (recover). +<li> +5g: Better floating point support. </ul> - diff --git a/doc/effective_go.html b/doc/effective_go.html index 26e317b5d..3f6f89b8b 100644 --- a/doc/effective_go.html +++ b/doc/effective_go.html @@ -1124,14 +1124,14 @@ you can pass a pointer to the array. </p> <pre> -func Sum(a *[3]float) (sum float) { +func Sum(a *[3]float64) (sum float64) { for _, v := range *a { sum += v } return } -array := [...]float{7.0, 8.5, 9.1} +array := [...]float64{7.0, 8.5, 9.1} x := Sum(&array) // Note the explicit address-of operator </pre> @@ -1233,7 +1233,8 @@ Maps are a convenient and powerful built-in data structure to associate values of different types. The key can be of any type for which the equality operator is defined, such as integers, -floats, strings, pointers, and interfaces (as long as the dynamic type +floating point and complex numbers, +strings, pointers, and interfaces (as long as the dynamic type supports equality). Structs, arrays and slices cannot be used as map keys, because equality is not defined on those types. Like slices, maps are a reference type. If you pass a map to a function @@ -1652,7 +1653,7 @@ correctness of the program state before real execution begins. <pre> func init() { if USER == "" { - log.Exit("$USER not set") + log.Fatal("$USER not set") } if HOME == "" { HOME = "/usr/" + USER @@ -1806,7 +1807,7 @@ Because the two types (<code>Sequence</code> and <code>[]int</code>) are the same if we ignore the type name, it's legal to convert between them. The conversion doesn't create a new value, it just temporarily acts as though the existing value has a new type. -(There are other legal conversions, such as from integer to float, that +(There are other legal conversions, such as from integer to floating point, that do create a new value.) </p> <p> @@ -2525,39 +2526,49 @@ var serverChan = make(chan *Buffer) func client() { for { - b, ok := <-freeList // grab a buffer if available - if !ok { // if not, allocate a new one + var b *Buffer + // Grab a buffer if available; allocate if not. + select { + case b = <-freeList: + // Got one; nothing more to do. + default: + // None free, so allocate a new one. b = new(Buffer) } - load(b) // read next message from the net - serverChan <- b // send to server + load(b) // Read next message from the net. + serverChan <- b // Send to server. } } </pre> <p> -The server loop receives messages from the client, processes them, +The server loop receives each message from the client, processes it, and returns the buffer to the free list. </p> <pre> func server() { for { - b := <-serverChan // wait for work + b := <-serverChan // Wait for work. process(b) - _ = freeList <- b // reuse buffer if room + // Reuse buffer if there's room. + select { + case freeList <- b: + // Buffer on free list; nothing more to do. + default: + // Free list full, just carry on. + } } } </pre> <p> -The client's non-blocking receive from <code>freeList</code> obtains a -buffer if one is available; otherwise the client allocates -a fresh one. -The server's non-blocking send on freeList puts <code>b</code> back +The client attempts to retrieve a buffer from <code>freeList</code>; +if none is available, it allocates a fresh one. +The server's send to <code>freeList</code> puts <code>b</code> back on the free list unless the list is full, in which case the buffer is dropped on the floor to be reclaimed by the garbage collector. -(The assignment of the send operation to the blank identifier -makes it non-blocking but ignores whether -the operation succeeded.) +(The <code>default</code> clauses in the <code>select</code> +statements execute when no other case is ready, +meaning that the <code>selects</code> never block.) This implementation builds a leaky bucket free list in just a few lines, relying on the buffered channel and the garbage collector for bookkeeping. @@ -2860,7 +2871,7 @@ func main() { http.Handle("/", http.HandlerFunc(QR)) err := http.ListenAndServe(*addr, nil) if err != nil { - log.Exit("ListenAndServe:", err) + log.Fatal("ListenAndServe:", err) } } diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html index 393e57963..2ab6dcdae 100644 --- a/doc/gccgo_install.html +++ b/doc/gccgo_install.html @@ -296,8 +296,8 @@ than one value, the C function returns a struct. For example, these functions have equivalent types: <pre> -func GoFunction(int) (int, float) -struct { int i; float f; } CFunction(int) +func GoFunction(int) (int, float64) +struct { int i; float64 f; } CFunction(int) </pre> <p> diff --git a/doc/go_faq.html b/doc/go_faq.html index 1c7b85ef8..3f9c1d246 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -665,11 +665,16 @@ of Effective Go</a> for more details. Why is <code>int</code> 32 bits on 64 bit machines?</h3> <p> -The size of <code>int</code> and <code>float</code> is implementation-specific. +The sizes of <code>int</code> and <code>uint</code> are implementation-specific +but the same as each other on a given platform. The 64 bit Go compilers (both 6g and gccgo) use a 32 bit representation for -both <code>int</code> and <code>float</code>. Code that relies on a particular -size of value should use an explicitly sized type, like <code>int64</code> or -<code>float64</code>. +<code>int</code>. Code that relies on a particular +size of value should use an explicitly sized type, like <code>int64</code>. +On the other hand, floating-point scalars and complex +numbers are always sized: <code>float32</code>, <code>complex64</code>, +etc., because programmers should be aware of precision when using +floating-point numbers. +The default size of a floating-point constant is <code>float64</code>. </p> <h2 id="Concurrency">Concurrency</h2> @@ -788,7 +793,7 @@ Consider the following program: func main() { done := make(chan bool) - values = []string{ "a", "b", "c" } + values := []string{ "a", "b", "c" } for _, v := range values { go func() { fmt.Println(v) @@ -797,7 +802,7 @@ func main() { } // wait for all goroutines to complete before exiting - for i := range values { + for _ = range values { <-done } } @@ -818,7 +823,7 @@ could modify the inner loop to read: <pre> for _, v := range values { - go func(<b>u</b>) { + go func(<b>u</b> string) { fmt.Println(<b>u</b>) done <- true }(<b>v</b>) diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html index fae2ec44e..608ab147b 100644 --- a/doc/go_for_cpp_programmers.html +++ b/doc/go_for_cpp_programmers.html @@ -107,7 +107,7 @@ parentheses. <pre> var ( i int - m float + m float64 ) </pre> diff --git a/doc/go_spec.html b/doc/go_spec.html index e1c7e90e2..4e5d9c639 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,5 +1,5 @@ <!-- title The Go Programming Language Specification --> -<!-- subtitle Version of January 7, 2011 --> +<!-- subtitle Version of February 1, 2011 --> <!-- TODO @@ -11,7 +11,7 @@ TODO (struct{T} vs struct {T T} vs struct {t T}) [ ] need explicit language about the result type of operations [ ] may want to have some examples for the types of shift operations -[ ] should string(1<<s) and float(1<<s) be valid? +[ ] should string(1<<s) and float32(1<<s) be valid? [ ] should probably write something about evaluation order of statements even though obvious [ ] review language on implicit dereferencing @@ -531,7 +531,7 @@ the result value of some built-in functions such as <code>cap</code> or <code>len</code> applied to <a href="#Length_and_capacity">some expressions</a>, <code>real</code> and <code>imag</code> applied to a complex constant -and <code>cmplx</code> applied to numeric constants. +and <code>complex</code> applied to numeric constants. The boolean truth values are represented by the predeclared constants <code>true</code> and <code>false</code>. The predeclared identifier <a href="#Iota">iota</a> denotes an integer constant. @@ -561,7 +561,7 @@ or <a href="#Conversions">conversion</a>, or implicitly when used in a <a href="#Assignments">assignment</a> or as an operand in an <a href="#Expressions">expression</a>. It is an error if the constant value -cannot be accurately represented as a value of the respective type. +cannot be represented as a value of the respective type. For instance, <code>3.0</code> can be given any integer or any floating-point type, while <code>2147483648.0</code> (equal to <code>1<<31</code>) can be given the types <code>float32</code>, <code>float64</code>, or <code>uint32</code> but @@ -699,9 +699,7 @@ There is also a set of predeclared numeric types with implementation-specific si <pre class="grammar"> uint either 32 or 64 bits -int either 32 or 64 bits -float either 32 or 64 bits -complex real and imaginary parts have type float +int same size as uint uintptr an unsigned integer large enough to store the uninterpreted bits of a pointer value </pre> @@ -871,8 +869,8 @@ struct {} // A struct with 6 fields. struct { x, y int - u float - _ float // padding + u float32 + _ float32 // padding A *[]int F func() } @@ -1007,10 +1005,10 @@ func() func(x int) func() int func(prefix string, values ...int) -func(a, b int, z float) bool -func(a, b int, z float) (bool) -func(a, b int, z float, opt ...interface{}) (success bool) -func(int, int, float) (float, *[]int) +func(a, b int, z float32) bool +func(a, b int, z float32) (bool) +func(a, b int, z float64, opt ...interface{}) (success bool) +func(int, int, float64) (float64, *[]int) func(n int) func(p *T) </pre> @@ -1146,7 +1144,7 @@ failure will cause a <a href="#Run_time_panics">run-time panic</a>. <pre> map [string] int -map [*T] struct { x, y float } +map [*T] struct { x, y float64 } map [string] interface {} </pre> @@ -1197,7 +1195,7 @@ A channel may be constrained only to send or only to receive by <pre> chan T // can be used to send and receive values of type T -chan<- float // can only be used to send floats +chan<- float64 // can only be used to send float64s <-chan int // can only be used to receive ints </pre> @@ -1291,8 +1289,8 @@ type ( T1 []string T2 struct { a, b int } T3 struct { a, c int } - T4 func(int, float) *T0 - T5 func(x int, y float) *[]string + T4 func(int, float64) *T0 + T5 func(x int, y float64) *[]string ) </pre> @@ -1304,13 +1302,13 @@ these types are identical: T0 and T0 []int and []int struct { a, b *T5 } and struct { a, b *T5 } -func(x int, y float) *[]string and func(int, float) (result *[]string) +func(x int, y float64) *[]string and func(int, float64) (result *[]string) </pre> <p> <code>T0</code> and <code>T1</code> are different because they are named types -with distinct declarations; <code>func(int, float) *T0</code> and -<code>func(x int, y float) *[]string</code> are different because <code>T0</code> +with distinct declarations; <code>func(int, float64) *T0</code> and +<code>func(x int, y float64) *[]string</code> are different because <code>T0</code> is different from <code>[]string</code>. </p> @@ -1483,7 +1481,7 @@ Basic types: int8 int16 int32 int64 string uint8 uint16 uint32 uint64 Architecture-specific convenience types: - complex float int uint uintptr + int uint uintptr Constants: true false iota @@ -1492,7 +1490,7 @@ Zero value: nil Functions: - append cap close closed cmplx copy imag len + append cap close closed complex copy imag len make new panic print println real recover </pre> @@ -1561,7 +1559,7 @@ const ( eof = -1 // untyped integer constant ) const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", untyped integer and string constants -const u, v float = 0, 3 // u = 0.0, v = 3.0 +const u, v float32 = 0, 3 // u = 0.0, v = 3.0 </pre> <p> @@ -1614,9 +1612,9 @@ const ( ) const ( - u = iota * 42 // u == 0 (untyped integer constant) - v float = iota * 42 // v == 42.0 (float constant) - w = iota * 42 // w == 84 (untyped integer constant) + u = iota * 42 // u == 0 (untyped integer constant) + v float64 = iota * 42 // v == 42.0 (float64 constant) + w = iota * 42 // w == 84 (untyped integer constant) ) const x = iota // x == 0 (iota has been reset) @@ -1736,9 +1734,9 @@ VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList <pre> var i int -var U, V, W float +var U, V, W float64 var k = 0 -var x, y float = -1, -2 +var x, y float32 = -1, -2 var ( i int u, v, s = 2.0, 3.0, "bar" @@ -1763,7 +1761,7 @@ of the expression list. <p> If the type is absent and the corresponding expression evaluates to an untyped <a href="#Constants">constant</a>, the type of the declared variable -is <code>bool</code>, <code>int</code>, <code>float</code>, or <code>string</code> +is <code>bool</code>, <code>int</code>, <code>float64</code>, or <code>string</code> respectively, depending on whether the value is a boolean, integer, floating-point, or string constant: </p> @@ -1771,7 +1769,7 @@ floating-point, or string constant: <pre> var b = true // t has type bool var i = 0 // i has type int -var f = 3.0 // f has type float +var f = 3.0 // f has type float64 var s = "OMDB" // s has type string </pre> @@ -2055,7 +2053,7 @@ For array and slice literals the following rules apply: <p> Taking the address of a composite literal (§<a href="#Address_operators">Address operators</a>) -generates a unique pointer to an instance of the literal's value. +generates a pointer to a unique instance of the literal's value. </p> <pre> var pointer *Point3D = &Point3D{y: 1000} @@ -2132,11 +2130,11 @@ primes := []int{2, 3, 5, 7, 9, 11, 13, 17, 19, 991} // vowels[ch] is true if ch is a vowel vowels := [128]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true, 'y': true} -// the array [10]float{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} -filter := [10]float{-1, 4: -0.1, -0.1, 9: -1} +// the array [10]float32{-1, 0, 0, 0, -0.1, -0.1, 0, 0, 0, -1} +filter := [10]float32{-1, 4: -0.1, -0.1, 9: -1} // frequencies in Hz for equal-tempered scale (A4 = 440Hz) -noteFrequency := map[string]float{ +noteFrequency := map[string]float32{ "C0": 16.35, "D0": 18.35, "E0": 20.60, "F0": 21.83, "G0": 24.50, "A0": 27.50, "B0": 30.87, } @@ -2155,7 +2153,7 @@ FunctionLit = FunctionType Body . </pre> <pre> -func(a, b int, z float) bool { return a*b < int(z) } +func(a, b int, z float64) bool { return a*b < int(z) } </pre> <p> @@ -2590,7 +2588,7 @@ func Join(s, t string) string { } if Join(Split(value, len(value)/2)) != value { - log.Crash("test fails") + log.Panic("test fails") } </pre> @@ -2669,9 +2667,7 @@ Operators combine operands into expressions. Expression = UnaryExpr | Expression binary_op UnaryExpr . UnaryExpr = PrimaryExpr | unary_op UnaryExpr . -binary_op = log_op | com_op | rel_op | add_op | mul_op . -log_op = "||" | "&&" . -com_op = "<-" . +binary_op = "||" | "&&" | rel_op | add_op | mul_op . rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" . add_op = "+" | "-" | "|" | "^" . mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" . @@ -2713,11 +2709,11 @@ the left operand alone. <pre> var s uint = 33 -var i = 1<<s // 1 has type int -var j = int32(1<<s) // 1 has type int32; j == 0 -var u = uint64(1<<s) // 1 has type uint64; u == 1<<33 -var f = float(1<<s) // illegal: 1 has type float, cannot shift -var g = float(1<<33) // legal; 1<<33 is a constant shift operation; g == 1<<33 +var i = 1<<s // 1 has type int +var j = int32(1<<s) // 1 has type int32; j == 0 +var u = uint64(1<<s) // 1 has type uint64; u == 1<<33 +var f = float32(1<<s) // illegal: 1 has type float32, cannot shift +var g = float32(1<<33) // legal; 1<<33 is a constant shift operation; g == 1<<33 </pre> <h3 id="Operator_precedence">Operator precedence</h3> @@ -2728,18 +2724,17 @@ statements, not expressions, they fall outside the operator hierarchy. As a consequence, statement <code>*p++</code> is the same as <code>(*p)++</code>. <p> -There are six precedence levels for binary operators. +There are five precedence levels for binary operators. Multiplication operators bind strongest, followed by addition -operators, comparison operators, <code><-</code> (channel send), -<code>&&</code> (logical and), and finally <code>||</code> (logical or): +operators, comparison operators, <code>&&</code> (logical and), +and finally <code>||</code> (logical or): </p> <pre class="grammar"> Precedence Operator - 6 * / % << >> & &^ - 5 + - | ^ - 4 == != < <= > >= - 3 <- + 5 * / % << >> & &^ + 4 + - | ^ + 3 == != < <= > >= 2 && 1 || </pre> @@ -2985,15 +2980,19 @@ The right operand is evaluated conditionally. <h3 id="Address_operators">Address operators</h3> <p> -The address-of operator <code>&</code> generates the address of its operand, -which must be <i>addressable</i>, +For an operand <code>x</code> of type <code>T</code>, the address operation +<code>&x</code> generates a pointer of type <code>*T</code> to <code>x</code>. +The operand must be <i>addressable</i>, that is, either a variable, pointer indirection, or slice indexing -operation; -or a field selector of an addressable struct operand; +operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. -Given an operand of pointer type, the pointer indirection -operator <code>*</code> retrieves the value pointed -to by the operand. +As an exception to the addressability requirement, <code>x</code> may also be a +<a href="#Composite_literals">composite literal</a>. +</p> +<p> +For an operand <code>x</code> of pointer type <code>*T</code>, the pointer +indirection <code>*x</code> denotes the value of type <code>T</code> pointed +to by <code>x</code>. </p> <pre> @@ -3003,76 +3002,28 @@ to by the operand. *pf(x) </pre> -<h3 id="Communication_operators">Communication operators</h3> - -<p> -The term <i>channel</i> means "value of <a href="#Channel_types">channel type</a>". -</p> -<p> -The send operation uses the binary operator "<-", which operates on -a channel and a value (expression): -</p> - -<pre> -ch <- 3 -</pre> - -<p> -The send operation sends the value on the channel. Both the channel -and the expression are evaluated before communication begins. -Communication blocks until the send can proceed, at which point the -value is transmitted on the channel. -A send on an unbuffered channel can proceed if a receiver is ready. -A send on a buffered channel can proceed if there is room in the buffer. -</p> -<p> -If the send operation appears in an expression context, the value -of the expression is a boolean and the operation is non-blocking. -The value of the boolean reports true if the communication succeeded, -false if it did not. (The channel and -the expression to be sent are evaluated regardless.) -These two examples are equivalent: -</p> - -<pre> -ok := ch <- 3 -if ok { print("sent") } else { print("not sent") } - -if ch <- 3 { print("sent") } else { print("not sent") } -</pre> - -<p> -In other words, if the program tests the value of a send operation, -the send is non-blocking and the value of the expression is the -success of the operation. If the program does not test the value, -the operation blocks until it succeeds. -</p> -<p> -The receive operation uses the prefix unary operator "<-". -The value of the expression is the value received, whose type -is the element type of the channel. -</p> -<pre> -<-ch -</pre> +<h3 id="Receive_operator">Receive operator</h3> <p> -The expression blocks until a value is available, which then can -be assigned to a variable or used like any other expression. -If the receive expression does not save the value, the value is -discarded. +For an operand <code>ch</code> of <a href="#Channel_types">channel type</a>, +the value of the receive operation <code><-ch</code> is the value received +from the channel <code>ch</code>. The type of the value is the element type of +the channel. The expression blocks until a value is available. </p> <pre> v1 := <-ch v2 = <-ch f(<-ch) -<-strobe // wait until clock pulse +<-strobe // wait until clock pulse and discard received value </pre> +<!-- + TODO(rsc): Add after a release or two without any x,ok := <-c. + <p> -If a receive expression is used in an assignment or initialization of the form +A receive expression used in an assignment or initialization of the form </p> <pre> @@ -3082,18 +3033,16 @@ var x, ok = <-ch </pre> <p> -the receive operation becomes non-blocking. -If the operation can proceed, the boolean variable -<code>ok</code> will be set to <code>true</code> -and the value stored in <code>x</code>; otherwise -<code>ok</code> is set -to <code>false</code> and <code>x</code> is set to the -zero value for its type (§<a href="#The_zero_value">The zero value</a>). +yields an additional result. +The boolean variable <code>ok</code> indicates whether +the received value was sent on the channel (<code>true</code>) +or is a <a href="#The_zero_value">zero value</a> returned +because the channel is closed and empty (<code>false</code>). </p> +--> <p> -Except in a communications clause of a <a href="#Select_statements">select statement</a>, -sending or receiving from a <code>nil</code> channel causes a +Receiving from a <code>nil</code> channel causes a <a href="#Run_time_panics">run-time panic</a>. </p> @@ -3104,6 +3053,7 @@ need to be presented regarding send, receive, select, and goroutines.</span> </p> ---> + <h3 id="Method_expressions">Method expressions</h3> <p> @@ -3128,8 +3078,8 @@ Consider a struct type <code>T</code> with two methods, type T struct { a int } -func (tv T) Mv(a int) int { return 0 } // value receiver -func (tp *T) Mp(f float) float { return 1 } // pointer receiver +func (tv T) Mv(a int) int { return 0 } // value receiver +func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver var t T </pre> @@ -3174,7 +3124,7 @@ yields a function value representing <code>Mp</code> with signature </p> <pre> -func(tp *T, f float) float +func(tp *T, f float32) float32 </pre> <p> @@ -3422,14 +3372,14 @@ result is an untyped complex constant. Complex constants are always constructed from constant expressions involving imaginary literals or constants derived from them, or calls of the built-in function -<a href="#Complex_numbers"><code>cmplx</code></a>. +<a href="#Complex_numbers"><code>complex</code></a>. </p> <pre> const Σ = 1 - 0.707i const Δ = Σ + 2.0e-4 - 1/1i const Φ = iota * 1i -const iΓ = cmplx(0, Γ) +const iΓ = complex(0, Γ) </pre> <p> @@ -3525,7 +3475,7 @@ Statement = FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt | DeferStmt . -SimpleStmt = EmptyStmt | ExpressionStmt | IncDecStmt | Assignment | ShortVarDecl . +SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl . </pre> @@ -3553,14 +3503,14 @@ Label = identifier . </pre> <pre> -Error: log.Crash("error encountered") +Error: log.Panic("error encountered") </pre> <h3 id="Expression_statements">Expression statements</h3> <p> -Function calls, method calls, and channel operations +Function calls, method calls, and receive operations can appear in statement context. </p> @@ -3570,11 +3520,44 @@ ExpressionStmt = Expression . </pre> <pre> -f(x+y) +h(x+y) +f.Close() <-ch </pre> +<h3 id="Send_statements">Send statements</h3> + +<p> +A send statement sends a value on a channel. +The channel expression must be of <a href="#Channel_types">channel type</a> +and the type of the value must be <a href="#Assignability">assignable</a> +to the channel's element type. +</p> + +<pre class="ebnf"> +SendStmt = Channel "<-" Expression . +Channel = Expression . +</pre> + +<p> +Both the channel and the value expression are evaluated before communication +begins. Communication blocks until the send can proceed, at which point the +value is transmitted on the channel. +A send on an unbuffered channel can proceed if a receiver is ready. +A send on a buffered channel can proceed if there is room in the buffer. +</p> + +<pre> +ch <- 3 +</pre> + +<p> +Sending to a <code>nil</code> channel causes a +<a href="#Run_time_panics">run-time panic</a>. +</p> + + <h3 id="IncDec_statements">IncDec statements</h3> <p> @@ -3680,8 +3663,8 @@ In assignments, each value must be <a href="#Assignability">assignable</a> to the type of the operand to which it is assigned. If an untyped <a href="#Constants">constant</a> is assigned to a variable of interface type, the constant is <a href="#Conversions">converted</a> -to type <code>bool</code>, <code>int</code>, <code>float</code>, -<code>complex</code> or <code>string</code> +to type <code>bool</code>, <code>int</code>, <code>float64</code>, +<code>complex128</code> or <code>string</code> respectively, depending on whether the value is a boolean, integer, floating-point, complex, or string constant. </p> @@ -3847,9 +3830,9 @@ case nil: printString("x is nil") case int: printInt(i) // i is an int -case float: - printFloat(i) // i is a float -case func(int) float: +case float64: + printFloat64(i) // i is a float64 +case func(int) float64: printFunction(i) // i is a function case bool, string: printString("type is bool or string") // i is an interface{} @@ -3868,9 +3851,9 @@ if v == nil { printString("x is nil") } else if i, is_int := v.(int); is_int { printInt(i) // i is an int -} else if i, is_float := v.(float); is_float { - printFloat(i) // i is a float -} else if i, is_func := v.(func(int) float); is_func { +} else if i, is_float64 := v.(float64); is_float64 { + printFloat64(i) // i is a float64 +} else if i, is_func := v.(func(int) float64); is_func { printFunction(i) // i is a function } else { i1, is_bool := v.(bool) @@ -4093,15 +4076,19 @@ cases all referring to communication operations. <pre class="ebnf"> SelectStmt = "select" "{" { CommClause } "}" . CommClause = CommCase ":" { Statement ";" } . -CommCase = "case" ( SendExpr | RecvExpr) | "default" . -SendExpr = Expression "<-" Expression . -RecvExpr = [ Expression ( "=" | ":=" ) ] "<-" Expression . +CommCase = "case" ( SendStmt | RecvStmt ) | "default" . +RecvStmt = [ Expression ( "=" | ":=" ) ] RecvExpr . +RecvExpr = Expression . </pre> +<!-- TODO(rsc): +RecvStmt = [ Expression [ "," Expression ] ( "=" | ":=" ) ] RecvExpr . +--> <p> -For all the send and receive expressions in the "select" +RecvExpr must be a <a href="#Receive_operator">receive operation</a>. +For all the cases in the "select" statement, the channel expressions are evaluated in top-to-bottom order, along with -any expressions that appear on the right hand side of send expressions. +any expressions that appear on the right hand side of send statements. A channel may be <code>nil</code>, which is equivalent to that case not being present in the select statement @@ -4126,6 +4113,7 @@ in the "select" statement. If multiple cases can proceed, a pseudo-random fair choice is made to decide which single communication will execute. <p> +<!-- TODO(rsc): s/variable/& or &s/ --> The receive case may declare a new variable using a <a href="#Short_variable_declarations">short variable declaration</a>. </p> @@ -4138,6 +4126,14 @@ case i1 = <-c1: print("received ", i1, " from c1\n") case c2 <- i2: print("sent ", i2, " to c2\n") +<!-- TODO(rsc): add , c3 to channel list above too +case i3, ok := <-c3: + if ok { + print("received ", i3, " from c3\n") + } else { + print("c3 is closed\n") + } +--> default: print("no communication\n") } @@ -4189,7 +4185,7 @@ func simple_f() int { return 2 } -func complex_f1() (re float, im float) { +func complex_f1() (re float64, im float64) { return -7.0, -4.0 } </pre> @@ -4201,7 +4197,7 @@ func complex_f1() (re float, im float) { "return" statement listing these variables, at which point the rules of the previous case apply. <pre> -func complex_f2() (re float, im float) { +func complex_f2() (re float64, im float64) { return complex_f1() } </pre> @@ -4212,7 +4208,7 @@ func complex_f2() (re float, im float) { and the function may assign values to them as necessary. The "return" statement returns the values of these variables. <pre> -func complex_f3() (re float, im float) { +func complex_f3() (re float64, im float64) { re = 7.0 im = 4.0 return @@ -4391,15 +4387,21 @@ BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" . BuiltinArgs = Type [ "," ExpressionList ] | ExpressionList . </pre> +<!-- TODO(rsc): s/.and.closed//g --> <h3 id="Close_and_closed">Close and closed</h3> <p> For a channel <code>c</code>, the built-in function <code>close(c)</code> marks the channel as unable to accept more values through a send operation; -values sent to a closed channel are ignored. +sending to or closing a closed channel causes a <a href="#Run_time_panics">run-time panic</a>. After calling <code>close</code>, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking. + +<!-- TODO(rsc): delete next sentence, replace with + The multi-valued <a href="#Receive_operator">receive operation</a> + returns a received value along with an indication of whether the channel is closed. +--> After at least one such zero value has been received, <code>closed(c)</code> returns true. </p> @@ -4474,7 +4476,7 @@ For instance </p> <pre> -type S struct { a int; b float } +type S struct { a int; b float64 } new(S) </pre> @@ -4593,29 +4595,28 @@ n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello") <p> Three functions assemble and disassemble complex numbers. -The built-in function <code>cmplx</code> constructs a complex +The built-in function <code>complex</code> constructs a complex value from a floating-point real and imaginary part, while <code>real</code> and <code>imag</code> extract the real and imaginary parts of a complex value. </p> <pre class="grammar"> -cmplx(realPart, imaginaryPart floatT) complexT +complex(realPart, imaginaryPart floatT) complexT real(complexT) floatT imag(complexT) floatT </pre> <p> The type of the arguments and return value correspond. -For <code>cmplx</code>, the two arguments must be of the same +For <code>complex</code>, the two arguments must be of the same floating-point type and the return type is the complex type with the corresponding floating-point constituents: -<code>complex</code> for <code>float</code>, <code>complex64</code> for <code>float32</code>, <code>complex128</code> for <code>float64</code>. The <code>real</code> and <code>imag</code> functions together form the inverse, so for a complex value <code>z</code>, -<code>z</code> <code>==</code> <code>cmplx(real(z),</code> <code>imag(z))</code>. +<code>z</code> <code>==</code> <code>complex(real(z),</code> <code>imag(z))</code>. </p> <p> @@ -4624,12 +4625,12 @@ value is a constant. </p> <pre> -var a = cmplx(2, -2) // has type complex -var b = cmplx(1.0, -1.4) // has type complex -x := float32(math.Cos(math.Pi/2)) -var c64 = cmplx(5, -x) // has type complex64 -var im = imag(b) // has type float -var rl = real(c64) // type float32 +var a = complex(2, -2) // complex128 +var b = complex(1.0, -1.4) // complex128 +x := float32(math.Cos(math.Pi/2)) // float32 +var c64 = complex(5, -x) // complex64 +var im = imag(b) // float64 +var rl = real(c64) // float32 </pre> <h3 id="Handling_panics">Handling panics</h3> @@ -4984,7 +4985,7 @@ After </p> <pre> -type T struct { i int; f float; next *T } +type T struct { i int; f float64; next *T } t := new(T) </pre> diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html index 11e9b4ad7..ece22036a 100644 --- a/doc/go_tutorial.html +++ b/doc/go_tutorial.html @@ -238,14 +238,19 @@ started; for instance, <code>os.Args</code> is a slice used by the <p> <h2>An Interlude about Types</h2> <p> -Go has some familiar types such as <code>int</code> and <code>float</code>, which represent +Go has some familiar types such as <code>int</code> and <code>uint</code> (unsigned <code>int</code>), which represent values of the ''appropriate'' size for the machine. It also defines explicitly-sized types such as <code>int8</code>, <code>float64</code>, and so on, plus -unsigned integer types such as <code>uint</code>, <code>uint32</code>, etc. These are -distinct types; even if <code>int</code> and <code>int32</code> are both 32 bits in size, +unsigned integer types such as <code>uint</code>, <code>uint32</code>, etc. +These are distinct types; even if <code>int</code> and <code>int32</code> are both 32 bits in size, they are not the same type. There is also a <code>byte</code> synonym for <code>uint8</code>, which is the element type for strings. <p> +Floating-point types are always sized: <code>float32</code> and <code>float64</code>, +plus <code>complex64</code> (two <code>float32s</code>) and <code>complex128</code> +(two <code>float64s</code>). Complex numbers are outside the +scope of this tutorial. +<p> Speaking of <code>string</code>, that's a built-in type as well. Strings are <i>immutable values</i>—they are not just arrays of <code>byte</code> values. Once you've built a string <i>value</i>, you can't change it, although @@ -452,14 +457,15 @@ language specification but here are some illustrative examples: a := uint64(0) // equivalent; uses a "conversion" i := 0x1234 // i gets default type: int var j int = 1e6 // legal - 1000000 is representable in an int - x := 1.5 // a float + x := 1.5 // a float64, the default type for floating constants i3div2 := 3/2 // integer division - result is 1 - f3div2 := 3./2. // floating point division - result is 1.5 + f3div2 := 3./2. // floating-point division - result is 1.5 </pre> <p> Conversions only work for simple cases such as converting <code>ints</code> of one -sign or size to another, and between <code>ints</code> and <code>floats</code>, plus a few other -simple cases. There are no automatic numeric conversions of any kind in Go, +sign or size to another and between integers and floating-point numbers, +plus a couple of other instances outside the scope of a tutorial. +There are no automatic numeric conversions of any kind in Go, other than that of making constants have concrete size and type when assigned to a variable. <p> @@ -538,9 +544,9 @@ We can use the factory to construct some familiar, exported variables of type <c <p> <pre> <!-- progs/file.go /var/ /^.$/ --> 24 var ( -25 Stdin = newFile(0, "/dev/stdin") -26 Stdout = newFile(1, "/dev/stdout") -27 Stderr = newFile(2, "/dev/stderr") +25 Stdin = newFile(syscall.Stdin, "/dev/stdin") +26 Stdout = newFile(syscall.Stdout, "/dev/stdout") +27 Stderr = newFile(syscall.Stderr, "/dev/stderr") 28 ) </pre> <p> @@ -663,7 +669,7 @@ something from the directory of installed packages. (Also, ''<code>file.go</code>'' must be compiled before we can import the package.) <p> -Now we can compile and run the program: +Now we can compile and run the program. On Unix, this would be the result: <p> <pre> $ 6g file.go # compile file package diff --git a/doc/go_tutorial.txt b/doc/go_tutorial.txt index 9c08bd278..5eea3c980 100644 --- a/doc/go_tutorial.txt +++ b/doc/go_tutorial.txt @@ -189,14 +189,19 @@ started; for instance, "os.Args" is a slice used by the An Interlude about Types ---- -Go has some familiar types such as "int" and "float", which represent +Go has some familiar types such as "int" and "uint" (unsigned "int"), which represent values of the ''appropriate'' size for the machine. It also defines explicitly-sized types such as "int8", "float64", and so on, plus -unsigned integer types such as "uint", "uint32", etc. These are -distinct types; even if "int" and "int32" are both 32 bits in size, +unsigned integer types such as "uint", "uint32", etc. +These are distinct types; even if "int" and "int32" are both 32 bits in size, they are not the same type. There is also a "byte" synonym for "uint8", which is the element type for strings. +Floating-point types are always sized: "float32" and "float64", +plus "complex64" (two "float32s") and "complex128" +(two "float64s"). Complex numbers are outside the +scope of this tutorial. + Speaking of "string", that's a built-in type as well. Strings are <i>immutable values</i>—they are not just arrays of "byte" values. Once you've built a string <i>value</i>, you can't change it, although @@ -362,13 +367,14 @@ language specification but here are some illustrative examples: a := uint64(0) // equivalent; uses a "conversion" i := 0x1234 // i gets default type: int var j int = 1e6 // legal - 1000000 is representable in an int - x := 1.5 // a float + x := 1.5 // a float64, the default type for floating constants i3div2 := 3/2 // integer division - result is 1 - f3div2 := 3./2. // floating point division - result is 1.5 + f3div2 := 3./2. // floating-point division - result is 1.5 Conversions only work for simple cases such as converting "ints" of one -sign or size to another, and between "ints" and "floats", plus a few other -simple cases. There are no automatic numeric conversions of any kind in Go, +sign or size to another and between integers and floating-point numbers, +plus a couple of other instances outside the scope of a tutorial. +There are no automatic numeric conversions of any kind in Go, other than that of making constants have concrete size and type when assigned to a variable. @@ -482,7 +488,7 @@ something from the directory of installed packages. (Also, ''"file.go"'' must be compiled before we can import the package.) -Now we can compile and run the program: +Now we can compile and run the program. On Unix, this would be the result: $ 6g file.go # compile file package $ 6g helloworld3.go # compile main package diff --git a/doc/htmlgen.go b/doc/htmlgen.go index 4bed9ed73..5d0bad8b5 100644 --- a/doc/htmlgen.go +++ b/doc/htmlgen.go @@ -50,7 +50,7 @@ func read() { break } if err != nil { - log.Exit(err) + log.Fatal(err) } n := len(lines) lines = lines[0 : n+1] diff --git a/doc/install.html b/doc/install.html index 92b099fe8..5917da964 100644 --- a/doc/install.html +++ b/doc/install.html @@ -45,11 +45,10 @@ architectures. </dt> <dd> Incomplete. - It only supports Linux binaries, the optimizer is not enabled, - and floating point is performed entirely in software. + It only supports Linux binaries, the optimizer is incomplete, + and floating point uses the VFP unit. However, all tests pass. - Work on the optimizer and use of the VFP hardware - floating point unit is underway. + Work on the optimizer is continuing. Tested against a Nexus One. </dd> </dl> diff --git a/doc/progs/file.go b/doc/progs/file.go index d3fb5ae9e..df3a3cf71 100644 --- a/doc/progs/file.go +++ b/doc/progs/file.go @@ -22,9 +22,9 @@ func newFile(fd int, name string) *File { } var ( - Stdin = newFile(0, "/dev/stdin") - Stdout = newFile(1, "/dev/stdout") - Stderr = newFile(2, "/dev/stderr") + Stdin = newFile(syscall.Stdin, "/dev/stdin") + Stdout = newFile(syscall.Stdout, "/dev/stdout") + Stderr = newFile(syscall.Stderr, "/dev/stderr") ) func Open(name string, mode int, perm uint32) (file *File, err os.Error) { diff --git a/doc/progs/run b/doc/progs/run index 29f1f8152..241e65dfa 100755 --- a/doc/progs/run +++ b/doc/progs/run @@ -29,9 +29,8 @@ for i in \ sieve.go \ sieve1.go \ server1.go \ + strings.go \ ; do - BASE=$(basename $i .go) - $GC $i done @@ -58,6 +57,7 @@ testit helloworld "" "Hello, world; or Καλημέρα κόσμε; or こんに testit helloworld3 "" "hello, world can't open file; err=no such file or directory" testit echo "hello, world" "hello, world" testit sum "" "6" +testit strings "" "" alphabet=abcdefghijklmnopqrstuvwxyz rot13=nopqrstuvwxyzabcdefghijklm diff --git a/doc/progs/sort.go b/doc/progs/sort.go index 6738860d9..79e7f563e 100644 --- a/doc/progs/sort.go +++ b/doc/progs/sort.go @@ -37,11 +37,11 @@ func (p IntArray) Less(i, j int) bool { return p[i] < p[j] } func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } -type FloatArray []float +type Float64Array []float64 -func (p FloatArray) Len() int { return len(p) } -func (p FloatArray) Less(i, j int) bool { return p[i] < p[j] } -func (p FloatArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p Float64Array) Len() int { return len(p) } +func (p Float64Array) Less(i, j int) bool { return p[i] < p[j] } +func (p Float64Array) Swap(i, j int) { p[i], p[j] = p[j], p[i] } type StringArray []string @@ -54,10 +54,10 @@ func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // Convenience wrappers for common cases func SortInts(a []int) { Sort(IntArray(a)) } -func SortFloats(a []float) { Sort(FloatArray(a)) } +func SortFloat64s(a []float64) { Sort(Float64Array(a)) } func SortStrings(a []string) { Sort(StringArray(a)) } func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) } -func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)) } +func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Array(a)) } func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) } diff --git a/doc/progs/strings.go b/doc/progs/strings.go index 0ec25f8e8..2cdb6101a 100644 --- a/doc/progs/strings.go +++ b/doc/progs/strings.go @@ -4,7 +4,6 @@ package main -import "fmt" import "os" func main() { diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py index e8c84abec..095270577 100644 --- a/lib/codereview/codereview.py +++ b/lib/codereview/codereview.py @@ -139,6 +139,32 @@ def typecheck(s, t): if type(s) != t: raise util.Abort("type check failed: %s has type %s != %s" % (repr(s), type(s), t)) +# If we have to pass unicode instead of str, ustr does that conversion clearly. +def ustr(s): + typecheck(s, str) + return s.decode("utf-8") + +# Even with those, Mercurial still sometimes turns unicode into str +# and then tries to use it as ascii. Change Mercurial's default. +def set_mercurial_encoding_to_utf8(): + from mercurial import encoding + encoding.encoding = 'utf-8' + +set_mercurial_encoding_to_utf8() + +# Even with those we still run into problems. +# I tried to do things by the book but could not convince +# Mercurial to let me check in a change with UTF-8 in the +# CL description or author field, no matter how many conversions +# between str and unicode I inserted and despite changing the +# default encoding. I'm tired of this game, so set the default +# encoding for all of Python to 'utf-8', not 'ascii'. +def default_to_utf8(): + import sys + reload(sys) # site.py deleted setdefaultencoding; get it back + sys.setdefaultencoding('utf-8') + +default_to_utf8() ####################################################################### # Change list parsing. @@ -573,6 +599,16 @@ def CodeReviewDir(ui, repo): typecheck(dir, str) return dir +# Turn leading tabs into spaces, so that the common white space +# prefix doesn't get confused when people's editors write out +# some lines with spaces, some with tabs. Only a heuristic +# (some editors don't use 8 spaces either) but a useful one. +def TabsToSpaces(line): + i = 0 + while i < len(line) and line[i] == '\t': + i += 1 + return ' '*(8*i) + line[i:] + # Strip maximal common leading white space prefix from text def StripCommon(text): typecheck(text, str) @@ -581,6 +617,7 @@ def StripCommon(text): line = line.rstrip() if line == '': continue + line = TabsToSpaces(line) white = line[:len(line)-len(line.lstrip())] if ws == None: ws = white @@ -597,6 +634,7 @@ def StripCommon(text): t = '' for line in text.split('\n'): line = line.rstrip() + line = TabsToSpaces(line) if line.startswith(ws): line = line[len(ws):] if line == '' and t == '': @@ -638,28 +676,53 @@ def effective_revpair(repo): return cmdutil.revpair(repo, None) # Return list of changed files in repository that match pats. -def ChangedFiles(ui, repo, pats, opts): - # Find list of files being operated on. +# Warn about patterns that did not match. +def matchpats(ui, repo, pats, opts): matcher = cmdutil.match(repo, pats, opts) node1, node2 = effective_revpair(repo) - modified, added, removed = repo.status(node1, node2, matcher)[:3] + modified, added, removed, deleted, unknown, ignored, clean = repo.status(node1, node2, matcher, ignored=True, clean=True, unknown=True) + return (modified, added, removed, deleted, unknown, ignored, clean) + +# Return list of changed files in repository that match pats. +# The patterns came from the command line, so we warn +# if they have no effect or cannot be understood. +def ChangedFiles(ui, repo, pats, opts, taken=None): + taken = taken or {} + # Run each pattern separately so that we can warn about + # patterns that didn't do anything useful. + for p in pats: + modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, [p], opts) + redo = False + for f in unknown: + promptadd(ui, repo, f) + redo = True + for f in deleted: + promptremove(ui, repo, f) + redo = True + if redo: + modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, [p], opts) + for f in modified + added + removed: + if f in taken: + ui.warn("warning: %s already in CL %s\n" % (f, taken[f].name)) + if not modified and not added and not removed: + ui.warn("warning: %s did not match any modified files\n" % (p,)) + + # Again, all at once (eliminates duplicates) + modified, added, removed = matchpats(ui, repo, pats, opts)[:3] l = modified + added + removed l.sort() + if taken: + l = Sub(l, taken.keys()) return l # Return list of changed files in repository that match pats and still exist. def ChangedExistingFiles(ui, repo, pats, opts): - matcher = cmdutil.match(repo, pats, opts) - node1, node2 = effective_revpair(repo) - modified, added, _ = repo.status(node1, node2, matcher)[:3] + modified, added = matchpats(ui, repo, pats, opts)[:2] l = modified + added l.sort() return l # Return list of files claimed by existing CLs -def TakenFiles(ui, repo): - return Taken(ui, repo).keys() - def Taken(ui, repo): all = LoadAllCL(ui, repo, web=False) taken = {} @@ -670,7 +733,7 @@ def Taken(ui, repo): # Return list of changed files that are not claimed by other CLs def DefaultFiles(ui, repo, pats, opts): - return Sub(ChangedFiles(ui, repo, pats, opts), TakenFiles(ui, repo)) + return ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo)) def Sub(l1, l2): return [l for l in l1 if l not in l2] @@ -701,6 +764,39 @@ def Incoming(ui, repo, opts): _, incoming, _ = findcommonincoming(repo, getremote(ui, repo, opts)) return incoming +desc_re = '^(.+: |tag release\.|release\.|fix build)' + +desc_msg = '''Your CL description appears not to use the standard form. + +The first line of your change description is conventionally a +one-line summary of the change, prefixed by the primary affected package, +and is used as the subject for code review mail; the rest of the description +elaborates. + +Examples: + + encoding/rot13: new package + + math: add IsInf, IsNaN + + net: fix cname in LookupHost + + unicode: update to Unicode 5.0.2 + +''' + + + +def promptremove(ui, repo, f): + if promptyesno(ui, "hg remove %s (y/n)?" % (f,)): + if commands.remove(ui, repo, 'path:'+f) != 0: + ui.warn("error removing %s" % (f,)) + +def promptadd(ui, repo, f): + if promptyesno(ui, "hg add %s (y/n)?" % (f,)): + if commands.add(ui, repo, 'path:'+f) != 0: + ui.warn("error adding %s" % (f,)) + def EditCL(ui, repo, cl): set_status(None) # do not show status s = cl.EditorText() @@ -711,13 +807,54 @@ def EditCL(ui, repo, cl): if not promptyesno(ui, "error parsing change list: line %d: %s\nre-edit (y/n)?" % (line, err)): return "change list not modified" continue - cl.desc = clx.desc; + + # Check description. + if clx.desc == '': + if promptyesno(ui, "change list should have a description\nre-edit (y/n)?"): + continue + elif not re.match(desc_re, clx.desc.split('\n')[0]): + if promptyesno(ui, desc_msg + "re-edit (y/n)?"): + continue + + # Check file list for files that need to be hg added or hg removed + # or simply aren't understood. + pats = ['path:'+f for f in clx.files] + modified, added, removed, deleted, unknown, ignored, clean = matchpats(ui, repo, pats, {}) + files = [] + for f in clx.files: + if f in modified or f in added or f in removed: + files.append(f) + continue + if f in deleted: + promptremove(ui, repo, f) + files.append(f) + continue + if f in unknown: + promptadd(ui, repo, f) + files.append(f) + continue + if f in ignored: + ui.warn("error: %s is excluded by .hgignore; omitting\n" % (f,)) + continue + if f in clean: + ui.warn("warning: %s is listed in the CL but unchanged\n" % (f,)) + files.append(f) + continue + p = repo.root + '/' + f + if os.path.isfile(p): + ui.warn("warning: %s is a file but not known to hg\n" % (f,)) + files.append(f) + continue + if os.path.isdir(p): + ui.warn("error: %s is a directory, not a file; omitting\n" % (f,)) + continue + ui.warn("error: %s does not exist; omitting\n" % (f,)) + clx.files = files + + cl.desc = clx.desc cl.reviewer = clx.reviewer cl.cc = clx.cc cl.files = clx.files - if cl.desc == '': - if promptyesno(ui, "change list should have description\nre-edit (y/n)?"): - continue break return "" @@ -736,7 +873,7 @@ def CommandLineCL(ui, repo, pats, opts, defaultcc=None): else: cl = CL("new") cl.local = True - cl.files = Sub(ChangedFiles(ui, repo, pats, opts), TakenFiles(ui, repo)) + cl.files = ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo)) if not cl.files: return None, "no files changed" if opts.get('reviewer'): @@ -758,10 +895,11 @@ def CommandLineCL(ui, repo, pats, opts, defaultcc=None): # which expands the syntax @clnumber to mean the files # in that CL. original_match = None -def ReplacementForCmdutilMatch(repo, pats=[], opts={}, globbed=False, default='relpath'): +def ReplacementForCmdutilMatch(repo, pats=None, opts=None, globbed=False, default='relpath'): taken = [] files = [] pats = pats or [] + opts = opts or {} for p in pats: if p.startswith('@'): taken.append(p) @@ -799,7 +937,7 @@ def CheckGofmt(ui, repo, files, just_warn): if not files: return try: - cmd = subprocess.Popen(["gofmt", "-l"] + files, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + cmd = subprocess.Popen(["gofmt", "-l"] + files, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=sys.platform != "win32") cmd.stdin.close() except: raise util.Abort("gofmt: " + ExceptionDetail()) @@ -895,9 +1033,7 @@ def change(ui, repo, *pats, **opts): name = "new" cl = CL("new") dirty[cl] = True - files = ChangedFiles(ui, repo, pats, opts) - taken = TakenFiles(ui, repo) - files = Sub(files, taken) + files = ChangedFiles(ui, repo, pats, opts, taken=Taken(ui, repo)) if opts["delete"] or opts["deletelocal"]: if opts["delete"] and opts["deletelocal"]: @@ -1134,8 +1270,12 @@ def mail(ui, repo, *pats, **opts): return "no reviewers listed in CL" cl.cc = Sub(cl.cc, defaultcc) cl.reviewer = defaultcc - cl.Flush(ui, repo) - cl.Mail(ui, repo) + cl.Flush(ui, repo) + + if cl.files == []: + return "no changed files, not sending mail" + + cl.Mail(ui, repo) def nocommit(ui, repo, *pats, **opts): """(disabled when using this extension)""" @@ -1205,6 +1345,9 @@ def submit(ui, repo, *pats, **opts): if missing_codereview: return missing_codereview + # We already called this on startup but sometimes Mercurial forgets. + set_mercurial_encoding_to_utf8() + repo.ui.quiet = True if not opts["no_incoming"] and Incoming(ui, repo, opts): return "local repository out of date; must sync before submit" @@ -1217,6 +1360,7 @@ def submit(ui, repo, *pats, **opts): if cl.copied_from: user = cl.copied_from userline = CheckContributor(ui, repo, user) + typecheck(userline, str) about = "" if cl.reviewer: @@ -1246,6 +1390,7 @@ def submit(ui, repo, *pats, **opts): if cl.copied_from: about += "\nCommitter: " + CheckContributor(ui, repo, None) + "\n" + typecheck(about, str) if not cl.mailed and not cl.copied_from: # in case this is TBR cl.Mail(ui, repo) @@ -1254,7 +1399,9 @@ def submit(ui, repo, *pats, **opts): date = opts.get('date') if date: opts['date'] = util.parsedate(date) + typecheck(opts['date'], str) opts['message'] = cl.desc.rstrip() + "\n\n" + about + typecheck(opts['message'], str) if opts['dryrun']: print "NOT SUBMITTING:" @@ -1266,7 +1413,7 @@ def submit(ui, repo, *pats, **opts): return "dry run; not submitted" m = match.exact(repo.root, repo.getcwd(), cl.files) - node = repo.commit(opts['message'], userline, opts.get('date'), m) + node = repo.commit(ustr(opts['message']), ustr(userline), opts.get('date'), m) if not node: return "nothing changed" @@ -1707,7 +1854,7 @@ def MySend1(request_path, payload=None, def GetForm(url): f = FormParser() - f.feed(MySend(url).decode("utf-8")) # f.feed wants unicode + f.feed(ustr(MySend(url))) # f.feed wants unicode f.close() # convert back to utf-8 to restore sanity m = {} @@ -2280,10 +2427,18 @@ def GetRpcServer(options): def GetUserCredentials(): """Prompts the user for a username and password.""" + # Disable status prints so they don't obscure the password prompt. + global global_status + st = global_status + global_status = None + email = options.email if email is None: email = GetEmail("Email (login for uploading to %s)" % options.server) password = getpass.getpass("Password for %s: " % email) + + # Put status back. + global_status = st return (email, password) # If this is the dev_appserver, use fake authentication. @@ -2603,7 +2758,7 @@ class MercurialVCS(VersionControlSystem): self.base_rev = self.options.revision else: mqparent, err = RunShellWithReturnCode(['hg', 'log', '--rev', 'qparent', '--template={node}']) - if not err: + if not err and mqparent != "": self.base_rev = mqparent else: self.base_rev = RunShell(["hg", "parents", "-q"]).split(':')[1].strip() diff --git a/lib/godoc/package.html b/lib/godoc/package.html index 5dc61b7cd..570ae4016 100644 --- a/lib/godoc/package.html +++ b/lib/godoc/package.html @@ -5,9 +5,7 @@ --> {.section PAst} - <pre> - {@ FSet|html} - </pre> + <pre>{@ FSet|html}</pre> {.end} {.section PDoc} <!-- PackageName is printed as title by the top-level template --> diff --git a/lib/godoc/search.html b/lib/godoc/search.html index 3d3dd1958..58a933fef 100644 --- a/lib/godoc/search.html +++ b/lib/godoc/search.html @@ -79,6 +79,10 @@ {.repeated section Lines} <a href="/{Filename|url-src}?h={Query|urlquery-esc}#L{@|html-esc}">{@|html-esc}</a> {.end} + {.section Complete} + {.or} + ... + {.end} </td> </tr> {.end} diff --git a/misc/bbedit/Go.plist b/misc/bbedit/Go.plist index 39c8f0dc3..9dc3bf6f1 100755 --- a/misc/bbedit/Go.plist +++ b/misc/bbedit/Go.plist @@ -15,7 +15,6 @@ chan, close, closed, - cmplx, complex, complex128, complex64, @@ -27,7 +26,6 @@ else, fallthrough, false, - float, float32, float64, for, diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go index c2b105072..c188b2dd9 100644 --- a/misc/cgo/stdio/chain.go +++ b/misc/cgo/stdio/chain.go @@ -23,7 +23,7 @@ func link(left chan<- int, right <-chan int) { for { v := <-right stdio.Stdout.WriteString(strconv.Itoa(v) + "\n") - left <- 1+v + left <- 1 + v } } diff --git a/misc/dashboard/builder/main.go b/misc/dashboard/builder/main.go index 32a2e10da..7e80934e1 100644 --- a/misc/dashboard/builder/main.go +++ b/misc/dashboard/builder/main.go @@ -66,24 +66,24 @@ func main() { for i, builder := range flag.Args() { b, err := NewBuilder(builder) if err != nil { - log.Exit(err) + log.Fatal(err) } builders[i] = b } if err := os.RemoveAll(*buildroot); err != nil { - log.Exitf("Error removing build root (%s): %s", *buildroot, err) + log.Fatalf("Error removing build root (%s): %s", *buildroot, err) } if err := os.Mkdir(*buildroot, mkdirPerm); err != nil { - log.Exitf("Error making build root (%s): %s", *buildroot, err) + log.Fatalf("Error making build root (%s): %s", *buildroot, err) } if err := run(nil, *buildroot, "hg", "clone", hgUrl, goroot); err != nil { - log.Exit("Error cloning repository:", err) + log.Fatal("Error cloning repository:", err) } // if specified, build revision and return if *buildRevision != "" { c, err := getCommit(*buildRevision) if err != nil { - log.Exit("Error finding revision: ", err) + log.Fatal("Error finding revision: ", err) } for _, b := range builders { if err := b.buildCommit(c); err != nil { diff --git a/misc/fraise/go.plist b/misc/fraise/go.plist index 298361501..17f416221 100644 --- a/misc/fraise/go.plist +++ b/misc/fraise/go.plist @@ -70,7 +70,6 @@ <string>chan</string> <string>complex64</string> <string>complex128</string> - <string>float</string> <string>float32</string> <string>float64</string> <string>int</string> diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go index 5923360f6..bc11bb759 100644 --- a/misc/goplay/goplay.go +++ b/misc/goplay/goplay.go @@ -42,7 +42,7 @@ func main() { case "386": archChar = "8" default: - log.Exitln("unrecognized GOARCH:", runtime.GOARCH) + log.Fatalln("unrecognized GOARCH:", runtime.GOARCH) } // source of unique numbers @@ -54,7 +54,7 @@ func main() { http.HandleFunc("/", FrontPage) http.HandleFunc("/compile", Compile) - log.Exit(http.ListenAndServe(*httpListen, nil)) + log.Fatal(http.ListenAndServe(*httpListen, nil)) } // FrontPage is an HTTP handler that renders the goplay interface. diff --git a/misc/kate/go.xml b/misc/kate/go.xml index 3a5c39c94..b8ff59267 100644 --- a/misc/kate/go.xml +++ b/misc/kate/go.xml @@ -42,10 +42,8 @@ <item> bool </item> <item> byte </item> <item> chan </item> - <item> complex </item> <item> complex64 </item> <item> complex128 </item> - <item> float </item> <item> float32 </item> <item> float64 </item> <item> int </item> @@ -67,7 +65,7 @@ <item> cap </item> <item> close </item> <item> closed </item> - <item> cmplx </item> + <item> complex </item> <item> copy </item> <item> imag </item> <item> len </item> diff --git a/misc/vim/ftplugin/go/import.vim b/misc/vim/ftplugin/go/import.vim new file mode 100644 index 000000000..b5814ca5d --- /dev/null +++ b/misc/vim/ftplugin/go/import.vim @@ -0,0 +1,201 @@ +" Copyright 2011 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. +" +" import.vim: Vim commands to import/drop Go packages. +" +" This filetype plugin adds three new commands for go buffers: +" +" :Import {path} +" +" Import ensures that the provided package {path} is imported +" in the current Go buffer, using proper style and ordering. +" If {path} is already being imported, an error will be +" displayed and the buffer will be untouched. +" +" :ImportAs {localname} {path} +" +" Same as Import, but uses a custom local name for the package. +" +" :Drop {path} +" +" Remove the import line for the provided package {path}, if +" present in the current Go buffer. If {path} is not being +" imported, an error will be displayed and the buffer will be +" untouched. +" +" In addition to these commands, there are also two shortcuts mapped: +" +" \f - Runs :Import fmt +" \F - Runs :Drop fmt +" +" The backslash is the default maplocalleader, so it is possible that +" your vim is set to use a different character (:help maplocalleader). +" +if exists("b:did_ftplugin") + finish +endif + +command! -buffer -nargs=? Drop call s:SwitchImport(0, '', <f-args>) +command! -buffer -nargs=1 Import call s:SwitchImport(1, '', <f-args>) +command! -buffer -nargs=* ImportAs call s:SwitchImport(1, <f-args>) +map <buffer> <LocalLeader>f :Import fmt<CR> +map <buffer> <LocalLeader>F :Drop fmt<CR> + +function! s:SwitchImport(enabled, localname, path) + let view = winsaveview() + let path = a:path + + " Quotes are not necessary, so remove them if provided. + if path[0] == '"' + let path = strpart(path, 1) + endif + if path[len(path)-1] == '"' + let path = strpart(path, 0, len(path) - 1) + endif + if path == '' + call s:Error('Import path not provided') + return + endif + + let qpath = '"' . path . '"' + if a:localname != '' + let qlocalpath = a:localname . ' ' . qpath + else + let qlocalpath = qpath + endif + let indentstr = 0 + let packageline = -1 " Position of package name statement + let appendline = -1 " Position to introduce new import + let deleteline = -1 " Position of line with existing import + let linesdelta = 0 " Lines added/removed + + " Find proper place to add/remove import. + let line = 0 + while line <= line('$') + let linestr = getline(line) + + if linestr =~# '^package\s' + let packageline = line + let appendline = line + + elseif linestr =~# '^import\s\+(' + let appendstr = qlocalpath + let indentstr = 1 + let appendline = line + while line <= line("$") + let line = line + 1 + let linestr = getline(line) + let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)') + if empty(m) + continue + endif + if m[1] == ')' + break + endif + if a:localname != '' && m[3] != '' + let qlocalpath = printf('%-' . (len(m[3])-1) . 's %s', a:localname, qpath) + endif + let appendstr = m[2] . qlocalpath + let indentstr = 0 + if m[4] == path + let appendline = -1 + let deleteline = line + break + elseif m[4] < path + let appendline = line + endif + endwhile + break + + elseif linestr =~# '^import ' + if appendline == packageline + let appendstr = 'import ' . qlocalpath + let appendline = line - 1 + endif + let m = matchlist(linestr, '^import\(\s\+\)\(\S*\s*\)"\(.\+\)"') + if !empty(m) + if m[3] == path + let appendline = -1 + let deleteline = line + break + endif + if m[3] < path + let appendline = line + endif + if a:localname != '' && m[2] != '' + let qlocalpath = printf("%s %" . len(m[2])-1 . "s", a:localname, qpath) + endif + let appendstr = 'import' . m[1] . qlocalpath + endif + + elseif linestr =~# '^\(var\|const\|type\|func\)\>' + break + + endif + let line = line + 1 + endwhile + + " Append or remove the package import, as requested. + if a:enabled + if deleteline != -1 + call s:Error(qpath . ' already being imported') + elseif appendline == -1 + call s:Error('No package line found') + else + if appendline == packageline + call append(appendline + 0, '') + call append(appendline + 1, 'import (') + call append(appendline + 2, ')') + let appendline += 2 + let linesdelta += 3 + let appendstr = qlocalpath + let indentstr = 1 + endif + call append(appendline, appendstr) + execute appendline + 1 + if indentstr + execute 'normal >>' + endif + let linesdelta += 1 + endif + else + if deleteline == -1 + call s:Error(qpath . ' not being imported') + else + execute deleteline . 'd' + let linesdelta -= 1 + + if getline(deleteline-1) =~# '^import\s\+(' && getline(deleteline) =~# '^)' + " Delete empty import block + let deleteline -= 1 + execute deleteline . "d" + execute deleteline . "d" + let linesdelta -= 2 + endif + + if getline(deleteline) == '' && getline(deleteline - 1) == '' + " Delete spacing for removed line too. + execute deleteline . "d" + let linesdelta -= 1 + endif + endif + endif + + " Adjust view for any changes. + let view.lnum += linesdelta + let view.topline += linesdelta + if view.topline < 0 + let view.topline = 0 + endif + + " Put buffer back where it was. + call winrestview(view) + +endfunction + +function! s:Error(s) + echohl Error | echo a:s | echohl None +endfunction + +" vim:ts=4:sw=4:et diff --git a/misc/vim/readme.txt b/misc/vim/readme.txt index bb36d4bbe..f836f58f3 100644 --- a/misc/vim/readme.txt +++ b/misc/vim/readme.txt @@ -21,3 +21,17 @@ commands: ln -s $GOROOT/misc/vim/ftdetect/gofiletype.vim $HOME/.vim/ftdetect/ ln -s $GOROOT/misc/vim/syntax/go.vim $HOME/.vim/syntax echo "syntax on" >> $HOME/.vimrc + + +Vim filetype plugins for Go +=========================== + +To install one of the available filetype plugins for Go: + + 1. Same as 1 above. + 2. Copy or link one or more plugins from ftplugin/go/*.vim to the + Go-specific ftplugin directory underneath your vim runtime directory + (normally $HOME/.vim/ftplugin/go/*.vim). + 3. Add the following line to your .vimrc file (normally $HOME/.vimrc): + + filetype plugin on diff --git a/misc/vim/syntax/go.vim b/misc/vim/syntax/go.vim index 7adbe8e35..7507cada2 100644 --- a/misc/vim/syntax/go.vim +++ b/misc/vim/syntax/go.vim @@ -70,8 +70,8 @@ hi def link goRepeat Repeat syn keyword goType chan map bool string syn keyword goSignedInts int int8 int16 int32 int64 syn keyword goUnsignedInts byte uint uint8 uint16 uint32 uint64 uintptr -syn keyword goFloats float float32 float64 -syn keyword goComplexes complex complex64 complex128 +syn keyword goFloats float32 float64 +syn keyword goComplexes complex64 complex128 hi def link goType Type hi def link goSignedInts Type @@ -85,7 +85,7 @@ syn match goType /\<func\>/ syn match goDeclaration /^func\>/ " Predefined functions and values -syn keyword goBuiltins append cap close closed cmplx copy imag len +syn keyword goBuiltins append cap close closed complex copy imag len syn keyword goBuiltins make new panic print println real recover syn keyword goConstants iota true false nil @@ -198,4 +198,11 @@ endif hi def link goExtraType Type hi def link goSpaceError Error +" Search backwards for a global declaration to start processing the syntax. +"syn sync match goSync grouphere NONE /^\(const\|var\|type\|func\)\>/ + +" There's a bug in the implementation of grouphere. For now, use the +" following as a more expensive/less precise workaround. +syn sync minlines=500 + let b:current_syntax = "go" diff --git a/src/Make.pkg b/src/Make.pkg index ec7d5722e..0ffab7294 100644 --- a/src/Make.pkg +++ b/src/Make.pkg @@ -48,7 +48,7 @@ coverage: 6cov -g $(shell pwd) $O.out | grep -v '_test\.go:' CLEANFILES+=*.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* -CLEANFILES+=_cgo_.c _cgo_import.c _cgo_main.c +CLEANFILES+=_cgo_.c _cgo_import.c _cgo_main.c _cgo_flags _cgo_run CLEANFILES+=*.so _obj _test _testmain.go *.exe test: @@ -112,11 +112,21 @@ dir: # ifdef CGOFILES -_cgo_defun.c: $(CGOFILES) +_cgo_run: $(CGOFILES) + @touch _cgo_run CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES) +# _CGO_CFLAGS and _CGO_LDFLAGS are defined via the evaluation of _cgo_flags. +# The include happens before the commands in the recipe run, +# so it cannot be done in the same recipe that runs cgo. +_cgo_flags: _cgo_run + $(eval include _cgo_flags) + +# Include any previous flags in case cgo files are up to date. +-include _cgo_flags + # Ugly but necessary - cgo writes these files too. -_cgo_gotypes.go _cgo_export.c _cgo_export.h _cgo_main.c: _cgo_defun.c +_cgo_gotypes.go _cgo_export.c _cgo_export.h _cgo_main.c _cgo_defun.c: _cgo_flags @true %.cgo1.go %.cgo2.c: _cgo_defun.c @@ -125,7 +135,7 @@ endif # Compile rules for gcc source files. %.o: %.c - $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $*.c + $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) $*.c # To find out which symbols are needed from external libraries # and which libraries are needed, we build a simple a.out that @@ -136,10 +146,10 @@ endif # by Go code. That's crosscall2 and any exported symbols. _cgo_main.o: _cgo_main.c - $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) _cgo_main.c + $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $(_CGO_CFLAGS) _cgo_main.c _cgo1_.o: _cgo_main.o $(CGO_OFILES) - $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) + $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) $(_CGO_LDFLAGS) _cgo_import.c: _cgo1_.o cgo -dynimport _cgo1_.o >_$@ && mv -f _$@ $@ diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h index bc4f433e1..550b61dcf 100644 --- a/src/cmd/5a/a.h +++ b/src/cmd/5a/a.h @@ -54,7 +54,6 @@ typedef struct Hist Hist; #define NSYMB 8192 #define BUFSIZ 8192 #define HISTSZ 20 -#define NHUNK 10000 #define EOF (-1) #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 1328f4be6..032409bae 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -169,7 +169,7 @@ cgen(Node *n, Node *res) case OREAL: case OIMAG: - case OCMPLX: + case OCOMPLEX: fatal("unexpected complex"); break; @@ -567,7 +567,8 @@ agen(Node *n, Node *res) regalloc(&n1, tmp.type, N); gmove(&tmp, &n1); } - } else if(nl->addable) { + } else + if(nl->addable) { if(!isconst(nr, CTINT)) { tempname(&tmp, types[TINT32]); p2 = cgenindex(nr, &tmp); @@ -671,7 +672,8 @@ agen(Node *n, Node *res) p1 = gins(AMOVW, N, &n3); datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); p1->from.type = D_CONST; - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { + } else + if(isslice(nl->type) || nl->type->etype == TSTRING) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; @@ -813,6 +815,28 @@ agenr(Node *n, Node *a, Node *res) agen(n, a); } +void +gencmp0(Node *n, Type *t, int o, Prog *to) +{ + Node n1, n2, n3; + int a; + + regalloc(&n1, t, N); + cgen(n, &n1); + a = optoas(OCMP, t); + if(a != ACMP) { + nodconst(&n2, t, 0); + regalloc(&n3, t, N); + gmove(&n2, &n3); + gcmp(a, &n1, &n3); + regfree(&n3); + } else + gins(ATST, &n1, N); + a = optoas(o, t); + patch(gbranch(a, t), to); + regfree(&n1); +} + /* * generate: * if(n == true) goto to; @@ -855,19 +879,10 @@ bgen(Node *n, int true, Prog *to) switch(n->op) { default: - def: - regalloc(&n1, n->type, N); - cgen(n, &n1); - nodconst(&n2, n->type, 0); - regalloc(&n3, n->type, N); - gmove(&n2, &n3); - gcmp(optoas(OCMP, n->type), &n1, &n3); - a = ABNE; + a = ONE; if(!true) - a = ABEQ; - patch(gbranch(a, n->type), to); - regfree(&n1); - regfree(&n3); + a = OEQ; + gencmp0(n, n->type, a, to); goto ret; case OLITERAL: @@ -876,23 +891,6 @@ bgen(Node *n, int true, Prog *to) patch(gbranch(AB, T), to); goto ret; - case ONAME: - if(n->addable == 0) - goto def; - nodconst(&n1, n->type, 0); - regalloc(&n2, n->type, N); - regalloc(&n3, n->type, N); - gmove(&n1, &n2); - cgen(n, &n3); - gcmp(optoas(OCMP, n->type), &n2, &n3); - a = ABNE; - if(!true) - a = ABEQ; - patch(gbranch(a, n->type), to); - regfree(&n2); - regfree(&n3); - goto ret; - case OANDAND: if(!true) goto caseor; @@ -975,6 +973,16 @@ bgen(Node *n, int true, Prog *to) yyerror("illegal array comparison"); break; } + + regalloc(&n1, types[tptr], N); + agen(nl, &n1); + n2 = n1; + n2.op = OINDREG; + n2.xoffset = Array_array; + gencmp0(&n2, types[tptr], a, to); + regfree(&n1); + break; + a = optoas(a, types[tptr]); regalloc(&n1, types[tptr], N); regalloc(&n3, types[tptr], N); @@ -1000,6 +1008,16 @@ bgen(Node *n, int true, Prog *to) yyerror("illegal interface comparison"); break; } + + regalloc(&n1, types[tptr], N); + agen(nl, &n1); + n2 = n1; + n2.op = OINDREG; + n2.xoffset = 0; + gencmp0(&n2, types[tptr], a, to); + regfree(&n1); + break; + a = optoas(a, types[tptr]); regalloc(&n1, types[tptr], N); regalloc(&n3, types[tptr], N); @@ -1039,6 +1057,17 @@ bgen(Node *n, int true, Prog *to) break; } + if(nr->op == OLITERAL) { + if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) { + gencmp0(nl, nl->type, a, to); + break; + } + if(nr->val.ctype == CTNIL) { + gencmp0(nl, nl->type, a, to); + break; + } + } + a = optoas(a, nr->type); if(nr->ullman >= UINF) { @@ -1063,11 +1092,17 @@ bgen(Node *n, int true, Prog *to) break; } + tempname(&n3, nl->type); + cgen(nl, &n3); + + tempname(&tmp, nr->type); + cgen(nr, &tmp); + regalloc(&n1, nl->type, N); - cgen(nl, &n1); + gmove(&n3, &n1); regalloc(&n2, nr->type, N); - cgen(nr, &n2); + gmove(&tmp, &n2); gcmp(optoas(OCMP, nr->type), &n1, &n2); if(isfloat[nl->type->etype]) { @@ -1080,7 +1115,6 @@ bgen(Node *n, int true, Prog *to) } else { patch(gbranch(a, nr->type), to); } - regfree(&n1); regfree(&n2); break; diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c index 716ec5ed5..78f2f4aeb 100644 --- a/src/cmd/5g/cgen64.c +++ b/src/cmd/5g/cgen64.c @@ -233,8 +233,7 @@ cgen64(Node *n, Node *res) // shift is >= 1<<32 split64(r, &cl, &ch); gmove(&ch, &s); - p1 = gins(AMOVW, &s, &s); - p1->scond |= C_SBIT; + p1 = gins(ATST, &s, N); p6 = gbranch(ABNE, T); gmove(&cl, &s); splitclean(); @@ -242,8 +241,7 @@ cgen64(Node *n, Node *res) gmove(r, &s); p6 = P; } - p1 = gins(AMOVW, &s, &s); - p1->scond |= C_SBIT; + p1 = gins(ATST, &s, N); // shift == 0 p1 = gins(AMOVW, &bl, &al); @@ -390,8 +388,7 @@ olsh_break: // shift is >= 1<<32 split64(r, &cl, &ch); gmove(&ch, &s); - p1 = gins(AMOVW, &s, &s); - p1->scond |= C_SBIT; + p1 = gins(ATST, &s, N); p6 = gbranch(ABNE, T); gmove(&cl, &s); splitclean(); @@ -399,8 +396,7 @@ olsh_break: gmove(r, &s); p6 = P; } - p1 = gins(AMOVW, &s, &s); - p1->scond |= C_SBIT; + p1 = gins(ATST, &s, N); // shift == 0 p1 = gins(AMOVW, &bl, &al); diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c index 9c8760aea..0fece9a08 100644 --- a/src/cmd/5g/galign.c +++ b/src/cmd/5g/galign.c @@ -17,8 +17,6 @@ Typedef typedefs[] = "int", TINT, TINT32, "uint", TUINT, TUINT32, "uintptr", TUINTPTR, TUINT32, - "float", TFLOAT, TFLOAT32, - "complex", TCOMPLEX, TCOMPLEX64, 0 }; diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 42a89415d..182d7f147 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -172,7 +172,7 @@ ginscall(Node *f, int proc) p->to.reg = REGSP; p->to.offset = 8; - nodconst(&con, types[TINT32], argsize(f->type) + 4); + nodconst(&con, types[TINT32], argsize(f->type)); gins(AMOVW, &con, &r); p = gins(AMOVW, &r, N); p->to.type = D_OREG; @@ -595,8 +595,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res) } // test for shift being 0 - p1 = gins(AMOVW, &n1, &n1); - p1->scond |= C_SBIT; + p1 = gins(ATST, &n1, N); p3 = gbranch(ABEQ, T); // test and fix up large shifts diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h index 9a4e17571..7a0070fc9 100644 --- a/src/cmd/5g/opt.h +++ b/src/cmd/5g/opt.h @@ -128,7 +128,7 @@ Reg* rega(void); int rcmp(const void*, const void*); void regopt(Prog*); void addmove(Reg*, int, int, int); -Bits mkvar(Reg *r, Adr *a, int); +Bits mkvar(Reg *r, Adr *a); void prop(Reg*, Bits, Bits); void loopit(Reg*, int32); void synch(Reg*, Bits); diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c index 32333e8a9..f619a6206 100644 --- a/src/cmd/5g/peep.c +++ b/src/cmd/5g/peep.c @@ -89,11 +89,11 @@ loop1: /* * elide shift into D_SHIFT operand of subsequent instruction */ - if(shiftprop(r)) { - excise(r); - t++; - break; - } +// if(shiftprop(r)) { +// excise(r); +// t++; +// break; +// } break; case AMOVW: @@ -101,10 +101,10 @@ loop1: case AMOVD: if(!regtyp(&p->to)) break; - if(isdconst(&p->from)) { - constprop(&p->from, &p->to, r->s1); - break; - } +// if(isdconst(&p->from)) { +// constprop(&p->from, &p->to, r->s1); +// break; +// } if(!regtyp(&p->from)) break; if(p->from.type != p->to.type) @@ -166,87 +166,89 @@ loop1: excise(r1); } - for(r=firstr; r!=R; r=r->link) { - p = r->prog; - switch(p->as) { - case AMOVW: - case AMOVB: - case AMOVBU: - if(p->from.type == D_OREG && p->from.offset == 0) - xtramodes(r, &p->from); - else if(p->to.type == D_OREG && p->to.offset == 0) - xtramodes(r, &p->to); - else - continue; - break; - case ACMP: - /* - * elide CMP $0,x if calculation of x can set condition codes - */ - if(isdconst(&p->from) || p->from.offset != 0) - continue; - r2 = r->s1; - if(r2 == R) - continue; - t = r2->prog->as; - switch(t) { - default: - continue; - case ABEQ: - case ABNE: - case ABMI: - case ABPL: - break; - case ABGE: - t = ABPL; - break; - case ABLT: - t = ABMI; - break; - case ABHI: - t = ABNE; - break; - case ABLS: - t = ABEQ; - break; - } - r1 = r; - do - r1 = uniqp(r1); - while (r1 != R && r1->prog->as == ANOP); - if(r1 == R) - continue; - p1 = r1->prog; - if(p1->to.type != D_REG) - continue; - if(p1->to.reg != p->reg) - if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) - continue; - switch(p1->as) { - default: - continue; - case AMOVW: - if(p1->from.type != D_REG) - continue; - case AAND: - case AEOR: - case AORR: - case ABIC: - case AMVN: - case ASUB: - case ARSB: - case AADD: - case AADC: - case ASBC: - case ARSC: - break; - } - p1->scond |= C_SBIT; - r2->prog->as = t; - excise(r); - continue; - } - } +// for(r=firstr; r!=R; r=r->link) { +// p = r->prog; +// switch(p->as) { +// case AMOVW: +// case AMOVB: +// case AMOVBU: +// if(p->from.type == D_OREG && p->from.offset == 0) +// xtramodes(r, &p->from); +// else +// if(p->to.type == D_OREG && p->to.offset == 0) +// xtramodes(r, &p->to); +// else +// continue; +// break; +// case ACMP: +// /* +// * elide CMP $0,x if calculation of x can set condition codes +// */ +// if(isdconst(&p->from) || p->from.offset != 0) +// continue; +// r2 = r->s1; +// if(r2 == R) +// continue; +// t = r2->prog->as; +// switch(t) { +// default: +// continue; +// case ABEQ: +// case ABNE: +// case ABMI: +// case ABPL: +// break; +// case ABGE: +// t = ABPL; +// break; +// case ABLT: +// t = ABMI; +// break; +// case ABHI: +// t = ABNE; +// break; +// case ABLS: +// t = ABEQ; +// break; +// } +// r1 = r; +// do +// r1 = uniqp(r1); +// while (r1 != R && r1->prog->as == ANOP); +// if(r1 == R) +// continue; +// p1 = r1->prog; +// if(p1->to.type != D_REG) +// continue; +// if(p1->to.reg != p->reg) +// if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) +// continue; +// +// switch(p1->as) { +// default: +// continue; +// case AMOVW: +// if(p1->from.type != D_REG) +// continue; +// case AAND: +// case AEOR: +// case AORR: +// case ABIC: +// case AMVN: +// case ASUB: +// case ARSB: +// case AADD: +// case AADC: +// case ASBC: +// case ARSC: +// break; +// } +// p1->scond |= C_SBIT; +// r2->prog->as = t; +// excise(r); +// continue; +// } +// } predicate(); } @@ -331,10 +333,13 @@ subprop(Reg *r0) case ABL: return 0; - case ACMP: + case AMULLU: + case AMULA: + case ACMN: case AADD: case ASUB: + case ASBC: case ARSB: case ASLL: case ASRL: @@ -342,12 +347,14 @@ subprop(Reg *r0) case AORR: case AAND: case AEOR: + case AMVN: case AMUL: + case AMULU: case ADIV: case ADIVU: + case AMOD: + case AMODU: - case ACMPF: - case ACMPD: case AADDD: case AADDF: case ASUBD: @@ -622,8 +629,8 @@ shiftprop(Reg *r) case AADC: case AORR: case ASUB: - case ARSB: case ASBC: + case ARSB: case ARSC: if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { if(p1->from.type != D_REG) @@ -648,6 +655,7 @@ shiftprop(Reg *r) print("\t=>%P", p1); } case ABIC: + case ATST: case ACMP: case ACMN: if(p1->reg == n) @@ -922,8 +930,7 @@ copyu(Prog *p, Adr *v, Adr *s) switch(p->as) { default: - if(debug['P']) - print(" (?)"); + print("copyu: cant find %A\n", p->as); return 2; case AMOVM: @@ -983,7 +990,7 @@ copyu(Prog *p, Adr *v, Adr *s) return 2; } else { if(p->to.reg == v->reg) - return 2; + return 2; } } if(s != A) { @@ -1005,8 +1012,14 @@ copyu(Prog *p, Adr *v, Adr *s) return 1; return 0; + case AMULLU: /* read, read, write, write */ + case AMULA: + return 2; + case AADD: /* read, read, write */ + case AADC: case ASUB: + case ASBC: case ARSB: case ASLL: case ASRL: @@ -1014,9 +1027,13 @@ copyu(Prog *p, Adr *v, Adr *s) case AORR: case AAND: case AEOR: + case AMVN: case AMUL: + case AMULU: case ADIV: case ADIVU: + case AMOD: + case AMODU: case AADDF: case AADDD: case ASUBF: @@ -1028,6 +1045,7 @@ copyu(Prog *p, Adr *v, Adr *s) case ACMPF: case ACMPD: + case ATST: case ACMP: case ACMN: case ACASE: @@ -1138,9 +1156,13 @@ a2type(Prog *p) switch(p->as) { + case ATST: case ACMP: case ACMN: + case AMULLU: + case AMULA: + case AADD: case ASUB: case ARSB: @@ -1150,9 +1172,13 @@ a2type(Prog *p) case AORR: case AAND: case AEOR: + case AMVN: case AMUL: + case AMULU: case ADIV: case ADIVU: + case AMOD: + case AMODU: return D_REG; case ACMPF: @@ -1369,12 +1395,15 @@ int modifiescpsr(Prog *p) { switch(p->as) { - case ATST: + case AMULLU: + case AMULA: + case AMULU: + case ADIVU: + case ATEQ: case ACMN: + case ATST: case ACMP: - case AMULU: - case ADIVU: case AMUL: case ADIV: case AMOD: diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c index 5011e75cc..eaf02b237 100644 --- a/src/cmd/5g/reg.c +++ b/src/cmd/5g/reg.c @@ -83,7 +83,7 @@ setoutvar(void) n = nodarg(t, 1); a = zprog.from; naddr(n, &a, 0); - bit = mkvar(R, &a, 0); + bit = mkvar(R, &a); for(z=0; z<BITS; z++) ovar.b[z] |= bit.b[z]; t = structnext(&save); @@ -137,14 +137,13 @@ regopt(Prog *firstp) uint32 vreg; Bits bit; -return; // disabled for the moment if(first == 0) { fmtinstall('Q', Qconv); } first++; if(debug['K']) { - if(first != 20) + if(first != 13) return; // debug['R'] = 2; // debug['P'] = 2; @@ -166,7 +165,7 @@ return; // disabled for the moment firstr = R; lastr = R; nvar = 0; - regbits = 0; + regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); for(z=0; z<BITS; z++) { externs.b[z] = 0; params.b[z] = 0; @@ -221,14 +220,14 @@ return; // disabled for the moment /* * left side always read */ - bit = mkvar(r, &p->from, p->as==AMOVW); + bit = mkvar(r, &p->from); for(z=0; z<BITS; z++) r->use1.b[z] |= bit.b[z]; /* * right side depends on opcode */ - bit = mkvar(r, &p->to, 0); + bit = mkvar(r, &p->to); if(bany(&bit)) switch(p->as) { default: @@ -254,8 +253,7 @@ return; // disabled for the moment * funny */ case ABL: - for(z=0; z<BITS; z++) - addrs.b[z] |= bit.b[z]; + setaddrs(bit); break; } @@ -273,6 +271,18 @@ return; // disabled for the moment if(firstr == R) return; + for(i=0; i<nvar; i++) { + Var *v = var+i; + if(v->addr) { + bit = blsh(i); + for(z=0; z<BITS; z++) + addrs.b[z] |= bit.b[z]; + } + +// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n", +// i, v->addr, v->etype, v->width, v->sym, v->offset); + } + /* * pass 2 * turn branch references to pointers @@ -298,6 +308,7 @@ return; // disabled for the moment if(debug['R']) { p = firstr->prog; print("\n%L %D\n", p->lineno, &p->from); + print(" addr = %Q\n", addrs); } /* @@ -361,6 +372,7 @@ loop2: r->refahead.b[z] | r->calahead.b[z] | r->refbehind.b[z] | r->calbehind.b[z] | r->use1.b[z] | r->use2.b[z]; + bit.b[z] &= ~addrs.b[z]; } if(bany(&bit)) { @@ -486,18 +498,61 @@ brk: * last pass * eliminate nops * free aux structures + * adjust the stack pointer + * MOVW.W R1,-12(R13) <<- start + * MOVW R0,R1 + * MOVW R1,8(R13) + * MOVW $0,R1 + * MOVW R1,4(R13) + * BL ,runtime.newproc+0(SB) + * MOVW &ft+-32(SP),R7 <<- adjust + * MOVW &j+-40(SP),R6 <<- adjust + * MOVW autotmp_0003+-24(SP),R5 <<- adjust + * MOVW $12(R13),R13 <<- finish */ + vreg = 0; for(p = firstp; p != P; p = p->link) { while(p->link != P && p->link->as == ANOP) p->link = p->link->link; if(p->to.type == D_BRANCH) while(p->to.branch != P && p->to.branch->as == ANOP) p->to.branch = p->to.branch->link; + if(p->as == AMOVW && p->to.reg == 13) { + if(p->scond & C_WBIT) { + vreg = -p->to.offset; // in adjust region +// print("%P adjusting %d\n", p, vreg); + continue; + } + if(p->from.type == D_CONST && p->to.type == D_REG) { + if(p->from.offset != vreg) + print("in and out different\n"); +// print("%P finish %d\n", p, vreg); + vreg = 0; // done adjust region + continue; + } + +// print("%P %d %d from type\n", p, p->from.type, D_CONST); +// print("%P %d %d to type\n\n", p, p->to.type, D_REG); + } + + if(p->as == AMOVW && vreg != 0) { + if(p->from.sym != S) + if(p->from.name == D_AUTO || p->from.name == D_PARAM) { + p->from.offset += vreg; +// print("%P adjusting from %d %d\n", p, vreg, p->from.type); + } + if(p->to.sym != S) + if(p->to.name == D_AUTO || p->to.name == D_PARAM) { + p->to.offset += vreg; +// print("%P adjusting to %d %d\n", p, vreg, p->from.type); + } + } } if(r1 != R) { r1->link = freer; freer = firstr; } + } void @@ -557,24 +612,31 @@ addmove(Reg *r, int bn, int rn, int f) if(a->etype == TARRAY || a->sym == S) a->type = D_CONST; + if(v->addr) + fatal("addmove: shouldnt be doing this %A\n", a); + switch(v->etype) { default: print("What is this %E\n", v->etype); - case TINT32: - case TUINT32: - case TPTR32: - case TBOOL: - p1->as = AMOVW; - break; case TINT8: - case TUINT8: p1->as = AMOVB; break; + case TBOOL: + case TUINT8: + p1->as = AMOVBU; + break; case TINT16: - case TUINT16: p1->as = AMOVH; break; + case TUINT16: + p1->as = AMOVHU; + break; + case TINT32: + case TUINT32: + case TPTR32: + p1->as = AMOVW; + break; case TFLOAT32: p1->as = AMOVF; break; @@ -598,7 +660,7 @@ addmove(Reg *r, int bn, int rn, int f) a->type = D_FREG; a->reg = rn-NREG; } - if(v->etype == TUINT8) + if(v->etype == TUINT8 || v->etype == TBOOL) p1->as = AMOVBU; if(v->etype == TUINT16) p1->as = AMOVHU; @@ -622,7 +684,7 @@ overlap(int32 o1, int w1, int32 o2, int w2) } Bits -mkvar(Reg *r, Adr *a, int docon) +mkvar(Reg *r, Adr *a) { Var *v; int i, t, n, et, z, w, flag; @@ -634,29 +696,33 @@ mkvar(Reg *r, Adr *a, int docon) t = a->type; n = D_NONE; + flag = 0; +// if(a->pun) +// flag = 1; + switch(t) { default: print("type %d %d %D\n", t, a->name, a); goto none; - case D_CONST: - if(a->reg != NREG) - r->regu |= RtoB(a->reg); - // fallthrough - case D_NONE: case D_FCONST: case D_BRANCH: - goto none; + break; + + case D_CONST: + flag = 1; + goto onereg; case D_REGREG: if(a->offset != NREG) r->regu |= RtoB(a->offset); - // fallthrough + goto onereg; case D_REG: case D_SHIFT: case D_OREG: + onereg: if(a->reg != NREG) r->regu |= RtoB(a->reg); break; @@ -679,10 +745,6 @@ mkvar(Reg *r, Adr *a, int docon) break; } - flag = 0; -// if(a->pun) -// flag = 1; - s = a->sym; if(s == S) goto none; @@ -737,7 +799,6 @@ mkvar(Reg *r, Adr *a, int docon) if(debug['R']) print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a); -out: bit = blsh(i); if(n == D_EXTERN || n == D_STATIC) for(z=0; z<BITS; z++) @@ -746,22 +807,6 @@ out: for(z=0; z<BITS; z++) params.b[z] |= bit.b[z]; -// if(t == D_CONST) { -// if(s == S) { -// for(z=0; z<BITS; z++) -// consts.b[z] |= bit.b[z]; -// return bit; -// } -// if(et != TARRAY) -// for(z=0; z<BITS; z++) -// addrs.b[z] |= bit.b[z]; -// for(z=0; z<BITS; z++) -// params.b[z] |= bit.b[z]; -// return bit; -// } -// if(t != D_OREG) -// goto none; - return bit; none: @@ -1021,7 +1066,6 @@ allreg(uint32 b, Rgn *r) case TFLOAT32: case TFLOAT64: - case TFLOAT: i = BtoF(~b); if(i && r->cost >= 0) { r->regno = i+NREG; @@ -1195,6 +1239,7 @@ paint3(Reg *r, int bn, int32 rb, int rn) if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) addmove(r, bn, rn, 0); + for(;;) { r->act.b[z] |= bb; p = r->prog; @@ -1243,6 +1288,9 @@ void addreg(Adr *a, int rn) { + if(a->type == D_CONST) + fatal("addreg: cant do this %D %d\n", a, rn); + a->sym = 0; a->name = D_NONE; a->type = D_REG; diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile index 71798724b..c11ebe990 100644 --- a/src/cmd/5l/Makefile +++ b/src/cmd/5l/Makefile @@ -14,6 +14,7 @@ OFILES=\ enam.$O\ ldelf.$O\ ldmacho.$O\ + ldpe.$O\ lib.$O\ list.$O\ noop.$O\ diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 7ceea59b6..34565629f 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -448,7 +448,9 @@ asmb(void) sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC; sh->addralign = 1; - elfinterp(sh, startva, linuxdynld); + if(interpreter == nil) + interpreter = linuxdynld; + elfinterp(sh, startva, interpreter); ph = newElfPhdr(); ph->type = PT_INTERP; @@ -793,7 +795,8 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na rt = 0; if(p->as == AMOVW || p->as == AMVN) r = 0; - else if(r == NREG) + else + if(r == NREG) r = rt; o1 |= rf | (r<<16) | (rt<<12); break; @@ -1558,6 +1561,10 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na o1 |= (p->from.reg<<16); o1 |= (p->to.reg<<12); break; + case 90: /* tst reg */ + o1 = oprrr(ACMP+AEND, p->scond); + o1 |= p->from.reg<<16; + break; } out[0] = o1; @@ -1709,6 +1716,8 @@ oprrr(int a, int sc) return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); case AMOVFW+AEND: // copy FtoW return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); + case ACMP+AEND: // cmp imm + return o | (0x3<<24) | (0x5<<20); } diag("bad rrr %d", a); prasm(curp); diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go index 6f7408116..d266b9233 100644 --- a/src/cmd/5l/doc.go +++ b/src/cmd/5l/doc.go @@ -20,6 +20,11 @@ Original options are listed in the link above. Options new in this version: +-F + Force use of software floating point. + Also implied by setting GOARM=5 in the environment. +-I interpreter + Set the ELF dynamic linker to use. -L dir1 -L dir2 Search for libraries (package files) in dir1, dir2, etc. The default is the single location $GOROOT/pkg/$GOOS_arm. diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 4e7ccea88..c31028416 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -276,7 +276,6 @@ enum STRINGSZ = 200, NHASH = 10007, - NHUNK = 100000, MINSIZ = 64, NENT = 100, MAXIO = 8192, @@ -333,6 +332,7 @@ EXTERN Oprang thumboprange[ALAST]; EXTERN char* outfile; EXTERN int32 pc; EXTERN uchar repop[ALAST]; +EXTERN char* interpreter; EXTERN char* rpath; EXTERN uint32 stroffset; EXTERN int32 symsize; diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 5def0d3f1..a9439c27a 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -330,23 +330,23 @@ noops(void) p->from.reg = 1; p->reg = 2; } - + // MOVW.LO $autosize, R1 p = appendp(p); p->as = AMOVW; p->scond = C_SCOND_LO; p->from.type = D_CONST; - p->from.offset = 0; + /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ + p->from.offset = autosize+160; p->to.type = D_REG; p->to.reg = 1; - // MOVW.LO $args +4, R2 - // also need to store the extra 4 bytes. + // MOVW.LO $args, R2 p = appendp(p); p->as = AMOVW; p->scond = C_SCOND_LO; p->from.type = D_CONST; - p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4; + p->from.offset = (cursym->text->to.offset2 + 3) & ~3; p->to.type = D_REG; p->to.reg = 2; @@ -391,12 +391,12 @@ noops(void) p->to.type = D_REG; p->to.reg = 1; - // MOVW $args +4, R2 + // MOVW $args, R2 // also need to store the extra 4 bytes. p = appendp(p); p->as = AMOVW; p->from.type = D_CONST; - p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4; + p->from.offset = (cursym->text->to.offset2 + 3) & ~3; p->to.type = D_REG; p->to.reg = 2; diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index cb9ad9805..5b778d777 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -61,7 +61,7 @@ linkername[] = void usage(void) { - fprint(2, "usage: 5l [-E entry] [-H head] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n"); + fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n"); errorexit(); } @@ -69,6 +69,7 @@ void main(int argc, char *argv[]) { int c, i; + char *p; Binit(&bso, 1, OWRITE); cout = -1; @@ -80,6 +81,10 @@ main(int argc, char *argv[]) INITDAT = -1; INITRND = -1; INITENTRY = 0; + + p = getenv("GOARM"); + if(p != nil && strcmp(p, "5") == 0) + debug['F'] = 1; ARGBEGIN { default: @@ -95,6 +100,9 @@ main(int argc, char *argv[]) case 'E': INITENTRY = EARGF(usage()); break; + case 'I': + interpreter = EARGF(usage()); + break; case 'L': Lflag(EARGF(usage())); break; diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c index 96b216837..9ad0193ac 100644 --- a/src/cmd/5l/optab.c +++ b/src/cmd/5l/optab.c @@ -64,7 +64,7 @@ Optab optab[] = { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, { ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 }, { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, - { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, + { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, @@ -251,5 +251,7 @@ Optab optab[] = { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, + { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, + { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, }; diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c index be0f5e8b3..220140f43 100644 --- a/src/cmd/5l/span.c +++ b/src/cmd/5l/span.c @@ -962,7 +962,6 @@ buildop(void) oprange[ABIC] = oprange[r]; break; case ACMP: - oprange[ATST] = oprange[r]; oprange[ATEQ] = oprange[r]; oprange[ACMN] = oprange[r]; break; @@ -1055,6 +1054,7 @@ buildop(void) case ALDREX: case ASTREX: + case ATST: break; } } diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h index 9030081ca..2d4272646 100644 --- a/src/cmd/6a/a.h +++ b/src/cmd/6a/a.h @@ -57,7 +57,6 @@ typedef struct Gen2 Gen2; #define NSYMB 500 #define BUFSIZ 8192 #define HISTSZ 20 -#define NHUNK 10000 #define EOF (-1) #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index d4d22fd61..47f3374f5 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -431,9 +431,6 @@ agen(Node *n, Node *res) if(n == N || n->type == T) return; - if(!isptr[res->type->etype] && res->type->etype != TUINTPTR) - fatal("agen: not tptr: %T", res->type); - while(n->op == OCONVNOP) n = n->left; diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c index bdfc9947e..97bfb58e8 100644 --- a/src/cmd/6g/galign.c +++ b/src/cmd/6g/galign.c @@ -17,8 +17,6 @@ Typedef typedefs[] = "int", TINT, TINT32, "uint", TUINT, TUINT32, "uintptr", TUINTPTR, TUINT64, - "float", TFLOAT, TFLOAT32, - "complex", TCOMPLEX, TCOMPLEX64, 0 }; diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index ebb61ea94..c3dac1fdc 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -246,7 +246,7 @@ anyregalloc(void) { int i, j; - for(i=D_AL; i<=D_DI; i++) { + for(i=D_AX; i<=D_R15; i++) { if(reg[i] == 0) goto ok; for(j=0; j<nelem(resvd); j++) diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c index 464627066..1e1d64c59 100644 --- a/src/cmd/6g/reg.c +++ b/src/cmd/6g/reg.c @@ -748,7 +748,6 @@ addmove(Reg *r, int bn, int rn, int f) case TPTR64: p1->as = AMOVQ; break; - case TFLOAT: case TFLOAT32: p1->as = AMOVSS; break; @@ -1180,7 +1179,6 @@ allreg(uint32 b, Rgn *r) case TFLOAT32: case TFLOAT64: - case TFLOAT: i = BtoF(~b); if(i && r->cost > 0) { r->regno = i; diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile index fba1b42ae..abe204d4f 100644 --- a/src/cmd/6l/Makefile +++ b/src/cmd/6l/Makefile @@ -16,12 +16,14 @@ OFILES=\ go.$O\ ldelf.$O\ ldmacho.$O\ + ldpe.$O\ lib.$O\ list.$O\ macho.$O\ obj.$O\ optab.$O\ pass.$O\ + pe.$O\ prof.$O\ span.$O\ symtab.$O\ @@ -33,6 +35,7 @@ HFILES=\ ../ld/elf.h\ ../ld/macho.h\ ../ld/dwarf.h\ + ../ld/pe.h\ include ../../Make.ccmd diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 9726d227c..d6ffa4ff9 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -35,6 +35,7 @@ #include "../ld/elf.h" #include "../ld/dwarf.h" #include "../ld/macho.h" +#include "../ld/pe.h" #define Dbufslop 100 @@ -205,15 +206,16 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_X86_64_GOTPCREL: if(targ->dynimpname == nil || targ->dynexport) { // have symbol - // turn MOVQ of GOT entry into LEAQ of symbol itself - if(r->off < 2 || s->p[r->off-2] != 0x8b) { - diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name); + if(r->off >= 2 && s->p[r->off-2] == 0x8b) { + // turn MOVQ of GOT entry into LEAQ of symbol itself + s->p[r->off-2] = 0x8d; + r->type = D_PCREL; + r->add += 4; return; } - s->p[r->off-2] = 0x8d; - r->type = D_PCREL; - r->add += 4; - return; + // fall back to using GOT and hope for the best (CMOV*) + // TODO: just needs relocation, no need to put in .dynsym + targ->dynimpname = targ->name; } addgotsym(targ); r->type = D_PCREL; @@ -782,6 +784,8 @@ asmb(void) if(!debug['d']) elftextsh += 10; break; + case 10: + break; } symsize = 0; @@ -807,6 +811,10 @@ asmb(void) symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen; symo = rnd(symo, INITRND); break; + case 10: + symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen; + symo = rnd(symo, PEFILEALIGN); + break; } /* * the symbol information is stored as @@ -829,7 +837,7 @@ asmb(void) lputl(symsize); lputl(lcsize); cflush(); - if(!debug['s']) { + if(HEADTYPE != 10 && !debug['s']) { elfsymo = symo+8+symsize+lcsize; seek(cout, elfsymo, 0); asmelfsym64(); @@ -907,14 +915,17 @@ asmb(void) sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC; sh->addralign = 1; - switch(HEADTYPE) { - case 7: - elfinterp(sh, startva, linuxdynld); - break; - case 9: - elfinterp(sh, startva, freebsddynld); - break; + if(interpreter == nil) { + switch(HEADTYPE) { + case 7: + interpreter = linuxdynld; + break; + case 9: + interpreter = freebsddynld; + break; + } } + elfinterp(sh, startva, interpreter); ph = newElfPhdr(); ph->type = PT_INTERP; @@ -1090,6 +1101,9 @@ asmb(void) if(a+elfwriteinterp() > ELFRESERVE) diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); break; + case 10: + asmbpe(); + break; } cflush(); } @@ -1143,6 +1157,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) case SDATA: case SELFDATA: case SMACHOGOT: + case SWINDOWS: if(!s->reachable) continue; put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go index 501317f36..97fa2cc5a 100644 --- a/src/cmd/6l/doc.go +++ b/src/cmd/6l/doc.go @@ -32,6 +32,8 @@ Options new in this version: Write Apple Mach-O binaries (default when $GOOS is darwin) -H7 Write Linux ELF binaries (default when $GOOS is linux) +-I interpreter + Set the ELF dynamic linker to use. -L dir1 -L dir2 Search for libraries (package files) in dir1, dir2, etc. The default is the single location $GOROOT/pkg/$GOOS_amd64. diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 1c52ea89d..7f22493e0 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -183,6 +183,7 @@ enum SRODATA, SDATA, SMACHOGOT, + SWINDOWS, SBSS, SXREF, @@ -196,7 +197,6 @@ enum SSUB = 1<<8, NHASH = 10007, - NHUNK = 100000, MINSIZ = 8, STRINGSZ = 200, MINLC = 1, @@ -352,6 +352,7 @@ EXTERN int nerrors; EXTERN char* noname; EXTERN char* outfile; EXTERN vlong pc; +EXTERN char* interpreter; EXTERN char* rpath; EXTERN int32 spsize; EXTERN Sym* symlist; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 96d78c3b9..f9e257842 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -36,6 +36,7 @@ #include "../ld/elf.h" #include "../ld/macho.h" #include "../ld/dwarf.h" +#include "../ld/pe.h" #include <ar.h> char *noname = "<none>"; @@ -57,7 +58,7 @@ char* paramspace = "FP"; void usage(void) { - fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n"); + fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n"); exits("usage"); } @@ -95,6 +96,9 @@ main(int argc, char *argv[]) case 'H': HEADTYPE = atolwhex(EARGF(usage())); break; + case 'I': + interpreter = EARGF(usage()); + break; case 'L': Lflag(EARGF(usage())); break; @@ -133,6 +137,9 @@ main(int argc, char *argv[]) if(strcmp(goos, "freebsd") == 0) HEADTYPE = 9; else + if(strcmp(goos, "windows") == 0) + HEADTYPE = 10; + else print("goos is not known: %s\n", goos); } @@ -200,6 +207,16 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; + case 10: /* PE executable */ + peinit(); + HEADR = PEFILEHEADR; + if(INITTEXT == -1) + INITTEXT = PEBASE+PESECTHEADR; + if(INITDAT == -1) + INITDAT = 0; + if(INITRND == -1) + INITRND = PESECTALIGN; + break; } if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%llux is ignored because of -R0x%ux\n", @@ -245,6 +262,8 @@ main(int argc, char *argv[]) else doprof2(); span(); + if(HEADTYPE == 10) + dope(); addexport(); textaddress(); pclntab(); diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index 5c4ed00a6..5eb221a35 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -277,6 +277,29 @@ patch(void) vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { + if(HEADTYPE == 10) { + // Windows + // Convert + // op n(GS), reg + // to + // MOVL 0x58(GS), reg + // op n(reg), reg + // The purpose of this patch is to fix some accesses + // to extern register variables (TLS) on Windows, as + // a different method is used to access them. + if(p->from.type == D_INDIR+D_GS + && p->to.type >= D_AX && p->to.type <= D_DI + && p->from.offset != 0x58) { + q = appendp(p); + q->from = p->from; + q->from.type = D_INDIR + p->to.type; + q->to = p->to; + q->as = p->as; + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + } + } if(HEADTYPE == 7 || HEADTYPE == 9) { // ELF uses FS instead of GS. if(p->from.type == D_INDIR+D_GS) @@ -411,6 +434,21 @@ dostkoff(void) p->from.type = D_INDIR+D_GS; p->from.offset = tlsoffset+0; p->to.type = D_CX; + if(HEADTYPE == 10) { // Windows + // movq %gs:0x58, %rcx + // movq (%rcx), %rcx + p->as = AMOVQ; + p->from.type = D_INDIR+D_GS; + p->from.offset = 0x58; + p->to.type = D_CX; + + + p = appendp(p); + p->as = AMOVQ; + p->from.type = D_INDIR+D_CX; + p->from.offset = 0; + p->to.type = D_CX; + } if(debug['K']) { // 6l -K means check not only for stack diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h index fe6b17280..3cb30f4c2 100644 --- a/src/cmd/8a/a.h +++ b/src/cmd/8a/a.h @@ -57,7 +57,6 @@ typedef struct Gen2 Gen2; #define NSYMB 500 #define BUFSIZ 8192 #define HISTSZ 20 -#define NHUNK 10000 #define EOF (-1) #define IGN (-2) #define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c index 875d434fa..9c326e8ef 100644 --- a/src/cmd/8g/cgen.c +++ b/src/cmd/8g/cgen.c @@ -174,7 +174,7 @@ cgen(Node *n, Node *res) case OREAL: case OIMAG: - case OCMPLX: + case OCOMPLEX: fatal("unexpected complex"); return; diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c index 1c14dfe47..48edfdf3c 100644 --- a/src/cmd/8g/galign.c +++ b/src/cmd/8g/galign.c @@ -17,8 +17,6 @@ Typedef typedefs[] = "int", TINT, TINT32, "uint", TUINT, TUINT32, "uintptr", TUINTPTR, TUINT32, - "float", TFLOAT, TFLOAT32, - "complex", TCOMPLEX, TCOMPLEX64, 0 }; diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c index e1dacf55a..1465d372c 100644 --- a/src/cmd/8g/reg.c +++ b/src/cmd/8g/reg.c @@ -1095,7 +1095,6 @@ allreg(uint32 b, Rgn *r) case TFLOAT32: case TFLOAT64: - case TFLOAT: break; } return 0; diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile index 84976ba18..a85e3ffa7 100644 --- a/src/cmd/8l/Makefile +++ b/src/cmd/8l/Makefile @@ -16,6 +16,7 @@ OFILES=\ go.$O\ ldelf.$O\ ldmacho.$O\ + ldpe.$O\ lib.$O\ list.$O\ macho.$O\ diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index cdb5a33e6..6e83d8dea 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -520,7 +520,7 @@ adddynsym(Sym *s) adduint8(d, 0); // section adduint16(d, 0); // desc adduint32(d, 0); // value - } else { + } else if(HEADTYPE != 10) { diag("adddynsym: unsupported binary format"); } } @@ -540,7 +540,7 @@ adddynlib(char *lib) elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else if(HEADTYPE == 6) { // Mach-O machoadddynlib(lib); - } else { + } else if(HEADTYPE != 10) { diag("adddynlib: unsupported binary format"); } } @@ -936,14 +936,17 @@ asmb(void) sh->type = SHT_PROGBITS; sh->flags = SHF_ALLOC; sh->addralign = 1; - switch(HEADTYPE) { - case 7: - elfinterp(sh, startva, linuxdynld); - break; - case 9: - elfinterp(sh, startva, freebsddynld); - break; + if(interpreter == nil) { + switch(HEADTYPE) { + case 7: + interpreter = linuxdynld; + break; + case 9: + interpreter = freebsddynld; + break; + } } + elfinterp(sh, startva, interpreter); ph = newElfPhdr(); ph->type = PT_INTERP; diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go index 0bf6f151f..ef5ebc31d 100644 --- a/src/cmd/8l/doc.go +++ b/src/cmd/8l/doc.go @@ -29,6 +29,8 @@ Options new in this version: Write Apple Mach-O binaries (default when $GOOS is darwin) -H7 Write Linux ELF binaries (default when $GOOS is linux) +-I interpreter + Set the ELF dynamic linker to use. -L dir1 -L dir2 Search for libraries (package files) in dir1, dir2, etc. The default is the single location $GOROOT/pkg/$GOOS_386. diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index daede8879..e0746fc75 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -190,7 +190,6 @@ enum SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */ NHASH = 10007, - NHUNK = 100000, MINSIZ = 4, STRINGSZ = 200, MINLC = 1, @@ -316,6 +315,7 @@ EXTERN int maxop; EXTERN int nerrors; EXTERN char* noname; EXTERN int32 pc; +EXTERN char* interpreter; EXTERN char* rpath; EXTERN int32 spsize; EXTERN Sym* symlist; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 18b2112fe..fefb6d8b0 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -64,7 +64,7 @@ char *thestring = "386"; void usage(void) { - fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n"); + fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n"); exits("usage"); } @@ -102,6 +102,9 @@ main(int argc, char *argv[]) case 'H': HEADTYPE = atolwhex(EARGF(usage())); break; + case 'I': + interpreter = EARGF(usage()); + break; case 'L': Lflag(EARGF(usage())); break; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index 6e387b0b5..878a73dac 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -38,8 +38,15 @@ static void xfol(Prog*, Prog**); // see ../../pkg/runtime/proc.c:/StackGuard enum { +#ifdef __WINDOWS__ + // use larger stacks to compensate for larger stack guard, + // needed for exception handling. + StackSmall = 256, + StackBig = 8192, +#else StackSmall = 128, StackBig = 4096, +#endif }; Prog* @@ -510,7 +517,7 @@ dostkoff(void) p->to.type = D_DX; /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ p->from.type = D_CONST; - if(autoffset+160 > 4096) + if(autoffset+160+cursym->text->to.offset2 > 4096) p->from.offset = (autoffset+160) & ~7LL; p = appendp(p); // save arg size in AX diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile index 71f23383d..8327d9516 100644 --- a/src/cmd/cc/Makefile +++ b/src/cmd/cc/Makefile @@ -20,7 +20,7 @@ OFILES=\ mac.$O\ dcl.$O\ acid.$O\ - pickle.$O\ + godefs.$O\ bits.$O\ com.$O\ scon.$O\ diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index 3649bf5f6..8e8f6af44 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -59,7 +59,6 @@ typedef struct Bits Bits; typedef struct Dynimp Dynimp; typedef struct Dynexp Dynexp; -#define NHUNK 50000L #define BUFSIZ 8192 #define NSYMB 500 #define NHASH 1024 @@ -745,9 +744,11 @@ void acidtype(Type*); void acidvar(Sym*); /* - * pickle.c + * godefs.c */ -void pickletype(Type*); +int Uconv(Fmt*); +void godeftype(Type*); +void godefvar(Sym*); /* * bits.c diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c index f629925d1..d7604b649 100644 --- a/src/cmd/cc/dcl.c +++ b/src/cmd/cc/dcl.c @@ -130,6 +130,7 @@ loop: if(debug['d']) dbgdecl(s); acidvar(s); + godefvar(s); s->varlineno = lineno; break; } @@ -587,7 +588,7 @@ sualign(Type *t) t->width = w; t->align = maxal; acidtype(t); - pickletype(t); + godeftype(t); return; case TUNION: @@ -610,7 +611,7 @@ sualign(Type *t) t->width = w; t->align = maxal; acidtype(t); - pickletype(t); + godeftype(t); return; default: @@ -1538,6 +1539,7 @@ doenum(Sym *s, Node *n) if(debug['d']) dbgdecl(s); acidvar(s); + godefvar(s); } void diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c index 6eb5fb409..d78a72a2b 100644 --- a/src/cmd/cc/dpchk.c +++ b/src/cmd/cc/dpchk.c @@ -399,6 +399,7 @@ dpcheck(Node *n) return; i = l->param; + a = nil; b = n->right; a = Z; while(i > 0) { diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c new file mode 100644 index 000000000..9503cb2f2 --- /dev/null +++ b/src/cmd/cc/godefs.c @@ -0,0 +1,387 @@ +// cmd/cc/godefs.cc +// +// derived from pickle.cc which itself was derived from acid.cc. +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009-2011 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "cc.h" + +static int upper; + +static char *kwd[] = +{ + "_bool", + "_break", + "_byte", + "_case", + "_chan", + "_complex128", + "_complex64", + "_const", + "_continue", + "_default", + "_defer", + "_else", + "_fallthrough", + "_false", + "_float32", + "_float64", + "_for", + "_func", + "_go", + "_goto", + "_if", + "_import", + "_int", + "_int16", + "_int32", + "_int64", + "_int8", + "_interface", + "_intptr", + "_map", + "_package", + "_panic", + "_range", + "_return", + "_select", + "_string", + "_struct", + "_switch", + "_true", + "_type", + "_uint", + "_uint16", + "_uint32", + "_uint64", + "_uint8", + "_uintptr", + "_var", +}; + +static char* +pmap(char *s) +{ + int i, bot, top, mid; + + bot = -1; + top = nelem(kwd); + while(top - bot > 1){ + mid = (bot + top) / 2; + i = strcmp(kwd[mid]+1, s); + if(i == 0) + return kwd[mid]; + if(i < 0) + bot = mid; + else + top = mid; + } + + return s; +} + + +int +Uconv(Fmt *fp) +{ + char str[STRINGSZ+1]; + char *s, *n; + int i; + + str[0] = 0; + s = va_arg(fp->args, char*); + + // strip package name + n = strrchr(s, '.'); + if(n != nil) + s = n + 1; + + if(s && *s) { + if(upper) + str[0] = toupper(*s); + else + str[0] = tolower(*s); + for(i = 1; i < STRINGSZ && s[i] != 0; i++) + str[i] = tolower(s[i]); + str[i] = 0; + } + + return fmtstrcpy(fp, pmap(str)); +} + + +static Sym* +findsue(Type *t) +{ + int h; + Sym *s; + + if(t != T) + for(h=0; h<nelem(hash); h++) + for(s = hash[h]; s != S; s = s->link) + if(s->suetag && s->suetag->link == t) + return s; + return 0; +} + +static void +printtypename(Type *t) +{ + Sym *s; + Type *t1; + int w; + char *n; + + for( ; t != nil; t = t->link) { + switch(t->etype) { + case TIND: + // Special handling of *void. + if(t->link != nil && t->link->etype==TVOID) { + Bprint(&outbuf, "unsafe.Pointer"); + return; + } + // *func == func + if(t->link != nil && t->link->etype==TFUNC) + continue; + Bprint(&outbuf, "*"); + continue; + case TARRAY: + w = t->width; + if(t->link && t->link->width) + w /= t->link->width; + Bprint(&outbuf, "[%d]", w); + continue; + } + break; + } + + if(t == nil) { + Bprint(&outbuf, "bad // should not happen"); + return; + } + + switch(t->etype) { + case TINT: + Bprint(&outbuf, "int"); + break; + case TUINT: + Bprint(&outbuf, "uint"); + break; + case TCHAR: + Bprint(&outbuf, "int8"); + break; + case TUCHAR: + Bprint(&outbuf, "uint8"); + break; + case TSHORT: + Bprint(&outbuf, "int16"); + break; + case TUSHORT: + Bprint(&outbuf, "uint16"); + break; + case TLONG: + Bprint(&outbuf, "int32"); + break; + case TULONG: + Bprint(&outbuf, "uint32"); + break; + case TVLONG: + Bprint(&outbuf, "int64"); + break; + case TUVLONG: + Bprint(&outbuf, "uint64"); + break; + case TFLOAT: + Bprint(&outbuf, "float32"); + break; + case TDOUBLE: + Bprint(&outbuf, "float64"); + break; + case TUNION: + case TSTRUCT: + s = findsue(t->link); + n = "bad"; + if(s != S) + n = s->name; + else if(t->tag) + n = t->tag->name; + if(strcmp(n, "String") == 0){ + Bprint(&outbuf, "string"); + } else if(strcmp(n, "Slice") == 0){ + Bprint(&outbuf, "[]byte"); + } else + Bprint(&outbuf, "%U", n); + break; + case TFUNC: + Bprint(&outbuf, "func(", t); + for(t1 = t->down; t1 != T; t1 = t1->down) { + if(t1->etype == TVOID) + break; + if(t1 != t->down) + Bprint(&outbuf, ", "); + printtypename(t1); + } + Bprint(&outbuf, ")"); + if(t->link && t->link->etype != TVOID) { + Bprint(&outbuf, " "); + printtypename(t->link); + } + break; + case TDOT: + Bprint(&outbuf, "...interface{}"); + break; + default: + Bprint(&outbuf, " weird<%T>", t); + } +} + +static int +dontrun(void) +{ + Io *i; + int n; + + if(!debug['q'] && !debug['Q']) + return 1; + if(debug['q'] + debug['Q'] > 1) { + n = 0; + for(i=iostack; i; i=i->link) + n++; + if(n > 1) + return 1; + } + + upper = debug['Q']; + return 0; +} + +void +godeftype(Type *t) +{ + Sym *s; + Type *l; + int gotone; + + if(dontrun()) + return; + + switch(t->etype) { + case TUNION: + case TSTRUCT: + s = findsue(t->link); + if(s == S) { + Bprint(&outbuf, "/* can't find %T */\n\n", t); + return; + } + + gotone = 0; // for unions, take first member of size equal to union + Bprint(&outbuf, "type %U struct {\n", s->name); + for(l = t->link; l != T; l = l->down) { + Bprint(&outbuf, "\t"); + if(t->etype == TUNION) { + if(!gotone && l->width == t->width) + gotone = 1; + else + Bprint(&outbuf, "// (union)\t"); + } + if(l->sym != nil) // not anonymous field + Bprint(&outbuf, "%U\t", l->sym->name); + printtypename(l); + Bprint(&outbuf, "\n"); + } + Bprint(&outbuf, "}\n\n"); + break; + + default: + Bprint(&outbuf, "/* %T */\n\n", t); + break; + } +} + +void +godefvar(Sym *s) +{ + Type *t, *t1; + char n; + + if(dontrun()) + return; + + t = s->type; + if(t == nil) + return; + + switch(t->etype) { + case TENUM: + if(!typefd[t->etype]) + Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst); + else + Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst); + break; + + case TFUNC: + Bprint(&outbuf, "func %U(", s->name); + n = 'a'; + for(t1 = t->down; t1 != T; t1 = t1->down) { + if(t1->etype == TVOID) + break; + if(t1 != t->down) + Bprint(&outbuf, ", "); + Bprint(&outbuf, "%c ", n++); + printtypename(t1); + } + Bprint(&outbuf, ")"); + if(t->link && t->link->etype != TVOID) { + Bprint(&outbuf, " "); + printtypename(t->link); + } + Bprint(&outbuf, "\n"); + break; + + default: + switch(s->class) { + case CTYPEDEF: + if(!typesu[t->etype]) { + Bprint(&outbuf, "// type %U\t", s->name); + printtypename(t); + Bprint(&outbuf, "\n"); + } + break; + case CSTATIC: + case CEXTERN: + case CGLOBL: + if(strchr(s->name, '$') != nil) // TODO(lvd) + break; + Bprint(&outbuf, "var %U\t", s->name); + printtypename(t); + Bprint(&outbuf, "\n"); + break; + } + break; + } +} diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c index 3b413c246..dba8ff634 100644 --- a/src/cmd/cc/lex.c +++ b/src/cmd/cc/lex.c @@ -59,15 +59,20 @@ pathchar(void) * -d print declarations * -D name define * -F format specification check + * -G print pgen stuff + * -g print cgen trees * -i print initialization * -I path include * -l generate little-endian code * -L print every NAME symbol * -M constant multiplication * -m print add/sub/mul trees - * -n print acid to file (%.c=%.acid) (with -a or -aa) + * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa) * -o file output file * -p use standard cpp ANSI preprocessor (not on windows) + * -p something with peepholes + * -q print equivalent Go code for variables and types (lower-case identifiers) + * -Q print equivalent Go code for variables and types (upper-case identifiers) * -r print registerization * -s print structure offsets (with -a or -aa) * -S print assembly @@ -121,7 +126,7 @@ main(int argc, char *argv[]) p = ARGF(); if(p) { if(ndef%8 == 0) - defs = allocn(defs, ndef*sizeof(char *), + defs = allocn(defs, ndef*sizeof(char *), 8*sizeof(char *)); defs[ndef++] = p; dodefine(p); @@ -147,7 +152,7 @@ main(int argc, char *argv[]) * if we're writing acid to standard output, don't compile * concurrently, to avoid interleaving output. */ - if(((!debug['a'] && !debug['Z']) || debug['n']) && + if(((!debug['a'] && !debug['q'] && !debug['Q']) || debug['n']) && (p = getenv("NPROC")) != nil) nproc = atol(p); /* */ c = 0; @@ -220,8 +225,8 @@ compile(char *file, char **defs, int ndef) p = utfrune(outfile, 0); if(debug['a'] && debug['n']) strcat(p, ".acid"); - else if(debug['Z'] && debug['n']) - strcat(p, "_pickle.c"); + else if((debug['q'] || debug['Q']) && debug['n']) + strcat(p, ".go"); else { p[0] = '.'; p[1] = thechar; @@ -246,7 +251,7 @@ compile(char *file, char **defs, int ndef) * if we're writing acid to standard output, don't keep scratching * outbuf. */ - if((debug['a'] || debug['Z']) && !debug['n']) { + if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) { if (first) { outfile = 0; Binit(&outbuf, dup(1, -1), OWRITE); @@ -325,7 +330,7 @@ compile(char *file, char **defs, int ndef) newfile(file, -1); } yyparse(); - if(!debug['a'] && !debug['Z']) + if(!debug['a'] && !debug['q'] && !debug['Q']) gclean(); return nerrors; } @@ -1309,6 +1314,7 @@ cinit(void) fmtinstall('L', Lconv); fmtinstall('Q', Qconv); fmtinstall('|', VBconv); + fmtinstall('U', Uconv); } int @@ -1554,7 +1560,7 @@ setinclude(char *p) return; if(ninclude%8 == 0) - include = allocn(include, ninclude*sizeof(char *), + include = allocn(include, ninclude*sizeof(char *), 8*sizeof(char *)); include[ninclude++] = p; } @@ -1595,7 +1601,7 @@ ensuresymb(int32 n) if(symb == nil) { symb = alloc(NSYMB+1); nsymb = NSYMB; - } + } if(n > nsymb) { symb = allocn(symb, nsymb, n+1-nsymb); diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody index 0bccc1733..24f9bdc85 100644 --- a/src/cmd/cc/lexbody +++ b/src/cmd/cc/lexbody @@ -88,47 +88,32 @@ pragincomplete(void) ; } -void -gethunk(void) -{ - hunk = malloc(NHUNK); - memset(hunk, 0, NHUNK); - nhunk = NHUNK; -} - void* alloc(int32 n) { void *p; - while((uintptr)hunk & MAXALIGN) { - hunk++; - nhunk--; + p = malloc(n); + if(p == nil) { + print("alloc out of mem\n"); + exit(1); } - while(nhunk < n) - gethunk(); - p = hunk; - nhunk -= n; - hunk += n; + memset(p, 0, n); return p; } void* -allocn(void *p, int32 on, int32 n) +allocn(void *p, int32 n, int32 d) { - void *q; - - q = (uchar*)p + on; - if(q != hunk || nhunk < n) { - while(nhunk < on+n) - gethunk(); - memmove(hunk, p, on); - p = hunk; - hunk += on; - nhunk -= on; + if(p == nil) + return alloc(n+d); + p = realloc(p, n+d); + if(p == nil) { + print("allocn out of mem\n"); + exit(1); } - hunk += n; - nhunk -= n; + if(d > 0) + memset((char*)p+n, 0, d); return p; } diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index a9d7f1ef4..5d17cafc9 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -586,8 +586,7 @@ bcomplex(Node *n, Node *c) *b->right = *nodconst(0); b->right->type = n->type; b->type = types[TLONG]; - cgen(b, Z); - return 0; + n = b; } bool64(n); boolgen(n, 1, Z); diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c deleted file mode 100644 index 82cf5eb05..000000000 --- a/src/cmd/cc/pickle.c +++ /dev/null @@ -1,298 +0,0 @@ -// Inferno utils/cc/pickle.c -// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "cc.h" - -static char *kwd[] = -{ - "$adt", "$aggr", "$append", "$complex", "$defn", - "$delete", "$do", "$else", "$eval", "$head", "$if", - "$local", "$loop", "$return", "$tail", "$then", - "$union", "$whatis", "$while", -}; -static char picklestr[] = "\tbp = pickle(bp, ep, un, "; - -static char* -pmap(char *s) -{ - int i, bot, top, new; - - bot = 0; - top = bot + nelem(kwd) - 1; - while(bot <= top){ - new = bot + (top - bot)/2; - i = strcmp(kwd[new]+1, s); - if(i == 0) - return kwd[new]; - - if(i < 0) - bot = new + 1; - else - top = new - 1; - } - return s; -} - -Sym* -picklesue(Type *t) -{ - int h; - Sym *s; - - if(t != T) - for(h=0; h<nelem(hash); h++) - for(s = hash[h]; s != S; s = s->link) - if(s->suetag && s->suetag->link == t) - return s; - return 0; -} - -Sym* -picklefun(Type *t) -{ - int h; - Sym *s; - - for(h=0; h<nelem(hash); h++) - for(s = hash[h]; s != S; s = s->link) - if(s->type == t) - return s; - return 0; -} - -char picklechar[NTYPE]; -Init picklecinit[] = -{ - TCHAR, 'C', 0, - TUCHAR, 'b', 0, - TSHORT, 'd', 0, - TUSHORT, 'u', 0, - TLONG, 'D', 0, - TULONG, 'U', 0, - TVLONG, 'V', 0, - TUVLONG, 'W', 0, - TFLOAT, 'f', 0, - TDOUBLE, 'F', 0, - TARRAY, 'a', 0, - TIND, 'X', 0, - -1, 0, 0, -}; - -static void -pickleinit(void) -{ - Init *p; - - for(p=picklecinit; p->code >= 0; p++) - picklechar[p->code] = p->value; - - picklechar[TINT] = picklechar[TLONG]; - picklechar[TUINT] = picklechar[TULONG]; - if(types[TINT]->width != types[TLONG]->width) { - picklechar[TINT] = picklechar[TSHORT]; - picklechar[TUINT] = picklechar[TUSHORT]; - if(types[TINT]->width != types[TSHORT]->width) - warn(Z, "picklemember int not long or short"); - } - -} - -void -picklemember(Type *t, int32 off) -{ - Sym *s, *s1; - static int picklecharinit = 0; - - if(picklecharinit == 0) { - pickleinit(); - picklecharinit = 1; - } - s = t->sym; - switch(t->etype) { - default: - Bprint(&outbuf, " T%d\n", t->etype); - break; - - case TIND: - if(s == S) - Bprint(&outbuf, - "%s\"p\", (char*)addr+%d+_i*%d);\n", - picklestr, t->offset+off, t->width); - else - Bprint(&outbuf, - "%s\"p\", &addr->%s);\n", - picklestr, pmap(s->name)); - break; - - case TINT: - case TUINT: - case TCHAR: - case TUCHAR: - case TSHORT: - case TUSHORT: - case TLONG: - case TULONG: - case TVLONG: - case TUVLONG: - case TFLOAT: - case TDOUBLE: - if(s == S) - Bprint(&outbuf, "%s\"%c\", (char*)addr+%d+_i*%d);\n", - picklestr, picklechar[t->etype], t->offset+off, t->width); - else - Bprint(&outbuf, "%s\"%c\", &addr->%s);\n", - picklestr, picklechar[t->etype], pmap(s->name)); - break; - case TARRAY: - Bprint(&outbuf, "\tfor(_i = 0; _i < %d; _i++) {\n\t", - t->width/t->link->width); - picklemember(t->link, t->offset+off); - Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n"); - break; - - case TSTRUCT: - case TUNION: - s1 = picklesue(t->link); - if(s1 == S) - break; - if(s == S) { - Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%d+_i*%d));\n", - pmap(s1->name), pmap(s1->name), t->offset+off, t->width); - } else { - Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n", - pmap(s1->name), pmap(s->name)); - } - break; - } -} - -void -pickletype(Type *t) -{ - Sym *s; - Type *l; - Io *i; - int n; - char *an; - - if(!debug['P']) - return; - if(debug['P'] > 1) { - n = 0; - for(i=iostack; i; i=i->link) - n++; - if(n > 1) - return; - } - s = picklesue(t->link); - if(s == S) - return; - switch(t->etype) { - default: - Bprint(&outbuf, "T%d\n", t->etype); - return; - - case TUNION: - case TSTRUCT: - if(debug['s']) - goto asmstr; - an = pmap(s->name); - - Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an); - for(l = t->link; l != T; l = l->down) - picklemember(l, 0); - Bprint(&outbuf, "\treturn bp;\n}\n\n"); - break; - asmstr: - if(s == S) - break; - for(l = t->link; l != T; l = l->down) - if(l->sym != S) - Bprint(&outbuf, "#define\t%s.%s\t%d\n", - s->name, - l->sym->name, - l->offset); - break; - } -} - -void -picklevar(Sym *s) -{ - int n; - Io *i; - Type *t; - Sym *s1, *s2; - - if(!debug['P'] || debug['s']) - return; - if(debug['P'] > 1) { - n = 0; - for(i=iostack; i; i=i->link) - n++; - if(n > 1) - return; - } - t = s->type; - while(t && t->etype == TIND) - t = t->link; - if(t == T) - return; - if(t->etype == TENUM) { - Bprint(&outbuf, "%s = ", pmap(s->name)); - if(!typefd[t->etype]) - Bprint(&outbuf, "%lld;\n", s->vconst); - else - Bprint(&outbuf, "%f\n;", s->fconst); - return; - } - if(!typesu[t->etype]) - return; - s1 = picklesue(t->link); - if(s1 == S) - return; - switch(s->class) { - case CAUTO: - case CPARAM: - s2 = picklefun(thisfn); - if(s2) - Bprint(&outbuf, "complex %s %s:%s;\n", - pmap(s1->name), pmap(s2->name), pmap(s->name)); - break; - - case CSTATIC: - case CEXTERN: - case CGLOBL: - case CLOCAL: - Bprint(&outbuf, "complex %s %s;\n", - pmap(s1->name), pmap(s->name)); - break; - } -} diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 8689ac3da..2eae22aed 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -35,6 +35,10 @@ func parse(name string, flags uint) *ast.File { return ast1 } +func sourceLine(n ast.Node) int { + return fset.Position(n.Pos()).Line +} + // ReadGo populates f with information learned from reading the // Go source file with the given file name. It gathers the C preamble // attached to the import "C" comment, a list of references to C.xxx, @@ -69,10 +73,13 @@ func (f *File) ReadGo(name string) { if s.Name != nil { error(s.Path.Pos(), `cannot rename import "C"`) } - if s.Doc != nil { - f.Preamble += doc.CommentText(s.Doc) + "\n" - } else if len(d.Specs) == 1 && d.Doc != nil { - f.Preamble += doc.CommentText(d.Doc) + "\n" + cg := s.Doc + if cg == nil && len(d.Specs) == 1 { + cg = d.Doc + } + if cg != nil { + f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name) + f.Preamble += doc.CommentText(cg) + "\n" } } } @@ -298,6 +305,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} f.walk(n.Stmt, "stmt", visit) case *ast.ExprStmt: f.walk(&n.X, "expr", visit) + case *ast.SendStmt: + f.walk(&n.Chan, "expr", visit) + f.walk(&n.Value, "expr", visit) case *ast.IncDecStmt: f.walk(&n.X, "expr", visit) case *ast.AssignStmt: @@ -336,8 +346,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{} f.walk(n.Assign, "stmt", visit) f.walk(n.Body, "stmt", visit) case *ast.CommClause: - f.walk(n.Lhs, "expr", visit) - f.walk(n.Rhs, "expr", visit) + f.walk(n.Comm, "stmt", visit) f.walk(n.Body, "stmt", visit) case *ast.SelectStmt: f.walk(n.Body, "stmt", visit) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 0f9204d7f..c4868345c 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -23,6 +23,15 @@ the package. For example: // #include <errno.h> import "C" +CFLAGS and LDFLAGS may be defined with pseudo #cgo directives +within these comments to tweak the behavior of gcc. Values defined +in multiple directives are concatenated together. For example: + + // #cgo CFLAGS: -DPNG_DEBUG=1 + // #cgo LDFLAGS: -lpng + // #include <png.h> + import "C" + C identifiers or field names that are keywords in Go can be accessed by prefixing them with an underscore: if x points at a C struct with a field named "type", x._type accesses the field. diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index be3b8fe64..cadc6fae9 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -21,19 +21,22 @@ import ( "os" "strconv" "strings" + "unicode" ) var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") var nameToC = map[string]string{ - "schar": "signed char", - "uchar": "unsigned char", - "ushort": "unsigned short", - "uint": "unsigned int", - "ulong": "unsigned long", - "longlong": "long long", - "ulonglong": "unsigned long long", + "schar": "signed char", + "uchar": "unsigned char", + "ushort": "unsigned short", + "uint": "unsigned int", + "ulong": "unsigned long", + "longlong": "long long", + "ulonglong": "unsigned long long", + "complexfloat": "float complex", + "complexdouble": "double complex", } // cname returns the C name to use for C.s. @@ -57,6 +60,107 @@ func cname(s string) string { return s } +// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file +// preamble. Multiple occurrences are concatenated with a separating space, +// even across files. +func (p *Package) ParseFlags(f *File, srcfile string) { + linesIn := strings.Split(f.Preamble, "\n", -1) + linesOut := make([]string, 0, len(linesIn)) + for _, line := range linesIn { + l := strings.TrimSpace(line) + if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) { + linesOut = append(linesOut, line) + continue + } + + l = strings.TrimSpace(l[4:]) + fields := strings.Split(l, ":", 2) + if len(fields) != 2 { + fatal("%s: bad #cgo line: %s", srcfile, line) + } + + k := fields[0] + v := strings.TrimSpace(fields[1]) + if k != "CFLAGS" && k != "LDFLAGS" { + fatal("%s: unsupported #cgo option %s", srcfile, k) + } + args, err := splitQuoted(v) + if err != nil { + fatal("%s: bad #cgo option %s: %s", srcfile, k, err.String()) + } + if oldv, ok := p.CgoFlags[k]; ok { + p.CgoFlags[k] = oldv + " " + v + } else { + p.CgoFlags[k] = v + } + if k == "CFLAGS" { + p.GccOptions = append(p.GccOptions, args...) + } + } + f.Preamble = strings.Join(linesOut, "\n") +} + +// splitQuoted splits the string s around each instance of one or more consecutive +// white space characters while taking into account quotes and escaping, and +// returns an array of substrings of s or an empty list if s contains only white space. +// Single quotes and double quotes are recognized to prevent splitting within the +// quoted region, and are removed from the resulting substrings. If a quote in s +// isn't closed err will be set and r will have the unclosed argument as the +// last element. The backslash is used for escaping. +// +// For example, the following string: +// +// `a b:"c d" 'e''f' "g\""` +// +// Would be parsed as: +// +// []string{"a", "b:c d", "ef", `g"`} +// +func splitQuoted(s string) (r []string, err os.Error) { + var args []string + arg := make([]int, len(s)) + escaped := false + quoted := false + quote := 0 + i := 0 + for _, rune := range s { + switch { + case escaped: + escaped = false + case rune == '\\': + escaped = true + continue + case quote != 0: + if rune == quote { + quote = 0 + continue + } + case rune == '"' || rune == '\'': + quoted = true + quote = rune + continue + case unicode.IsSpace(rune): + if quoted || i > 0 { + quoted = false + args = append(args, string(arg[:i])) + i = 0 + } + continue + } + arg[i] = rune + i++ + } + if quoted || i > 0 { + args = append(args, string(arg[:i])) + } + if quote != 0 { + err = os.ErrorString("unclosed quote") + } else if escaped { + err = os.ErrorString("unfinished escaping") + } + return args, err +} + // Translate rewrites f.AST, the original Go input, to remove // references to the imported package C, replacing them with // references to the equivalent Go types, functions, and variables. @@ -205,9 +309,7 @@ func (p *Package) guessKinds(f *File) []*Name { for _, line := range strings.Split(stderr, "\n", -1) { if len(line) < 9 || line[0:9] != "cgo-test:" { - if len(line) > 8 && line[0:8] == "<stdin>:" { - fatal("gcc produced unexpected output:\n%s\non input:\n%s", line, b.Bytes()) - } + // the user will see any compiler errors when the code is compiled later. continue } line = line[9:] @@ -568,10 +670,6 @@ func runGcc(stdin []byte, args []string) (string, string) { os.Stderr.Write(stderr) } if !ok { - fmt.Fprint(os.Stderr, "Error running gcc:\n") - fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) - os.Stderr.Write(stdin) - fmt.Fprint(os.Stderr, "EOF\n") os.Stderr.Write(stderr) os.Exit(2) } @@ -591,6 +689,7 @@ type typeConv struct { int8, int16, int32, int64 ast.Expr uint8, uint16, uint32, uint64, uintptr ast.Expr float32, float64 ast.Expr + complex64, complex128 ast.Expr void ast.Expr unsafePointer ast.Expr string ast.Expr @@ -617,6 +716,8 @@ func (c *typeConv) Init(ptrSize int64) { c.uintptr = c.Ident("uintptr") c.float32 = c.Ident("float32") c.float64 = c.Ident("float64") + c.complex64 = c.Ident("complex64") + c.complex128 = c.Ident("complex128") c.unsafePointer = c.Ident("unsafe.Pointer") c.void = c.Ident("void") c.string = c.Ident("string") @@ -648,6 +749,8 @@ var dwarfToName = map[string]string{ "long long int": "longlong", "long long unsigned int": "ulonglong", "signed char": "schar", + "float complex": "complexfloat", + "double complex": "complexdouble", } // Type returns a *Type with the same memory layout as @@ -749,6 +852,19 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type { t.Align = c.ptrSize } + case *dwarf.ComplexType: + switch t.Size { + default: + fatal("unexpected: %d-byte complex type - %s", t.Size, dtype) + case 8: + t.Go = c.complex64 + case 16: + t.Go = c.complex128 + } + if t.Align = t.Size; t.Align >= c.ptrSize { + t.Align = c.ptrSize + } + case *dwarf.FuncType: // No attempt at translation: would enable calls // directly between worlds, but we need to moderate those. diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 942bda5f4..b15d34527 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -20,6 +20,7 @@ import ( "os" "reflect" "strings" + "runtime" ) // A Package collects information about the package we're going to write. @@ -28,6 +29,7 @@ type Package struct { PackagePath string PtrSize int64 GccOptions []string + CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS) Written map[string]bool Name map[string]*Name // accumulated Name from Files Typedef map[string]ast.Expr // accumulated Typedef from Files @@ -97,7 +99,8 @@ type FuncType struct { } func usage() { - fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n") + fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n") + flag.PrintDefaults() os.Exit(2) } @@ -127,6 +130,13 @@ func main() { // specialized knowledge gcc has about where to look for imported // symbols and which ones to use. syms, imports := dynimport(*dynobj) + if runtime.GOOS == "windows" { + for _, sym := range syms { + ss := strings.Split(sym, ":", -1) + fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1])) + } + return + } for _, sym := range syms { fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "") } @@ -152,7 +162,12 @@ func main() { if i == len(args) { usage() } - gccOptions, goFiles := args[0:i], args[i:] + + // Copy it to a new slice so it can grow. + gccOptions := make([]string, i) + copy(gccOptions, args[0:i]) + + goFiles := args[i:] arch := os.Getenv("GOARCH") if arch == "" { @@ -171,6 +186,7 @@ func main() { p := &Package{ PtrSize: ptrSize, GccOptions: gccOptions, + CgoFlags: make(map[string]string), Written: make(map[string]bool), } @@ -190,11 +206,17 @@ func main() { } cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6]) - for _, input := range goFiles { + fs := make([]*File, len(goFiles)) + for i, input := range goFiles { + // Parse flags for all files before translating due to CFLAGS. f := new(File) - // Reset f.Preamble so that we don't end up with conflicting headers / defines - f.Preamble = "" f.ReadGo(input) + p.ParseFlags(f, input) + fs[i] = f + } + + for i, input := range goFiles { + f := fs[i] p.Translate(f) for _, cref := range f.Ref { switch cref.Context { diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index c3f9ae60b..ede8f57d8 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -8,6 +8,7 @@ import ( "bytes" "debug/elf" "debug/macho" + "debug/pe" "fmt" "go/ast" "go/printer" @@ -32,9 +33,17 @@ func (p *Package) writeDefs() { fc := creat("_cgo_defun.c") fm := creat("_cgo_main.c") + fflg := creat("_cgo_flags") + for k, v := range p.CgoFlags { + fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v) + } + fflg.Close() + // Write C main file for using gcc to resolve imports. fmt.Fprintf(fm, "int main() { return 0; }\n") - fmt.Fprintf(fm, "int crosscall2;\n\n") + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") + fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") + fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") // Write second Go output: definitions of _C_xxx. // In a separate file so that the import of "unsafe" does not @@ -101,12 +110,14 @@ func dynimport(obj string) (syms, imports []string) { ImportedSymbols() ([]string, os.Error) } var isMacho bool - var err1, err2 os.Error + var err1, err2, err3 os.Error if f, err1 = elf.Open(obj); err1 != nil { - if f, err2 = macho.Open(obj); err2 != nil { - fatal("cannot parse %s as ELF (%v) or Mach-O (%v)", obj, err1, err2) + if f, err2 = pe.Open(obj); err2 != nil { + if f, err3 = macho.Open(obj); err3 != nil { + fatal("cannot parse %s as ELF (%v) or PE (%v) or Mach-O (%v)", obj, err1, err2, err3) + } + isMacho = true } - isMacho = true } var err os.Error diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go index 10cb5b387..5eb398735 100644 --- a/src/cmd/ebnflint/ebnflint.go +++ b/src/cmd/ebnflint/ebnflint.go @@ -88,6 +88,7 @@ func main() { src, err := ioutil.ReadFile(filename) if err != nil { scanner.PrintError(os.Stderr, err) + os.Exit(1) } if path.Ext(filename) == ".html" { @@ -97,9 +98,11 @@ func main() { grammar, err := ebnf.Parse(fset, filename, src) if err != nil { scanner.PrintError(os.Stderr, err) + os.Exit(1) } if err = ebnf.Verify(fset, grammar, *start); err != nil { scanner.PrintError(os.Stderr, err) + os.Exit(1) } } diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index a3785e871..ed20e7e8b 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -412,11 +412,9 @@ typeinit(void) isfloat[TFLOAT32] = 1; isfloat[TFLOAT64] = 1; - isfloat[TFLOAT] = 1; iscomplex[TCOMPLEX64] = 1; iscomplex[TCOMPLEX128] = 1; - iscomplex[TCOMPLEX] = 1; isptr[TPTR32] = 1; isptr[TPTR64] = 1; diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index 380abc642..48f45293f 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -66,16 +66,18 @@ char *runtimeimport = "func \"\".mapiter2 (hiter *any) (key any, val any)\n" "func \"\".makechan (elem *uint8, hint int64) chan any\n" "func \"\".chanrecv1 (hchan <-chan any) any\n" - "func \"\".chanrecv2 (hchan <-chan any) (elem any, pres bool)\n" + "func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n" "func \"\".chansend1 (hchan chan<- any, elem any)\n" - "func \"\".chansend2 (hchan chan<- any, elem any) bool\n" "func \"\".closechan (hchan any)\n" "func \"\".closedchan (hchan any) bool\n" + "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n" + "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n" "func \"\".newselect (size int) *uint8\n" "func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n" "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n" "func \"\".selectdefault (sel *uint8) bool\n" "func \"\".selectgo (sel *uint8)\n" + "func \"\".block ()\n" "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n" "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n" "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n" diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index 72e67a634..0ee693c02 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -980,10 +980,10 @@ defaultlit(Node **np, Type *t) n->type = types[TINT]; goto num; case CTFLT: - n->type = types[TFLOAT]; + n->type = types[TFLOAT64]; goto num; case CTCPLX: - n->type = types[TCOMPLEX]; + n->type = types[TCOMPLEX128]; goto num; num: if(t != T) { @@ -1034,13 +1034,13 @@ defaultlit2(Node **lp, Node **rp, int force) if(!force) return; if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) { - convlit(lp, types[TCOMPLEX]); - convlit(rp, types[TCOMPLEX]); + convlit(lp, types[TCOMPLEX128]); + convlit(rp, types[TCOMPLEX128]); return; } if(isconst(l, CTFLT) || isconst(r, CTFLT)) { - convlit(lp, types[TFLOAT]); - convlit(rp, types[TFLOAT]); + convlit(lp, types[TFLOAT64]); + convlit(rp, types[TFLOAT64]); return; } convlit(lp, types[TINT]); diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c index e25f3cabb..3ec9fe5a2 100644 --- a/src/cmd/gc/cplx.c +++ b/src/cmd/gc/cplx.c @@ -84,7 +84,7 @@ maybe: case OSUB: case OMUL: case OMINUS: - case OCMPLX: + case OCOMPLEX: case OREAL: case OIMAG: goto yes; @@ -120,7 +120,7 @@ complexgen(Node *n, Node *res) // pick off float/complex opcodes switch(n->op) { - case OCMPLX: + case OCOMPLEX: if(res->addable) { subnode(&n1, &n2, res); tempname(&tmp, n1.type); @@ -195,7 +195,7 @@ complexgen(Node *n, Node *res) case OSUB: case OMUL: case OMINUS: - case OCMPLX: + case OCOMPLEX: case OREAL: case OIMAG: break; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 73ea5b976..bf84c12a1 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -356,7 +356,7 @@ enum OARRAY, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, - OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP, + OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP, OBAD, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCAP, @@ -383,14 +383,14 @@ enum ONOT, OCOM, OPLUS, OMINUS, OOROR, OPANIC, OPRINT, OPRINTN, - OSEND, OSENDNB, + OSEND, OSLICE, OSLICEARR, OSLICESTR, ORECOVER, ORECV, ORUNESTR, OSELRECV, OIOTA, - OREAL, OIMAG, OCMPLX, + OREAL, OIMAG, OCOMPLEX, // stmts OBLOCK, @@ -440,11 +440,9 @@ enum TCOMPLEX64, // 12 TCOMPLEX128, - TCOMPLEX, TFLOAT32, // 15 TFLOAT64, - TFLOAT, TBOOL, // 18 diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 917265758..994840ee8 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -93,9 +93,10 @@ static void fixlbrace(int); %type <type> hidden_type_func %type <type> hidden_type_recv_chan hidden_type_non_recv_chan +%left LCOMM /* outside the usual hierarchy; here for good error messages */ + %left LOROR %left LANDAND -%left LCOMM %left LEQ LNE LLE LGE LLT LGT %left '+' '-' '|' '^' %left '*' '/' '%' '&' LLSH LRSH LANDNOT @@ -421,11 +422,18 @@ simple_stmt: | expr_list LCOLAS expr_list { if($3->n->op == OTYPESW) { + Node *n; + + n = N; if($3->next != nil) yyerror("expr.(type) must be alone in list"); - else if($1->next != nil) + if($1->next != nil) yyerror("argument count mismatch: %d = %d", count($1), 1); - $$ = nod(OTYPESW, $1->n, $3->n->right); + else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) + yyerror("invalid variable name %#N in type switch", $1->n); + else + n = $1->n; + $$ = nod(OTYPESW, n, $3->n->right); break; } $$ = colas($1, $3); @@ -764,6 +772,7 @@ expr: { $$ = nod(ORSH, $1, $3); } + /* not an expression anymore, but left in so we can give a good error */ | expr LCOMM expr { $$ = nod(OSEND, $1, $3); diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 0f1acd2fc..45b1257fa 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -1531,7 +1531,7 @@ static struct "cap", LNAME, Txxx, OCAP, "close", LNAME, Txxx, OCLOSE, "closed", LNAME, Txxx, OCLOSED, - "cmplx", LNAME, Txxx, OCMPLX, + "complex", LNAME, Txxx, OCOMPLEX, "copy", LNAME, Txxx, OCOPY, "imag", LNAME, Txxx, OIMAG, "len", LNAME, Txxx, OLEN, diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index 6bb1f026b..695a5a397 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -48,6 +48,7 @@ exprfmt(Fmt *f, Node *n, int prec) case ODOTMETH: case ODOTTYPE: case ODOTTYPE2: + case OXDOT: case OARRAYBYTESTR: case OCAP: case OCLOSE: @@ -365,8 +366,8 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, ")"); break; - case OCMPLX: - fmtprint(f, "cmplx("); + case OCOMPLEX: + fmtprint(f, "complex("); exprfmt(f, n->left, 0); fmtprint(f, ", "); exprfmt(f, n->right, 0); diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index dca3a5454..4ee8f39a7 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -93,6 +93,7 @@ walkrange(Node *n) Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 Node *ha, *hit; // hidden aggregate, iterator Node *hn, *hp; // hidden len, pointer + Node *hb; // hidden bool Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 Node *fn, *tmp; NodeList *body, *init; @@ -199,9 +200,15 @@ walkrange(Node *n) case TCHAN: hv1 = nod(OXXX, N, n); tempname(hv1, t->type); - - n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N); - n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N))); + hb = nod(OXXX, N, N); + tempname(hb, types[TBOOL]); + + n->ntest = nod(ONOT, hb, N); + a = nod(OAS2RECVCLOSED, N, N); + a->typecheck = 1; + a->list = list(list1(hv1), hb); + a->rlist = list1(nod(ORECV, ha, N)); + n->ntest->ninit = list1(a); body = list1(nod(OAS, v1, hv1)); break; diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index b31eb5154..36c245d47 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -419,10 +419,8 @@ enum { KindUint32, KindUint64, KindUintptr, - KindFloat, KindFloat32, KindFloat64, - KindComplex, KindComplex64, KindComplex128, KindArray, @@ -453,7 +451,6 @@ kinds[] = [TINT64] = KindInt64, [TUINT64] = KindUint64, [TUINTPTR] = KindUintptr, - [TFLOAT] = KindFloat, [TFLOAT32] = KindFloat32, [TFLOAT64] = KindFloat64, [TBOOL] = KindBool, @@ -466,7 +463,6 @@ kinds[] = [TMAP] = KindMap, [TARRAY] = KindArray, [TFUNC] = KindFunc, - [TCOMPLEX] = KindComplex, [TCOMPLEX64] = KindComplex64, [TCOMPLEX128] = KindComplex128, }; @@ -485,10 +481,8 @@ structnames[] = [TINT64] = "*runtime.IntType", [TUINT64] = "*runtime.UintType", [TUINTPTR] = "*runtime.UintType", - [TCOMPLEX] = "*runtime.ComplexType", [TCOMPLEX64] = "*runtime.ComplexType", [TCOMPLEX128] = "*runtime.ComplexType", - [TFLOAT] = "*runtime.FloatType", [TFLOAT32] = "*runtime.FloatType", [TFLOAT64] = "*runtime.FloatType", [TBOOL] = "*runtime.BoolType", @@ -542,7 +536,6 @@ haspointers(Type *t) case TINT64: case TUINT64: case TUINTPTR: - case TFLOAT: case TFLOAT32: case TFLOAT64: case TBOOL: diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 174bc050e..bf7d045c0 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -92,17 +92,20 @@ func mapiter2(hiter *any) (key any, val any) // *byte is really *runtime.Type func makechan(elem *byte, hint int64) (hchan chan any) func chanrecv1(hchan <-chan any) (elem any) -func chanrecv2(hchan <-chan any) (elem any, pres bool) +func chanrecv3(hchan <-chan any) (elem any, closed bool) func chansend1(hchan chan<- any, elem any) -func chansend2(hchan chan<- any, elem any) (pres bool) func closechan(hchan any) func closedchan(hchan any) bool +func selectnbsend(hchan chan<- any, elem any) bool +func selectnbrecv(elem *any, hchan <-chan any) bool + func newselect(size int) (sel *byte) func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool) func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) func selectdefault(sel *byte) (selected bool) func selectgo(sel *byte) +func block() func makeslice(typ *byte, nel int64, cap int64) (ary []any) func sliceslice1(old []any, lb uint64, width uint64) (ary []any) diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 1a3771311..5686e9599 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -45,27 +45,23 @@ typecheckselect(Node *sel) break; case OAS: - // convert x = <-c into OSELRECV(x, c) - // assignment might have introduced a - // conversion. throw it away. - // it will come back when the select code - // gets generated, because it always assigns - // through a temporary. + // convert x = <-c into OSELRECV(x, <-c). + // remove implicit conversions; the eventual assignment + // will reintroduce them. if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit) n->right = n->right->left; + if(n->right->op != ORECV) { yyerror("select assignment must have receive on right hand side"); break; } n->op = OSELRECV; - n->right = n->right->left; break; case ORECV: - // convert <-c into OSELRECV(N, c) - n->op = OSELRECV; - n->right = n->left; - n->left = N; + // convert <-c into OSELRECV(N, <-c) + n = nod(OSELRECV, N, n); + ncase->left = n; break; case OSEND: @@ -81,11 +77,149 @@ typecheckselect(Node *sel) void walkselect(Node *sel) { - int lno; - Node *n, *ncase, *r, *a, *tmp, *var; + int lno, i; + Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch; NodeList *l, *init; - + + if(sel->list == nil && sel->xoffset != 0) + fatal("double walkselect"); // already rewrote + lno = setlineno(sel); + i = count(sel->list); + + // optimization: zero-case select + if(i == 0) { + sel->nbody = list1(mkcall("block", nil, nil)); + goto out; + } + + // optimization: one-case select: single op. + if(i == 1) { + cas = sel->list->n; + l = cas->ninit; + if(cas->left != N) { // not default: + n = cas->left; + l = concat(l, n->ninit); + n->ninit = nil; + switch(n->op) { + default: + fatal("select %O", n->op); + + case OSEND: + ch = cheapexpr(n->left, &l); + n->left = ch; + break; + + case OSELRECV: + r = n->right; + ch = cheapexpr(r->left, &l); + r->left = ch; + + if(n->left == N) + n = r; + else { + n = nod(OAS, n->left, r); + typecheck(&n, Etop); + } + break; + } + + // if ch == nil { block() }; n; + a = nod(OIF, N, N); + a->ntest = nod(OEQ, ch, nodnil()); + a->nbody = list1(mkcall("block", nil, &l)); + typecheck(&a, Etop); + l = list(l, a); + l = list(l, n); + } + l = concat(l, cas->nbody); + sel->nbody = l; + goto out; + } + + // introduce temporary variables for OSELRECV where needed. + // this rewrite is used by both the general code and the next optimization. + for(l=sel->list; l; l=l->next) { + cas = l->n; + n = cas->left; + if(n == N) + continue; + switch(n->op) { + case OSELRECV: + ch = n->right->left; + + // If we can use the address of the target without + // violating addressability or order of operations, do so. + // Otherwise introduce a temporary. + // Also introduce a temporary for := variables that escape, + // so that we can delay the heap allocation until the case + // is selected. + if(n->left == N || isblank(n->left)) + n->left = nodnil(); + else if(n->left->op == ONAME && + (!n->colas || (n->class&PHEAP) == 0) && + convertop(ch->type->type, n->left->type, nil) == OCONVNOP) { + n->left = nod(OADDR, n->left, N); + n->left->etype = 1; // pointer does not escape + typecheck(&n->left, Erv); + } else { + tmp = nod(OXXX, N, N); + tempname(tmp, ch->type->type); + a = nod(OADDR, tmp, N); + a->etype = 1; // pointer does not escape + typecheck(&a, Erv); + r = nod(OAS, n->left, tmp); + typecheck(&r, Etop); + cas->nbody = concat(n->ninit, cas->nbody); + n->ninit = nil; + cas->nbody = concat(list1(r), cas->nbody); + n->left = a; + } + } + } + + // optimization: two-case select but one is default: single non-blocking op. + if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) { + if(sel->list->n->left == nil) { + cas = sel->list->next->n; + dflt = sel->list->n; + } else { + dflt = sel->list->next->n; + cas = sel->list->n; + } + + n = cas->left; + r = nod(OIF, N, N); + r->ninit = cas->ninit; + switch(n->op) { + default: + fatal("select %O", n->op); + + case OSEND: + // if c != nil && selectnbsend(c, v) { body } else { default body } + ch = cheapexpr(n->left, &r->ninit); + r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()), + mkcall1(chanfn("selectnbsend", 2, ch->type), + types[TBOOL], &r->ninit, ch, n->right)); + break; + + case OSELRECV: + // if c != nil && selectnbrecv(&v, c) { body } else { default body } + r = nod(OIF, N, N); + r->ninit = cas->ninit; + ch = cheapexpr(n->right->left, &r->ninit); + r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()), + mkcall1(chanfn("selectnbrecv", 2, ch->type), + types[TBOOL], &r->ninit, n->left, ch)); + break; + } + typecheck(&r->ntest, Erv); + r->nbody = cas->nbody; + r->nelse = concat(dflt->ninit, dflt->nbody); + sel->nbody = list1(r); + goto out; + } + init = sel->ninit; sel->ninit = nil; @@ -96,16 +230,13 @@ walkselect(Node *sel) typecheck(&r, Etop); init = list(init, r); - if(sel->list == nil && sel->xoffset != 0) - fatal("double walkselect"); // already rewrote - // register cases for(l=sel->list; l; l=l->next) { - ncase = l->n; - n = ncase->left; + cas = l->n; + n = cas->left; r = nod(OIF, N, N); - r->nbody = ncase->ninit; - ncase->ninit = nil; + r->nbody = cas->ninit; + cas->ninit = nil; if(n != nil) { r->nbody = concat(r->nbody, n->ninit); n->ninit = nil; @@ -113,29 +244,24 @@ walkselect(Node *sel) if(n == nil) { // selectdefault(sel *byte); r->ntest = mkcall("selectdefault", types[TBOOL], &init, var); - } else if(n->op == OSEND) { - // selectsend(sel *byte, hchan *chan any, elem any) (selected bool); - r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &init, var, n->left, n->right); - } else if(n->op == OSELRECV) { - tmp = N; - if(n->left == N) - a = nodnil(); - else { - // introduce temporary until we're sure this will succeed. - tmp = nod(OXXX, N, N); - tempname(tmp, n->right->type->type); - a = nod(OADDR, tmp, N); - } - // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); - r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->type), types[TBOOL], &init, var, n->right, a); - if(tmp != N) { - a = nod(OAS, n->left, tmp); - typecheck(&a, Etop); - r->nbody = list(r->nbody, a); + } else { + switch(n->op) { + default: + fatal("select %O", n->op); + + case OSEND: + // selectsend(sel *byte, hchan *chan any, elem any) (selected bool); + r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], + &init, var, n->left, n->right); + break; + case OSELRECV: + // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); + r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], + &init, var, n->right->left, n->left); + break; } - } else - fatal("select %O", n->op); - r->nbody = concat(r->nbody, ncase->nbody); + } + r->nbody = concat(r->nbody, cas->nbody); r->nbody = list(r->nbody, nod(OBREAK, N, N)); init = list(init, r); } @@ -143,8 +269,9 @@ walkselect(Node *sel) // run the select init = list(init, mkcall("selectgo", T, nil, var)); sel->nbody = init; - sel->list = nil; - walkstmtlist(init); +out: + sel->list = nil; + walkstmtlist(sel->nbody); lineno = lno; } diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 19ee3327b..31781646d 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -94,7 +94,7 @@ init1(Node *n, NodeList **out) case OAS2FUNC: case OAS2MAPR: case OAS2DOTTYPE: - case OAS2RECV: + case OAS2RECVCLOSED: if(n->defn->initorder) break; n->defn->initorder = 1; @@ -917,14 +917,12 @@ gen_as_init(Node *n) case TPTR64: case TFLOAT32: case TFLOAT64: - case TFLOAT: gused(N); // in case the data is the dest of a goto gdata(&nam, nr, nr->type->width); break; case TCOMPLEX64: case TCOMPLEX128: - case TCOMPLEX: gused(N); // in case the data is the dest of a goto gdatacomplex(&nam, nr->val.u.cval); break; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 3c4501096..cb5e2a831 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -836,7 +836,7 @@ goopnames[] = [OCASE] = "case", [OCLOSED] = "closed", [OCLOSE] = "close", - [OCMPLX] = "cmplx", + [OCOMPLEX] = "complex", [OCOM] = "^", [OCONTINUE] = "continue", [OCOPY] = "copy", @@ -993,10 +993,8 @@ etnames[] = [TINT64] = "INT64", [TUINT64] = "UINT64", [TUINTPTR] = "UINTPTR", - [TFLOAT] = "FLOAT", [TFLOAT32] = "FLOAT32", [TFLOAT64] = "FLOAT64", - [TCOMPLEX] = "COMPLEX", [TCOMPLEX64] = "COMPLEX64", [TCOMPLEX128] = "COMPLEX128", [TBOOL] = "BOOL", @@ -1117,10 +1115,8 @@ basicnames[] = [TINT64] = "int64", [TUINT64] = "uint64", [TUINTPTR] = "uintptr", - [TFLOAT] = "float", [TFLOAT32] = "float32", [TFLOAT64] = "float64", - [TCOMPLEX] = "complex", [TCOMPLEX64] = "complex64", [TCOMPLEX128] = "complex128", [TBOOL] = "bool", @@ -1752,8 +1748,6 @@ int cplxsubtype(int et) { switch(et) { - case TCOMPLEX: - return TFLOAT; case TCOMPLEX64: return TFLOAT32; case TCOMPLEX128: diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index ca114d47c..931d0327a 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -18,7 +18,7 @@ static int onearg(Node*, char*, ...); static int twoarg(Node*); static int lookdot(Node*, Type*, int); static int looktypedot(Node*, Type*, int); -static void typecheckaste(int, int, Type*, NodeList*, char*); +static void typecheckaste(int, Node*, int, Type*, NodeList*, char*); static Type* lookdot1(Sym *s, Type *t, Type *f, int); static int nokeys(NodeList*); static void typecheckcomplit(Node**); @@ -56,6 +56,34 @@ typechecklist(NodeList *l, int top) typecheck(&l->n, top); } +static char* typekind[] = { + [TINT] = "int", + [TUINT] = "uint", + [TINT8] = "int8", + [TUINT8] = "uint8", + [TINT16] = "int16", + [TUINT16] = "uint16", + [TINT32] = "int32", + [TUINT32] = "uint32", + [TINT64] = "int64", + [TUINT64] = "uint64", + [TUINTPTR] = "uintptr", + [TCOMPLEX64] = "complex64", + [TCOMPLEX128] = "complex128", + [TFLOAT32] = "float32", + [TFLOAT64] = "float64", + [TBOOL] = "bool", + [TSTRING] = "string", + [TPTR32] = "pointer", + [TPTR64] = "pointer", + [TSTRUCT] = "struct", + [TINTER] = "interface", + [TCHAN] = "chan", + [TMAP] = "map", + [TARRAY] = "array", + [TFUNC] = "func", +}; + /* * type check node *np. * replaces *np with a new pointer in some cases. @@ -372,21 +400,25 @@ reswitch: et = t->etype; } if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { - badbinary: defaultlit2(&l, &r, 1); - yyerror("invalid operation: %#N (type %T %#O %T)", n, l->type, op, r->type); + yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type); + goto error; + } + if(!okfor[op][et]) { + notokfor: + yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind[et]); goto error; } - if(!okfor[op][et]) - goto badbinary; // okfor allows any array == array; // restrict to slice == nil and nil == slice. if(l->type->etype == TARRAY && !isslice(l->type)) - goto badbinary; + goto notokfor; if(r->type->etype == TARRAY && !isslice(r->type)) - goto badbinary; - if(isslice(l->type) && !isnil(l) && !isnil(r)) - goto badbinary; + goto notokfor; + if(isslice(l->type) && !isnil(l) && !isnil(r)) { + yyerror("invalid operation: %#N (slice can only be compared to nil)", n); + goto error; + } t = l->type; if(iscmp[n->op]) { evconst(n); @@ -472,7 +504,7 @@ reswitch: l = n->left; if((t = l->type) == T) goto error; - if(!(top & Eindir)) + if(!(top & Eindir) && !n->etype) addrescapes(n->left); n->type = ptrto(t); goto ret; @@ -636,6 +668,10 @@ reswitch: goto ret; case OSEND: + if(top & Erv) { + yyerror("send statement %#N used as value; use select for non-blocking send", n); + goto error; + } ok |= Etop | Erv; l = typecheck(&n->left, Erv); typecheck(&n->right, Erv); @@ -659,10 +695,6 @@ reswitch: // TODO: more aggressive n->etype = 0; n->type = T; - if(top & Erv) { - n->op = OSENDNB; - n->type = types[TBOOL]; - } goto ret; case OSLICE: @@ -769,7 +801,7 @@ reswitch: case ODOTMETH: n->op = OCALLMETH; - typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver"); + typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver"); break; default: @@ -780,7 +812,7 @@ reswitch: } break; } - typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument"); + typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument"); ok |= Etop; if(t->outtuple == 0) goto ret; @@ -852,7 +884,7 @@ reswitch: n->type = types[TINT]; goto ret; - case OCMPLX: + case OCOMPLEX: ok |= Erv; if(twoarg(n) < 0) goto error; @@ -865,7 +897,7 @@ reswitch: n->right = r; if(l->type->etype != r->type->etype) { badcmplx: - yyerror("invalid operation: %#N (cmplx of types %T, %T)", n, l->type, r->type); + yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type); goto error; } switch(l->type->etype) { @@ -874,9 +906,6 @@ reswitch: case TIDEAL: t = types[TIDEAL]; break; - case TFLOAT: - t = types[TCOMPLEX]; - break; case TFLOAT32: t = types[TCOMPLEX64]; break; @@ -1217,7 +1246,7 @@ reswitch: } if(curfn->type->outnamed && n->list == nil) goto ret; - typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument"); + typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument"); goto ret; case OSELECT: @@ -1562,7 +1591,7 @@ nokeys(NodeList *l) * typecheck assignment: type list = expression list */ static void -typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc) +typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc) { Type *t, *tl, *tn; Node *n; @@ -1581,16 +1610,24 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc) if(tl->isddd) { for(; tn; tn=tn->down) { exportassignok(tn->type, desc); - if(assignop(tn->type, tl->type->type, &why) == 0) - yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); + if(assignop(tn->type, tl->type->type, &why) == 0) { + if(call != N) + yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, desc, call, why); + else + yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); + } } goto out; } if(tn == T) goto notenough; exportassignok(tn->type, desc); - if(assignop(tn->type, tl->type, &why) == 0) - yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); + if(assignop(tn->type, tl->type, &why) == 0) { + if(call != N) + yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, desc, call, why); + else + yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); + } tn = tn->down; } if(tn != T) @@ -1635,19 +1672,29 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc) } if(nl != nil) goto toomany; - if(isddd) - yyerror("invalid use of ... in %#O", op); + if(isddd) { + if(call != N) + yyerror("invalid use of ... in call to %#N", call); + else + yyerror("invalid use of ... in %#O", op); + } out: lineno = lno; return; notenough: - yyerror("not enough arguments to %#O", op); + if(call != N) + yyerror("not enough arguments in call to %#N", call); + else + yyerror("not enough arguments to %#O", op); goto out; toomany: - yyerror("too many arguments to %#O", op); + if(call != N) + yyerror("too many arguments in call to %#N", call); + else + yyerror("too many arguments to %#O", op); goto out; } @@ -2329,8 +2376,8 @@ typecheckas2(Node *n) n->op = OAS2MAPR; goto common; case ORECV: - n->op = OAS2RECV; - goto common; + yyerror("cannot use multiple-value assignment for non-blocking receive; use select"); + goto out; case ODOTTYPE: n->op = OAS2DOTTYPE; r->op = ODOTTYPE2; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index fa3e5d5e4..b32b6fff5 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -269,9 +269,15 @@ walkdef(Node *n) } t = n->type; if(t != T) { - convlit(&e, t); - if(!okforconst[t->etype]) + if(!okforconst[t->etype]) { yyerror("invalid constant type %T", t); + goto ret; + } + if(!isideal(e->type) && !eqtype(t, e->type)) { + yyerror("cannot use %+N as type %T in const initializer", e, t); + goto ret; + } + convlit(&e, t); } n->val = e->val; n->type = e->type; @@ -397,7 +403,7 @@ walkstmt(Node **np) case OAS: case OAS2: case OAS2DOTTYPE: - case OAS2RECV: + case OAS2RECVCLOSED: case OAS2FUNC: case OAS2MAPW: case OAS2MAPR: @@ -664,7 +670,7 @@ walkexpr(Node **np, NodeList **init) case OGE: case OGT: case OADD: - case OCMPLX: + case OCOMPLEX: walkexpr(&n->left, init); walkexpr(&n->right, init); goto ret; @@ -816,14 +822,14 @@ walkexpr(Node **np, NodeList **init) n = liststmt(concat(concat(list1(r), ll), lpost)); goto ret; - case OAS2RECV: - // a,b = <-c + case OAS2RECVCLOSED: + // a = <-c; b = closed(c) but atomic *init = concat(*init, n->ninit); n->ninit = nil; r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); - fn = chanfn("chanrecv2", 2, r->left->type); + fn = chanfn("chanrecv3", 2, r->left->type); r = mkcall1(fn, getoutargx(fn->type), init, r->left); n->rlist->n = r; n->op = OAS2FUNC; @@ -1401,10 +1407,6 @@ walkexpr(Node **np, NodeList **init) n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right); goto ret; - case OSENDNB: - n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right); - goto ret; - case OCLOSURE: n = walkclosure(n, init); goto ret; diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c index 69ee1be5d..d4163421d 100644 --- a/src/cmd/godefs/main.c +++ b/src/cmd/godefs/main.c @@ -196,7 +196,7 @@ main(int argc, char **argv) av[n++] = "gcc"; av[n++] = "-fdollars-in-identifiers"; av[n++] = "-S"; // write assembly - av[n++] = "-gstabs"; // include stabs info + av[n++] = "-gstabs+"; // include stabs info av[n++] = "-o"; // to ... av[n++] = "-"; // ... stdout av[n++] = "-xc"; // read C diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c index 1bc96d4c8..f2bb57eb6 100644 --- a/src/cmd/godefs/stabs.c +++ b/src/cmd/godefs/stabs.c @@ -102,6 +102,23 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p) return 0; } +// Written to parse max/min of vlong correctly. +static vlong +parseoctal(char **pp) +{ + char *p; + vlong n; + + p = *pp; + if(*p++ != '0') + return 0; + n = 0; + while(*p >= '0' && *p <= '9') + n = n << 3 | *p++ - '0'; + *pp = p; + return n; +} + // Integer types are represented in stabs as a "range" // type with a lo and a hi value. The lo and hi used to // be lo and hi for the type, but there are now odd @@ -112,31 +129,24 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p) typedef struct Intrange Intrange; struct Intrange { - int signlo; // sign of lo vlong lo; - int signhi; // sign of hi vlong hi; int kind; }; -// NOTE(rsc): Iant says that these might be different depending -// on the gcc mode, though I haven't observed this yet. Intrange intranges[] = { - '+', 0, '+', 127, Int8, // char - '-', 128, '+', 127, Int8, // signed char - '+', 0, '+', 255, Uint8, - '-', 32768, '+', 32767, Int16, - '+', 0, '+', 65535, Uint16, - '-', 2147483648LL, '+', 2147483647LL, Int32, - '+', 0, '+', 4294967295LL, Uint32, - - // abnormal cases - '-', 0, '+', 4294967295LL, Int64, - '+', 0, '-', 1, Uint64, - - '+', 4, '+', 0, Float32, - '+', 8, '+', 0, Float64, - '+', 16, '+', 0, Void, + 0, 127, Int8, // char + -128, 127, Int8, // signed char + 0, 255, Uint8, + -32768, 32767, Int16, + 0, 65535, Uint16, + -2147483648LL, 2147483647LL, Int32, + 0, 4294967295LL, Uint32, + 1LL << 63, ~(1LL << 63), Int64, + 0, -1, Uint64, + 4, 0, Float32, + 8, 0, Float64, + 16, 0, Void, }; static int kindsize[] = { @@ -158,7 +168,7 @@ parsedef(char **pp, char *name) { char *p; Type *t, *tt; - int i, signlo, signhi; + int i; vlong n1, n2, lo, hi; Field *f; Intrange *r; @@ -213,6 +223,11 @@ parsedef(char **pp, char *name) *pp = ""; return t; + case '@': // type attribute + while (*++p != ';'); + *pp = ++p; + return parsedef(pp, nil); + case '*': // pointer p++; t->kind = Ptr; @@ -269,6 +284,10 @@ parsedef(char **pp, char *name) return nil; break; + case 'k': // const + ++*pp; + return parsedef(pp, nil); + case 'r': // sub-range (used for integers) p++; if(parsedef(&p, nil) == nil) @@ -280,23 +299,19 @@ parsedef(char **pp, char *name) fprint(2, "range expected number: %s\n", p); return nil; } - if(*p == '-') { - signlo = '-'; - p++; - } else - signlo = '+'; - lo = strtoll(p, &p, 10); + if(*p == '0') + lo = parseoctal(&p); + else + lo = strtoll(p, &p, 10); if(*p != ';' || *++p == ';') { if(stabsdebug) fprint(2, "range expected number: %s\n", p); return nil; } - if(*p == '-') { - signhi = '-'; - p++; - } else - signhi = '+'; - hi = strtoll(p, &p, 10); + if(*p == '0') + hi = parseoctal(&p); + else + hi = strtoll(p, &p, 10); if(*p != ';') { if(stabsdebug) fprint(2, "range expected trailing semi: %s\n", p); @@ -306,7 +321,7 @@ parsedef(char **pp, char *name) t->size = hi+1; // might be array size for(i=0; i<nelem(intranges); i++) { r = &intranges[i]; - if(r->signlo == signlo && r->signhi == signhi && r->lo == lo && r->hi == hi) { + if(r->lo == lo && r->hi == hi) { t->kind = r->kind; break; } diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go index 02779384c..f0006e750 100644 --- a/src/cmd/godoc/doc.go +++ b/src/cmd/godoc/doc.go @@ -47,8 +47,9 @@ The flags are: width of tabs in units of spaces -timestamps=true show timestamps with directory listings - -fulltext=false - build full text index for regular expression queries + -maxresults=10000 + maximum number of full text search results shown + (no full text index is built if maxresults <= 0) -path="" additional package directories (colon-separated) -html diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go index f68c67b24..66b01aa64 100644 --- a/src/cmd/godoc/format.go +++ b/src/cmd/godoc/format.go @@ -62,12 +62,48 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, if lw != nil { selections = append(selections, links) } + // compute the sequence of consecutive segment changes changes := newMerger(selections) + // The i'th bit in bitset indicates that the text // at the current offset is covered by selections[i]. bitset := 0 lastOffs := 0 + + // Text segments are written in a delayed fashion + // such that consecutive segments belonging to the + // same selection can be combined (peephole optimization). + // last describes the last segment which has not yet been written. + var last struct { + begin, end int // valid if begin < end + bitset int + } + + // flush writes the last delayed text segment + flush := func() { + if last.begin < last.end { + sw(w, text[last.begin:last.end], last.bitset) + } + last.begin = last.end // invalidate last + } + + // segment runs the segment [lastOffs, end) with the selection + // indicated by bitset through the segment peephole optimizer. + segment := func(end int) { + if lastOffs < end { // ignore empty segments + if last.end != lastOffs || last.bitset != bitset { + // the last segment is not adjacent to or + // differs from the new one + flush() + // start a new segment + last.begin = lastOffs + } + last.end = end + last.bitset = bitset + } + } + for { // get the next segment change index, offs, start := changes.next() @@ -81,14 +117,15 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, // we have a link segment change: // format the previous selection segment, write the // link tag and start a new selection segment - sw(w, text[lastOffs:offs], bitset) + segment(offs) + flush() lastOffs = offs lw(w, offs, start) } else { // we have a selection change: // format the previous selection segment, determine // the new selection bitset and start a new segment - sw(w, text[lastOffs:offs], bitset) + segment(offs) lastOffs = offs mask := 1 << uint(index) if start { @@ -98,7 +135,8 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, } } } - sw(w, text[lastOffs:], bitset) + segment(len(text)) + flush() } @@ -201,7 +239,9 @@ func lineSelection(text []byte) Selection { // func commentSelection(src []byte) Selection { var s scanner.Scanner - file := s.Init(token.NewFileSet(), "", src, nil, scanner.ScanComments+scanner.InsertSemis) + fset := token.NewFileSet() + file := fset.AddFile("", fset.Base(), len(src)) + s.Init(file, src, nil, scanner.ScanComments+scanner.InsertSemis) return func() (seg []int) { for { pos, tok, lit := s.Scan() @@ -283,17 +323,15 @@ var endTag = []byte(`</span>`) func selectionTag(w io.Writer, text []byte, selections int) { - if len(text) > 0 { - if selections < len(startTags) { - if tag := startTags[selections]; len(tag) > 0 { - w.Write(tag) - template.HTMLEscape(w, text) - w.Write(endTag) - return - } + if selections < len(startTags) { + if tag := startTags[selections]; len(tag) > 0 { + w.Write(tag) + template.HTMLEscape(w, text) + w.Write(endTag) + return } - template.HTMLEscape(w, text) } + template.HTMLEscape(w, text) } @@ -322,12 +360,12 @@ func FormatText(text []byte, line int, goSource bool, pattern string, selection if pattern != "" { highlights = regexpSelection(text, pattern) } - if comments != nil || highlights != nil || selection != nil { + if line >= 0 || comments != nil || highlights != nil || selection != nil { var lineTag LinkWriter if line >= 0 { lineTag = func(w io.Writer, _ int, start bool) { if start { - fmt.Fprintf(w, "<a id=\"L%d\"></a>%5d\t", line, line) + fmt.Fprintf(w, "<a id=\"L%d\"></a><span class=\"ln\">%6d</span>\t", line, line) line++ } } diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go index d6054ab9d..6a00a3e70 100644 --- a/src/cmd/godoc/godoc.go +++ b/src/cmd/godoc/godoc.go @@ -25,7 +25,6 @@ import ( "strings" "template" "time" - "utf8" ) @@ -56,7 +55,7 @@ var ( // TODO(gri) consider the invariant that goroot always end in '/' goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)") - path = flag.String("path", "", "additional package directories (colon-separated)") + pkgPath = flag.String("path", "", "additional package directories (colon-separated)") filter = flag.String("filter", "", "filter file containing permitted package directory paths") filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0") filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially @@ -64,7 +63,7 @@ var ( // layout control tabwidth = flag.Int("tabwidth", 4, "tab width") showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings") - fulltextIndex = flag.Bool("fulltext", false, "build full text index for regular expression queries") + maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown") // file system mapping fsMap Mapping // user-defined mapping @@ -80,7 +79,7 @@ var ( func initHandlers() { - fsMap.Init(*path) + fsMap.Init(*pkgPath) fileServer = http.FileServer(*goroot, "") cmdHandler = httpHandler{"/cmd/", pathutil.Join(*goroot, "src/cmd"), false} pkgHandler = httpHandler{"/pkg/", pathutil.Join(*goroot, "src/pkg"), true} @@ -626,11 +625,11 @@ func readTemplate(name string) *template.Template { path := pathutil.Join(*goroot, "lib/godoc/"+name) data, err := ioutil.ReadFile(path) if err != nil { - log.Exitf("ReadFile %s: %v", path, err) + log.Fatalf("ReadFile %s: %v", path, err) } t, err := template.Parse(string(data), fmap) if err != nil { - log.Exitf("%s: %v", name, err) + log.Fatalf("%s: %v", name, err) } return t } @@ -768,53 +767,6 @@ func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) { } -// TODO(gri): Should have a mapping from extension to handler, eventually. - -// textExt[x] is true if the extension x indicates a text file, and false otherwise. -var textExt = map[string]bool{ - ".css": false, // must be served raw - ".js": false, // must be served raw -} - - -func isTextFile(path string) bool { - // if the extension is known, use it for decision making - if isText, found := textExt[pathutil.Ext(path)]; found { - return isText - } - - // the extension is not known; read an initial chunk of - // file and check if it looks like correct UTF-8; if it - // does, it's probably a text file - f, err := os.Open(path, os.O_RDONLY, 0) - if err != nil { - return false - } - defer f.Close() - - var buf [1024]byte - n, err := f.Read(buf[0:]) - if err != nil { - return false - } - - s := string(buf[0:n]) - n -= utf8.UTFMax // make sure there's enough bytes for a complete unicode char - for i, c := range s { - if i > n { - break - } - if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' { - // decoding error or control character - not a text file - return false - } - } - - // likely a text file - return true -} - - func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) { src, err := ioutil.ReadFile(abspath) if err != nil { @@ -1159,41 +1111,47 @@ type SearchResult struct { func lookup(query string) (result SearchResult) { result.Query = query - // determine identifier lookup string and full text regexp - lookupStr := "" - lookupRx, err := regexp.Compile(query) - if err != nil { - result.Alert = "Error in query regular expression: " + err.String() - return - } - if prefix, complete := lookupRx.LiteralPrefix(); complete { - // otherwise we lookup "" (with no result) because - // identifier lookup doesn't support regexp search - lookupStr = prefix - } + index, timestamp := searchIndex.get() + if index != nil { + index := index.(*Index) - if index, timestamp := searchIndex.get(); index != nil { // identifier search - index := index.(*Index) - result.Hit, result.Alt, err = index.Lookup(lookupStr) - if err != nil && !*fulltextIndex { - // ignore the error if there is full text search - // since it accepts that query regular expression + var err os.Error + result.Hit, result.Alt, err = index.Lookup(query) + if err != nil && *maxResults <= 0 { + // ignore the error if full text search is enabled + // since the query may be a valid regular expression result.Alert = "Error in query string: " + err.String() return } - // textual search - // TODO(gri) should max be a flag? - const max = 10000 // show at most this many fulltext results - result.Found, result.Textual = index.LookupRegexp(lookupRx, max+1) - result.Complete = result.Found <= max - - // is the result accurate? - if _, ts := fsModified.get(); timestamp < ts { - result.Alert = "Indexing in progress: result may be inaccurate" + // full text search + if *maxResults > 0 && query != "" { + rx, err := regexp.Compile(query) + if err != nil { + result.Alert = "Error in query regular expression: " + err.String() + return + } + // If we get maxResults+1 results we know that there are more than + // maxResults results and thus the result may be incomplete (to be + // precise, we should remove one result from the result set, but + // nobody is going to count the results on the result page). + result.Found, result.Textual = index.LookupRegexp(rx, *maxResults+1) + result.Complete = result.Found <= *maxResults + if !result.Complete { + result.Found-- // since we looked for maxResults+1 + } } } + + // is the result accurate? + if _, ts := fsModified.get(); timestamp < ts { + // The index is older than the latest file system change + // under godoc's observation. Indexing may be in progress + // or start shortly (see indexer()). + result.Alert = "Indexing in progress: result may be inaccurate" + } + return } @@ -1278,7 +1236,7 @@ func indexer() { log.Printf("updating index...") } start := time.Nanoseconds() - index := NewIndex(fsDirnames(), *fulltextIndex) + index := NewIndex(fsDirnames(), *maxResults > 0) stop := time.Nanoseconds() searchIndex.set(index) if *verbose { diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go index ba6fe9acd..581409cde 100644 --- a/src/cmd/godoc/index.go +++ b/src/cmd/godoc/index.go @@ -47,7 +47,7 @@ import ( "index/suffixarray" "io/ioutil" "os" - pathutil "path" + "path" "regexp" "sort" "strings" @@ -430,8 +430,9 @@ func (a *AltWords) filter(s string) *AltWords { // Indexer // Adjust these flags as seems best. -const excludeMainPackages = false -const excludeTestFiles = false +const includeNonGoFiles = true +const includeMainPackages = true +const includeTestFiles = true type IndexResult struct { @@ -619,11 +620,14 @@ func pkgName(filename string) string { } -func (x *Indexer) addFile(filename string) *ast.File { +// addFile adds a file to the index if possible and returns the file set file +// and the file's AST if it was successfully parsed as a Go file. If addFile +// failed (that is, if the file was not added), it returns file == nil. +func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) { // open file f, err := os.Open(filename, os.O_RDONLY, 0) if err != nil { - return nil + return } defer f.Close() @@ -643,59 +647,127 @@ func (x *Indexer) addFile(filename string) *ast.File { panic("internal error - file base incorrect") } - // append file contents to x.sources - if _, err := x.sources.ReadFrom(f); err != nil { - x.sources.Truncate(base) // discard possibly added data - return nil // ignore files with I/O errors - } + // append file contents (src) to x.sources + if _, err := x.sources.ReadFrom(f); err == nil { + src := x.sources.Bytes()[base:] - // parse the file and in the process add it to the file set - src := x.sources.Bytes()[base:] // no need to reread the file - file, err := parser.ParseFile(x.fset, filename, src, parser.ParseComments) - if err != nil { - // do not discard the added source code in this case - // because the file has been added to the file set and - // the source size must match the file set base - // TODO(gri): given a FileSet.RemoveFile() one might be - // able to discard the data here (worthwhile?) - return nil // ignore files with (parse) errors + if goFile { + // parse the file and in the process add it to the file set + if ast, err = parser.ParseFile(x.fset, filename, src, parser.ParseComments); err == nil { + file = x.fset.File(ast.Pos()) // ast.Pos() is inside the file + return + } + // file has parse errors, and the AST may be incorrect - + // set lines information explicitly and index as ordinary + // text file (cannot fall through to the text case below + // because the file has already been added to the file set + // by the parser) + file = x.fset.File(token.Pos(base)) // token.Pos(base) is inside the file + file.SetLinesForContent(src) + ast = nil + return + } + + if isText(src) { + // only add the file to the file set (for the full text index) + file = x.fset.AddFile(filename, x.fset.Base(), len(src)) + file.SetLinesForContent(src) + return + } } - return file + // discard possibly added data + x.sources.Truncate(base - 1) // -1 to remove added byte 0 since no file was added + return } -func (x *Indexer) visitFile(dirname string, f *os.FileInfo) { - if !isGoFile(f) { - return +// Design note: Using an explicit white list of permitted files for indexing +// makes sure that the important files are included and massively reduces the +// number of files to index. The advantage over a blacklist is that unexpected +// (non-blacklisted) files won't suddenly explode the index. +// +// TODO(gri): We may want to make this list customizable, perhaps via a flag. + +// Files are whitelisted if they have a file name or extension +// present as key in whitelisted. +var whitelisted = map[string]bool{ + ".bash": true, + ".c": true, + ".css": true, + ".go": true, + ".goc": true, + ".h": true, + ".html": true, + ".js": true, + ".out": true, + ".py": true, + ".s": true, + ".sh": true, + ".txt": true, + ".xml": true, + "AUTHORS": true, + "CONTRIBUTORS": true, + "LICENSE": true, + "Makefile": true, + "PATENTS": true, + "README": true, +} + + +// isWhitelisted returns true if a file is on the list +// of "permitted" files for indexing. The filename must +// be the directory-local name of the file. +func isWhitelisted(filename string) bool { + key := path.Ext(filename) + if key == "" { + // file has no extension - use entire filename + key = filename } + return whitelisted[key] +} - path := pathutil.Join(dirname, f.Name) - if excludeTestFiles && (!isPkgFile(f) || strings.HasPrefix(path, "test/")) { + +func (x *Indexer) visitFile(dirname string, f *os.FileInfo) { + if !f.IsRegular() { return } - if excludeMainPackages && pkgName(path) == "main" { + filename := path.Join(dirname, f.Name) + goFile := false + + switch { + case isGoFile(f): + if !includeTestFiles && (!isPkgFile(f) || strings.HasPrefix(filename, "test/")) { + return + } + if !includeMainPackages && pkgName(filename) == "main" { + return + } + goFile = true + + case !includeNonGoFiles || !isWhitelisted(f.Name): return } - file := x.addFile(path) + file, fast := x.addFile(filename, goFile) if file == nil { - return + return // addFile failed } - // we've got a file to index - x.current = x.fset.File(file.Pos()) // file.Pos is in the current file - dir, _ := pathutil.Split(path) - pak := Pak{dir, file.Name.Name} - x.file = &File{path, pak} - ast.Walk(x, file) + if fast != nil { + // we've got a Go file to index + x.current = file + dir, _ := path.Split(filename) + pak := Pak{dir, fast.Name.Name} + x.file = &File{filename, pak} + ast.Walk(x, fast) + } // update statistics - // (count real file size as opposed to using the padded x.sources.Len()) - x.stats.Bytes += x.current.Size() + x.stats.Bytes += file.Size() x.stats.Files++ - x.stats.Lines += x.current.LineCount() + x.stats.Lines += file.LineCount() } @@ -817,7 +889,8 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) { func isIdentifier(s string) bool { var S scanner.Scanner - S.Init(token.NewFileSet(), "", []byte(s), nil, 0) + fset := token.NewFileSet() + S.Init(fset.AddFile("", fset.Base(), len(s)), []byte(s), nil, 0) if _, tok, _ := S.Scan(); tok == token.IDENT { _, tok, _ := S.Scan() return tok == token.EOF diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index fe3d22fb9..f1b11a760 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -227,7 +227,7 @@ func main() { } if *tabwidth < 0 { - log.Exitf("negative tabwidth %d", *tabwidth) + log.Fatalf("negative tabwidth %d", *tabwidth) } initHandlers() @@ -242,8 +242,8 @@ func main() { log.Printf("address = %s", *httpAddr) log.Printf("goroot = %s", *goroot) log.Printf("tabwidth = %d", *tabwidth) - if *fulltextIndex { - log.Print("full text index enabled") + if *maxResults > 0 { + log.Printf("maxresults = %d (full text index enabled)", *maxResults) } if !fsMap.IsEmpty() { log.Print("user-defined mapping:") @@ -284,7 +284,7 @@ func main() { // Start http server. if err := http.ListenAndServe(*httpAddr, handler); err != nil { - log.Exitf("ListenAndServe %s: %v", *httpAddr, err) + log.Fatalf("ListenAndServe %s: %v", *httpAddr, err) } return @@ -301,7 +301,7 @@ func main() { for i := 0; i < flag.NArg(); i++ { res, err := remoteSearch(flag.Arg(i)) if err != nil { - log.Exitf("remoteSearch: %s", err) + log.Fatalf("remoteSearch: %s", err) } io.Copy(os.Stdout, res.Body) } @@ -344,7 +344,7 @@ func main() { info = cmdHandler.getPageInfo(abspath, relpath, "", mode) } if info.Err != nil { - log.Exitf("%v", info.Err) + log.Fatalf("%v", info.Err) } // If we have more than one argument, use the remaining arguments for filtering @@ -352,7 +352,7 @@ func main() { args := flag.Args()[1:] rx := makeRx(args) if rx == nil { - log.Exitf("illegal regular expression from %v", args) + log.Fatalf("illegal regular expression from %v", args) } filter := func(s string) bool { return rx.MatchString(s) } diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go index 6a12febe1..c2838ed5a 100755 --- a/src/cmd/godoc/snippet.go +++ b/src/cmd/godoc/snippet.go @@ -26,7 +26,7 @@ type Snippet struct { func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet { // TODO instead of pretty-printing the node, should use the original source instead var buf bytes.Buffer - writeNode(&buf, fset, decl, true) + writeNode(&buf, fset, decl, false) return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)} } diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go index b1c1a883f..a533c1e0a 100644 --- a/src/cmd/godoc/spec.go +++ b/src/cmd/godoc/spec.go @@ -156,7 +156,8 @@ func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) { // initialize ebnfParser p.out = out p.src = src - p.file = p.scanner.Init(fset, "", src, p, 0) + p.file = fset.AddFile("", fset.Base(), len(src)) + p.scanner.Init(p.file, src, p, 0) p.next() // initializes pos, tok, lit // process source diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go index 55cf87841..a032bd331 100644 --- a/src/cmd/godoc/utils.go +++ b/src/cmd/godoc/utils.go @@ -15,11 +15,13 @@ import ( "strings" "sync" "time" + "utf8" ) // An RWValue wraps a value and permits mutually exclusive // access to it and records the time the value was last set. +// type RWValue struct { mutex sync.RWMutex value interface{} @@ -107,3 +109,63 @@ func writeFileAtomically(filename string, data []byte) os.Error { } return os.Rename(f.Name(), filename) } + + +// isText returns true if a significant prefix of s looks like correct UTF-8; +// that is, if it is likely that s is human-readable text. +// +func isText(s []byte) bool { + const max = 1024 // at least utf8.UTFMax + if len(s) > max { + s = s[0:max] + } + for i, c := range string(s) { + if i+utf8.UTFMax > len(s) { + // last char may be incomplete - ignore + break + } + if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' { + // decoding error or control character - not a text file + return false + } + } + return true +} + + +// TODO(gri): Should have a mapping from extension to handler, eventually. + +// textExt[x] is true if the extension x indicates a text file, and false otherwise. +var textExt = map[string]bool{ + ".css": false, // must be served raw + ".js": false, // must be served raw +} + + +// isTextFile returns true if the file has a known extension indicating +// a text file, or if a significant chunk of the specified file looks like +// correct UTF-8; that is, if it is likely that the file contains human- +// readable text. +// +func isTextFile(filename string) bool { + // if the extension is known, use it for decision making + if isText, found := textExt[pathutil.Ext(filename)]; found { + return isText + } + + // the extension is not known; read an initial chunk + // of the file and check if it looks like text + f, err := os.Open(filename, os.O_RDONLY, 0) + if err != nil { + return false + } + defer f.Close() + + var buf [1024]byte + n, err := f.Read(buf[0:]) + if err != nil { + return false + } + + return isText(buf[0:n]) +} diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go index 8ea5334e9..fbcd46aa2 100644 --- a/src/cmd/gofmt/rewrite.go +++ b/src/cmd/gofmt/rewrite.go @@ -124,9 +124,9 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { // Wildcard matches any expression. If it appears multiple // times in the pattern, it must match the same expression // each time. - if m != nil && pattern.Type() == identType { + if m != nil && pattern != nil && pattern.Type() == identType { name := pattern.Interface().(*ast.Ident).Name - if isWildcard(name) { + if isWildcard(name) && val != nil { // wildcards only match expressions if _, ok := val.Interface().(ast.Expr); ok { if old, ok := m[name]; ok { diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go index b0f08efdf..f13aeb3bc 100644 --- a/src/cmd/goinstall/main.go +++ b/src/cmd/goinstall/main.go @@ -244,8 +244,7 @@ func quietRun(dir string, stdin []byte, cmd ...string) os.Error { func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error { bin, err := exec.LookPath(cmd[0]) if err != nil { - // report binary as well as the error - return os.NewError(cmd[0] + ": " + err.String()) + return err } p, err := exec.Run(bin, cmd, os.Environ(), dir, exec.Pipe, exec.Pipe, exec.MergeWithStdout) if *verbose { diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c index 063967bd7..a16e98cfe 100644 --- a/src/cmd/gopack/ar.c +++ b/src/cmd/gopack/ar.c @@ -607,6 +607,7 @@ scanobj(Biobuf *b, Arfile *ap, long size) /* maybe a foreign object file? that's okay */ if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF + (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian Bseek(b, offset, 0); diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest index 7572610d2..87c680089 100755 --- a/src/cmd/gotest/gotest +++ b/src/cmd/gotest/gotest @@ -180,10 +180,4 @@ importpath=$(gomake -s importpath) $GC _testmain.go $GL _testmain.$O - -# Set dynamic linker library path, no matter what it's called, -# to include the current directory while running $O.out, -# so that cgo libraries can be tested without installation. -LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH \ -DYLD_LIBRARY_PATH=.:$DYLD_LIBRARY_PATH \ $E ./$O.out "$@" diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go index 2981891eb..5619b12ba 100644 --- a/src/cmd/govet/govet.go +++ b/src/cmd/govet/govet.go @@ -210,6 +210,7 @@ var printfList = map[string]int{ "Errorf": 0, "Fatalf": 0, "Fprintf": 1, + "Panicf": 0, "Printf": 0, "Sprintf": 0, } @@ -220,6 +221,7 @@ var printList = map[string]int{ "Error": 0, "Fatal": 0, "Fprint": 1, "Fprintln": 1, + "Panic": 0, "Panicln": 0, "Print": 0, "Println": 0, "Sprint": 0, "Sprintln": 0, } diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 210f10ab5..0551232cf 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -240,6 +240,33 @@ void dynrelocsym(Sym *s) { Reloc *r; + + if(thechar == '8' && HEADTYPE == 10) { // Windows PE + Sym *rel, *targ; + + rel = lookup(".rel", 0); + if(s == rel) + return; + for(r=s->r; r<s->r+s->nr; r++) { + targ = r->sym; + if(r->sym->plt == -2) { // make dynimport JMP table for PE object files. + targ->plt = rel->size; + r->sym = rel; + r->add = targ->plt; + + // jmp *addr + adduint8(rel, 0xff); + adduint8(rel, 0x25); + addaddr(rel, targ); + adduint8(rel, 0x90); + adduint8(rel, 0x90); + } else if(r->sym->plt >= 0) { + r->sym = rel; + r->add = targ->plt; + } + } + return; + } for(r=s->r; r<s->r+s->nr; r++) if(r->sym->type == SDYNIMPORT || r->type >= 256) @@ -871,7 +898,7 @@ address(void) segdata.rwx = 06; segdata.vaddr = va; segdata.fileoff = va - segtext.vaddr + segtext.fileoff; - if(thechar == '8' && HEADTYPE == 10) // Windows PE + if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Windows PE segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN); if(thechar == '8' && HEADTYPE == 2) { // Plan 9 segdata.vaddr = va = rnd(va, 4096); diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index 506c6e5db..5df3515f5 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -19,6 +19,7 @@ #include "../ld/dwarf_defs.h" #include "../ld/elf.h" #include "../ld/macho.h" +#include "../ld/pe.h" /* * Offsets and sizes of the debug_* sections in the cout file. @@ -453,19 +454,6 @@ getattr(DWDie *die, uint8 attr) return nil; } -static void -delattr(DWDie *die, uint8 attr) -{ - DWAttr **a; - - a = &die->attr; - while (*a != nil) - if ((*a)->atr == attr) - *a = (*a)->link; - else - a = &((*a)->link); -} - // Every DIE has at least a DW_AT_name attribute (but it will only be // written out if it is listed in the abbrev). If its parent is // keeping an index, the new DIE will be inserted there. @@ -768,10 +756,8 @@ enum { KindUint32, KindUint64, KindUintptr, - KindFloat, KindFloat32, KindFloat64, - KindComplex, KindComplex64, KindComplex128, KindArray, @@ -799,6 +785,17 @@ decode_reloc(Sym *s, int32 off) return nil; } +static Sym* +decode_reloc_sym(Sym *s, int32 off) +{ + Reloc *r; + + r = decode_reloc(s,off); + if (r == nil) + return nil; + return r->sym; +} + static uvlong decode_inuxi(uchar* p, int sz) { @@ -852,7 +849,7 @@ decodetype_size(Sym *s) static Sym* decodetype_arrayelem(Sym *s) { - return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30 + return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 } static vlong @@ -865,26 +862,26 @@ decodetype_arraylen(Sym *s) static Sym* decodetype_ptrelem(Sym *s) { - return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30 + return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 } // Type.MapType.key, elem static Sym* decodetype_mapkey(Sym *s) { - return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30 + return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 } static Sym* decodetype_mapvalue(Sym *s) { - return decode_reloc(s, 6*PtrSize + 8)->sym; // 0x20 / 0x38 + return decode_reloc_sym(s, 6*PtrSize + 8); // 0x20 / 0x38 } // Type.ChanType.elem static Sym* decodetype_chanelem(Sym *s) { - return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30 + return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30 } // Type.FuncType.dotdotdot @@ -913,7 +910,9 @@ decodetype_funcintype(Sym *s, int i) Reloc *r; r = decode_reloc(s, 6*PtrSize + 8); - return decode_reloc(r->sym, r->add + i * PtrSize)->sym; + if (r == nil) + return nil; + return decode_reloc_sym(r->sym, r->add + i * PtrSize); } static Sym* @@ -922,7 +921,9 @@ decodetype_funcouttype(Sym *s, int i) Reloc *r; r = decode_reloc(s, 7*PtrSize + 16); - return decode_reloc(r->sym, r->add + i * PtrSize)->sym; + if (r == nil) + return nil; + return decode_reloc_sym(r->sym, r->add + i * PtrSize); } // Type.StructType.fields.Slice::len @@ -936,21 +937,20 @@ decodetype_structfieldcount(Sym *s) static char* decodetype_structfieldname(Sym *s, int i) { - Reloc* r; - - r = decode_reloc(s, 6*PtrSize + 0x10 + i*5*PtrSize); // go.string."foo" 0x28 / 0x40 - if (r == nil) // embedded structs have a nil name. + // go.string."foo" 0x28 / 0x40 + s = decode_reloc_sym(s, 6*PtrSize + 0x10 + i*5*PtrSize); + if (s == nil) // embedded structs have a nil name. return nil; - r = decode_reloc(r->sym, 0); // string."foo" - if (r == nil) // shouldn't happen. + s = decode_reloc_sym(s, 0); // string."foo" + if (s == nil) // shouldn't happen. return nil; - return (char*)r->sym->p; // the c-string + return (char*)s->p; // the c-string } static Sym* decodetype_structfieldtype(Sym *s, int i) { - return decode_reloc(s, 8*PtrSize + 0x10 + i*5*PtrSize)->sym; // 0x30 / 0x50 + return decode_reloc_sym(s, 8*PtrSize + 0x10 + i*5*PtrSize); // 0x30 / 0x50 } static vlong @@ -977,6 +977,20 @@ enum { static DWDie* defptrto(DWDie *dwtype); // below +// Lookup predefined types +static Sym* +lookup_or_diag(char *n) +{ + Sym *s; + + s = lookup(n, 0); + if (s->size == 0) { + diag("dwarf: missing type: %s", n); + errorexit(); + } + return s; +} + // Define gotype, for composite ones recurse into constituents. static DWDie* defgotype(Sym *gotype) @@ -995,7 +1009,7 @@ defgotype(Sym *gotype) diag("Type name doesn't start with \".type\": %s", gotype->name); return find_or_diag(&dwtypes, "<unspecified>"); } - name = gotype->name + 5; // Altenatively decode from Type.string + name = gotype->name + 5; // could also decode from Type.string die = find(&dwtypes, name); if (die != nil) @@ -1049,7 +1063,6 @@ defgotype(Sym *gotype) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); break; - case KindFloat: case KindFloat32: case KindFloat64: die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); @@ -1057,7 +1070,6 @@ defgotype(Sym *gotype) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); break; - case KindComplex: case KindComplex64: case KindComplex128: die = newdie(&dwtypes, DW_ABRV_BASETYPE, name); @@ -1107,9 +1119,9 @@ defgotype(Sym *gotype) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0); nfields = decodetype_ifacemethodcount(gotype); if (nfields == 0) - s = lookup("type.runtime.eface", 0); + s = lookup_or_diag("type.runtime.eface"); else - s = lookup("type.runtime.iface", 0); + s = lookup_or_diag("type.runtime.iface"); newrefattr(die, DW_AT_type, defgotype(s)); break; @@ -1226,7 +1238,7 @@ synthesizestringtypes(DWDie* die) { DWDie *prototype; - prototype = defgotype(lookup("type.runtime.string_", 0)); + prototype = defgotype(lookup_or_diag("type.runtime._string")); if (prototype == nil) return; @@ -1242,7 +1254,7 @@ synthesizeslicetypes(DWDie *die) { DWDie *prototype, *elem; - prototype = defgotype(lookup("type.runtime.slice",0)); + prototype = defgotype(lookup_or_diag("type.runtime.slice")); if (prototype == nil) return; @@ -1281,22 +1293,22 @@ synthesizemaptypes(DWDie *die) { DWDie *hash, *hash_subtable, *hash_entry, - *dwh, *dwhs, *dwhe, *keytype, *valtype, *fld; + *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld; int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo; DWAttr *a; - hash = defgotype(lookup("type.runtime.hash",0)); - hash_subtable = defgotype(lookup("type.runtime.hash_subtable",0)); - hash_entry = defgotype(lookup("type.runtime.hash_entry",0)); + hash = defgotype(lookup_or_diag("type.runtime.hmap")); + hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable")); + hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry")); if (hash == nil || hash_subtable == nil || hash_entry == nil) return; - dwh = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data; - if (dwh == nil) + dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data; + if (dwhash == nil) return; - hashsize = getattr(dwh, DW_AT_byte_size)->value; + hashsize = getattr(dwhash, DW_AT_byte_size)->value; for (; die != nil; die = die->link) { if (die->abbrev != DW_ABRV_MAPTYPE) @@ -1328,13 +1340,19 @@ synthesizemaptypes(DWDie *die) mkinternaltypename("hash_entry", getattr(keytype, DW_AT_name)->data, getattr(valtype, DW_AT_name)->data)); - copychildren(dwhe, hash_entry); - substitutetype(dwhe, "key", keytype); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash"); + newrefattr(fld, DW_AT_type, dwhash); + newmemberoffsetattr(fld, 0); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key"); + newrefattr(fld, DW_AT_type, keytype); + newmemberoffsetattr(fld, hashsize); + + fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val"); if (valsize > MaxValsize) valtype = defptrto(valtype); - substitutetype(dwhe, "val", valtype); - fld = find_or_diag(dwhe, "val"); - delattr(fld, DW_AT_data_member_location); + newrefattr(fld, DW_AT_type, valtype); newmemberoffsetattr(fld, hashsize + datavo); newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL); @@ -1371,10 +1389,10 @@ synthesizechantypes(DWDie *die) DWAttr *a; int elemsize, linksize, sudogsize; - sudog = defgotype(lookup("type.runtime.sudoG",0)); - waitq = defgotype(lookup("type.runtime.waitQ",0)); - link = defgotype(lookup("type.runtime.link",0)); - hchan = defgotype(lookup("type.runtime.hChan",0)); + sudog = defgotype(lookup_or_diag("type.runtime.sudog")); + waitq = defgotype(lookup_or_diag("type.runtime.waitq")); + link = defgotype(lookup_or_diag("type.runtime.link")); + hchan = defgotype(lookup_or_diag("type.runtime.hchan")); if (sudog == nil || waitq == nil || link == nil || hchan == nil) return; @@ -2281,6 +2299,13 @@ writegdbscript(void) return sectionstart; } +static void +align(vlong size) +{ + if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Only Windows PE need section align. + strnput("", rnd(size, PEFILEALIGN) - size); +} + /* * This is the main entry point for generating dwarf. After emitting * the mandatory debug_abbrev section, it calls writelines() to set up @@ -2313,15 +2338,18 @@ dwarfemitdebugsections(void) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0); // Needed by the prettyprinter code for interface inspection. - defgotype(lookup("type.runtime.commonType",0)); - defgotype(lookup("type.runtime.InterfaceType",0)); - defgotype(lookup("type.runtime.itab",0)); + defgotype(lookup_or_diag("type.runtime.commonType")); + defgotype(lookup_or_diag("type.runtime.InterfaceType")); + defgotype(lookup_or_diag("type.runtime.itab")); genasmsym(defdwsymb); writeabbrev(); + align(abbrevsize); writelines(); + align(linesize); writeframes(); + align(framesize); synthesizestringtypes(dwtypes.child); synthesizeslicetypes(dwtypes.child); @@ -2354,16 +2382,23 @@ dwarfemitdebugsections(void) } } infosize = infoe - infoo; + align(infosize); pubnameso = writepub(ispubname); + pubnamessize = cpos() - pubnameso; + align(pubnamessize); + pubtypeso = writepub(ispubtype); + pubtypessize = cpos() - pubtypeso; + align(pubtypessize); + arangeso = writearanges(); - gdbscripto = writegdbscript(); + arangessize = cpos() - arangeso; + align(arangessize); - pubnamessize = pubtypeso - pubnameso; - pubtypessize = arangeso - pubtypeso; - arangessize = gdbscripto - arangeso; + gdbscripto = writegdbscript(); gdbscriptsize = cpos() - gdbscripto; + align(gdbscriptsize); } /* @@ -2545,3 +2580,24 @@ dwarfaddmachoheaders(void) ms->filesize += msect->size; } } + +/* + * Windows PE + */ +void +dwarfaddpeheaders(void) +{ + dwarfemitdebugsections(); + newPEDWARFSection(".debug_abbrev", abbrevsize); + newPEDWARFSection(".debug_line", linesize); + newPEDWARFSection(".debug_frame", framesize); + newPEDWARFSection(".debug_info", infosize); + if (pubnamessize > 0) + newPEDWARFSection(".debug_pubnames", pubnamessize); + if (pubtypessize > 0) + newPEDWARFSection(".debug_pubtypes", pubtypessize); + if (arangessize > 0) + newPEDWARFSection(".debug_aranges", arangessize); + if (gdbscriptsize > 0) + newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize); +} diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h index 7881213c2..f0df2f9b1 100644 --- a/src/cmd/ld/dwarf.h +++ b/src/cmd/ld/dwarf.h @@ -27,3 +27,4 @@ void dwarfaddshstrings(Sym *shstrtab); */ void dwarfaddelfheaders(void); void dwarfaddmachoheaders(void); +void dwarfaddpeheaders(void); diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c new file mode 100644 index 000000000..d8b0a6fc2 --- /dev/null +++ b/src/cmd/ld/ldpe.c @@ -0,0 +1,406 @@ +// Copyright 2010 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. + +#include "l.h" +#include "lib.h" +#include "../ld/pe.h" + +#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000 + +#define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_ABSOLUTE (-1) +#define IMAGE_SYM_DEBUG (-2) +#define IMAGE_SYM_TYPE_NULL 0 +#define IMAGE_SYM_TYPE_VOID 1 +#define IMAGE_SYM_TYPE_CHAR 2 +#define IMAGE_SYM_TYPE_SHORT 3 +#define IMAGE_SYM_TYPE_INT 4 +#define IMAGE_SYM_TYPE_LONG 5 +#define IMAGE_SYM_TYPE_FLOAT 6 +#define IMAGE_SYM_TYPE_DOUBLE 7 +#define IMAGE_SYM_TYPE_STRUCT 8 +#define IMAGE_SYM_TYPE_UNION 9 +#define IMAGE_SYM_TYPE_ENUM 10 +#define IMAGE_SYM_TYPE_MOE 11 +#define IMAGE_SYM_TYPE_BYTE 12 +#define IMAGE_SYM_TYPE_WORD 13 +#define IMAGE_SYM_TYPE_UINT 14 +#define IMAGE_SYM_TYPE_DWORD 15 +#define IMAGE_SYM_TYPE_PCODE 32768 +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 0x10 +#define IMAGE_SYM_DTYPE_FUNCTION 0x20 +#define IMAGE_SYM_DTYPE_ARRAY 0x30 +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1) +#define IMAGE_SYM_CLASS_NULL 0 +#define IMAGE_SYM_CLASS_AUTOMATIC 1 +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_REGISTER 4 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8 +#define IMAGE_SYM_CLASS_ARGUMENT 9 +#define IMAGE_SYM_CLASS_STRUCT_TAG 10 +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11 +#define IMAGE_SYM_CLASS_UNION_TAG 12 +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13 +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14 +#define IMAGE_SYM_CLASS_ENUM_TAG 15 +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 17 +#define IMAGE_SYM_CLASS_BIT_FIELD 18 +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */ +#define IMAGE_SYM_CLASS_BLOCK 100 +#define IMAGE_SYM_CLASS_FUNCTION 101 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 102 +#define IMAGE_SYM_CLASS_FILE 103 +#define IMAGE_SYM_CLASS_SECTION 104 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105 +#define IMAGE_SYM_CLASS_CLR_TOKEN 107 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_SEG12 0x0009 +#define IMAGE_REL_I386_SECTION 0x000A +#define IMAGE_REL_I386_SECREL 0x000B +#define IMAGE_REL_I386_TOKEN 0x000C +#define IMAGE_REL_I386_SECREL7 0x000D +#define IMAGE_REL_I386_REL32 0x0014 + +typedef struct PeSym PeSym; +typedef struct PeSect PeSect; +typedef struct PeObj PeObj; + +struct PeSym { + char* name; + uint32 value; + uint16 sectnum; + uint16 type; + uint8 sclass; + uint8 aux; + Sym* sym; +}; + +struct PeSect { + char* name; + uchar* base; + uint64 size; + Sym* sym; + IMAGE_SECTION_HEADER sh; +}; + +struct PeObj { + Biobuf *f; + char *name; + uint32 base; + + PeSect *sect; + uint nsect; + PeSym *pesym; + uint npesym; + + IMAGE_FILE_HEADER fh; + char* snames; +}; + +static int map(PeObj *obj, PeSect *sect); +static int readsym(PeObj *obj, int i, PeSym **sym); + +void +ldpe(Biobuf *f, char *pkg, int64 len, char *pn) +{ + char *name; + int32 base; + int i, j, l, numaux; + PeObj *obj; + PeSect *sect, *rsect; + IMAGE_SECTION_HEADER sh; + uchar symbuf[18]; + Sym *s; + Reloc *r, *rp; + PeSym *sym; + + if(debug['v']) + Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); + + version++; + base = Boffset(f); + + obj = mal(sizeof *obj); + obj->f = f; + obj->base = base; + obj->name = pn; + // read header + if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) + goto bad; + // load section list + obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); + obj->nsect = obj->fh.NumberOfSections; + for(i=0; i < obj->fh.NumberOfSections; i++) { + if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) + goto bad; + obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; + obj->sect[i].name = (char*)obj->sect[i].sh.Name; + // TODO return error if found .cormeta .rsrc + } + // load string table + Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); + if(Bread(f, &l, sizeof l) != sizeof l) + goto bad; + obj->snames = mal(l); + Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); + if(Bread(f, obj->snames, l) != l) + goto bad; + // read symbols + obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); + obj->npesym = obj->fh.NumberOfSymbols; + Bseek(f, base+obj->fh.PointerToSymbolTable, 0); + for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { + Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); + if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) + goto bad; + + if((symbuf[0] == 0) && (symbuf[1] == 0) && + (symbuf[2] == 0) && (symbuf[3] == 0)) { + l = le32(&symbuf[4]); + obj->pesym[i].name = (char*)&obj->snames[l]; + } else { // sym name length <= 8 + obj->pesym[i].name = mal(9); + strncpy(obj->pesym[i].name, (char*)symbuf, 8); + obj->pesym[i].name[8] = 0; + } + obj->pesym[i].value = le32(&symbuf[8]); + obj->pesym[i].sectnum = le16(&symbuf[12]); + obj->pesym[i].sclass = symbuf[16]; + obj->pesym[i].aux = symbuf[17]; + obj->pesym[i].type = le16(&symbuf[14]); + numaux = obj->pesym[i].aux; + if (numaux < 0) + numaux = 0; + } + // create symbols for mapped sections + for(i=0; i<obj->nsect; i++) { + sect = &obj->sect[i]; + if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) + continue; + if(map(obj, sect) < 0) + goto bad; + + name = smprint("%s(%s)", pn, sect->name); + s = lookup(name, version); + free(name); + switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| + IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { + case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata + s->type = SRODATA; + break; + case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss + case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data + s->type = SDATA; + break; + case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text + s->type = STEXT; + break; + default: + werrstr("unexpected flags for PE section %s", sect->name); + goto bad; + } + s->p = sect->base; + s->np = sect->size; + s->size = sect->size; + if(s->type == STEXT) { + if(etextp) + etextp->next = s; + else + textp = s; + etextp = s; + } + sect->sym = s; + } + + // load relocations + for(i=0; i<obj->nsect; i++) { + rsect = &obj->sect[i]; + if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) + continue; + if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) + continue; + r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); + Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); + for(j=0; j<rsect->sh.NumberOfRelocations; j++) { + rp = &r[j]; + if(Bread(f, symbuf, 10) != 10) + goto bad; + + uint32 rva, symindex; + uint16 type; + rva = le32(&symbuf[0]); + symindex = le32(&symbuf[4]); + type = le16(&symbuf[8]); + if(readsym(obj, symindex, &sym) < 0) + goto bad; + if(sym->sym == nil) { + werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); + goto bad; + } + rp->sym = sym->sym; + rp->siz = 4; + rp->off = rva; + switch(type) { + default: + diag("%s: unknown relocation type %d;", pn, type); + case IMAGE_REL_I386_REL32: + rp->type = D_PCREL; + rp->add = 0; + break; + case IMAGE_REL_I386_DIR32: + rp->type = D_ADDR; + // load addend from image + rp->add = le32(rsect->base+rp->off); + break; + } + } + qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); + + s = rsect->sym; + s->r = r; + s->nr = rsect->sh.NumberOfRelocations; + } + + // enter sub-symbols into symbol table. + // frist 2 entry is file name. + for(i=2; i<obj->npesym; i++) { + if(obj->pesym[i].name == 0) + continue; + if(obj->pesym[i].name[0] == '.') //skip section + continue; + if(obj->pesym[i].sectnum > 0) { + sect = &obj->sect[obj->pesym[i].sectnum-1]; + if(sect->sym == 0) + continue; + } + if(readsym(obj, i, &sym) < 0) + goto bad; + + s = sym->sym; + if(sym->sectnum == 0) {// extern + if(s->type == SDYNIMPORT) + s->plt = -2; // flag for dynimport in PE object files. + continue; + } else if (sym->sectnum > 0) { + sect = &obj->sect[sym->sectnum-1]; + if(sect->sym == 0) + diag("%s: %s sym == 0!", pn, s->name); + } else { + diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum); + } + + s->sub = sect->sym->sub; + sect->sym->sub = s; + s->type = sect->sym->type | SSUB; + s->value = sym->value; + s->size = 4; + s->outer = sect->sym; + if(sect->sym->type == STEXT) { + Prog *p; + + if(s->text != P) + diag("%s: duplicate definition of %s", pn, s->name); + // build a TEXT instruction with a unique pc + // just to make the rest of the linker happy. + p = prg(); + p->as = ATEXT; + p->from.type = D_EXTERN; + p->from.sym = s; + p->textflag = 7; + p->to.type = D_CONST; + p->link = nil; + p->pc = pc++; + s->text = p; + + etextp->next = s; + etextp = s; + } + } + + return; +bad: + diag("%s: malformed pe file: %r", pn); +} + +static int +map(PeObj *obj, PeSect *sect) +{ + if(sect->base != nil) + return 0; + + sect->base = mal(sect->sh.SizeOfRawData); + werrstr("short read"); + if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || + Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData) + return -1; + + return 0; +} + +static int +readsym(PeObj *obj, int i, PeSym **y) +{ + Sym *s; + PeSym *sym; + char *name, *p; + + if(i >= obj->npesym || i < 0) { + werrstr("invalid pe symbol index"); + return -1; + } + + sym = &obj->pesym[i]; + *y = sym; + s = nil; + + name = sym->name; + if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section + name = obj->sect[sym->sectnum-1].sym->name; + if(strncmp(sym->name, "__imp__", 6) == 0) + name = &sym->name[7]; // __imp__Name => Name + else if(sym->name[0] == '_') + name = &sym->name[1]; // _Name => Name + // remove last @XXX + p = strchr(name, '@'); + if(p) + *p = 0; + + switch(sym->type) { + default: + werrstr("%s: invalid symbol type %d", sym->name, sym->type); + return -1; + case IMAGE_SYM_DTYPE_FUNCTION: + case IMAGE_SYM_DTYPE_NULL: + switch(sym->sclass) { + case IMAGE_SYM_CLASS_EXTERNAL: //global + s = lookup(name, 0); + break; + case IMAGE_SYM_CLASS_NULL: + case IMAGE_SYM_CLASS_STATIC: + s = lookup(name, version); + break; + default: + werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass); + return -1; + } + break; + } + + if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0)) + s->type = SXREF; + sym->sym = s; + + return 0; +} diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index ae77247c3..b1a62f25e 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -406,6 +406,10 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence) ldmacho(f, pkg, len, pn); return; } + if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { + ldpe(f, pkg, len, pn); + return; + } /* check the header */ line = Brdline(f, '\n'); diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index bcf297116..4ac5d37f9 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -130,6 +130,7 @@ void ldobj1(Biobuf *f, char*, int64 len, char *pn); void ldobj(Biobuf*, char*, int64, char*, int); void ldelf(Biobuf*, char*, int64, char*); void ldmacho(Biobuf*, char*, int64, char*); +void ldpe(Biobuf*, char*, int64, char*); void ldpkg(Biobuf*, char*, int64, char*, int); void mark(Sym *s); void mkfwd(void); diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 82c6941f2..2c34daab4 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -10,6 +10,7 @@ #include "l.h" #include "../ld/lib.h" #include "../ld/pe.h" +#include "../ld/dwarf.h" // DOS stub that prints out // "This program cannot be run in DOS mode." @@ -33,6 +34,9 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static char symnames[256]; +static int nextsymoff; + int32 PESECTHEADR; int32 PEFILEHEADR; @@ -43,26 +47,33 @@ static int nextfileoff; static IMAGE_FILE_HEADER fh; static IMAGE_OPTIONAL_HEADER oh; +static PE64_IMAGE_OPTIONAL_HEADER oh64; static IMAGE_SECTION_HEADER sh[16]; +static IMAGE_DATA_DIRECTORY* dd; + +#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v)) +#define put(v) (pe64 ? vputl(v) : lputl(v)) typedef struct Imp Imp; struct Imp { Sym* s; - long va; - long vb; + uvlong off; Imp* next; }; typedef struct Dll Dll; struct Dll { char* name; - int count; + uvlong nameoff; + uvlong thunkoff; Imp* ms; Dll* next; }; static Dll* dr; -static int ndll, nimp, nsize; + +static Sym *dexport[1024]; +static int nexport; static IMAGE_SECTION_HEADER* addpesection(char *name, int sectsize, int filesize, Segment *s) @@ -99,17 +110,23 @@ addpesection(char *name, int sectsize, int filesize, Segment *s) void peinit(void) { + int32 l; + switch(thechar) { // 64-bit architectures case '6': pe64 = 1; + l = sizeof(oh64); + dd = oh64.DataDirectory; break; // 32-bit architectures default: + l = sizeof(oh); + dd = oh.DataDirectory; break; } - - PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN); + + PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN); PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN); nextsectoff = PESECTHEADR; nextfileoff = PEFILEHEADR; @@ -118,27 +135,34 @@ peinit(void) static void pewrite(void) { - int i, j; - seek(cout, 0, 0); ewrite(cout, dosstub, sizeof dosstub); strnput("PE", 4); - - for (i=0; i<sizeof(fh); i++) - cput(((char*)&fh)[i]); - for (i=0; i<sizeof(oh); i++) - cput(((char*)&oh)[i]); - for (i=0; i<nsect; i++) - for (j=0; j<sizeof(sh[i]); j++) - cput(((char*)&sh[i])[j]); + cflush(); + // TODO: This code should not assume that the + // memory representation is little-endian or + // that the structs are packed identically to + // their file representation. + ewrite(cout, &fh, sizeof fh); + if(pe64) + ewrite(cout, &oh64, sizeof oh64); + else + ewrite(cout, &oh, sizeof oh); + ewrite(cout, &sh, nsect * sizeof sh[0]); } static void strput(char *s) { - while(*s) + int n; + + for(n=0; *s; n++) cput(*s++); cput('\0'); + n++; + // string must be padded to even size + if(n%2) + cput('\0'); } static Dll* @@ -146,50 +170,33 @@ initdynimport(void) { Imp *m; Dll *d; - Sym *s; + Sym *s, *dynamic; int i; - Sym *dynamic; dr = nil; - ndll = 0; - nimp = 0; - nsize = 0; for(i=0; i<NHASH; i++) for(s = hash[i]; s != S; s = s->hash) { - if(!s->reachable || !s->dynimpname) + if(!s->reachable || !s->dynimpname || s->dynexport) continue; - nimp++; for(d = dr; d != nil; d = d->next) { if(strcmp(d->name,s->dynimplib) == 0) { m = mal(sizeof *m); - m->s = s; - m->next = d->ms; - d->ms = m; - d->count++; - nsize += strlen(s->dynimpname)+2+1; break; } } if(d == nil) { d = mal(sizeof *d); d->name = s->dynimplib; - d->count = 1; d->next = dr; dr = d; m = mal(sizeof *m); - m->s = s; - m->next = 0; - d->ms = m; - ndll++; - nsize += strlen(s->dynimpname)+2+1; - nsize += strlen(s->dynimplib)+1; } + m->s = s; + m->next = d->ms; + d->ms = m; } - nsize += 20*ndll + 20; - nsize += 4*nimp + 4*ndll; - dynamic = lookup(".windynamic", 0); dynamic->reachable = 1; dynamic->type = SWINDOWS; @@ -199,9 +206,9 @@ initdynimport(void) m->s->sub = dynamic->sub; dynamic->sub = m->s; m->s->value = dynamic->size; - dynamic->size += 4; + dynamic->size += PtrSize; } - dynamic->size += 4; + dynamic->size += PtrSize; } return dr; @@ -211,90 +218,245 @@ static void addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect) { IMAGE_SECTION_HEADER *isect; - uint32 va; - int noff, aoff, o, last_fn, last_name_off, iat_off; + uvlong n, oftbase, ftbase; Imp *m; Dll *d; Sym* dynamic; - isect = addpesection(".idata", nsize, nsize, 0); + dynamic = lookup(".windynamic", 0); + + // skip import descriptor table (will write it later) + n = 0; + for(d = dr; d != nil; d = d->next) + n++; + seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0); + + // write dll names + for(d = dr; d != nil; d = d->next) { + d->nameoff = cpos() - fileoff; + strput(d->name); + } + + // write function names + for(d = dr; d != nil; d = d->next) { + for(m = d->ms; m != nil; m = m->next) { + m->off = nextsectoff + cpos() - fileoff; + wputl(0); // hint + strput(m->s->dynimpname); + } + } + + // write OriginalFirstThunks + oftbase = cpos() - fileoff; + n = cpos(); + for(d = dr; d != nil; d = d->next) { + d->thunkoff = cpos() - n; + for(m = d->ms; m != nil; m = m->next) + put(m->off); + put(0); + } + + // add pe section and pad it at the end + n = cpos() - fileoff; + isect = addpesection(".idata", n, n, 0); isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; - va = isect->VirtualAddress; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; + strnput("", isect->SizeOfRawData - n); + cflush(); + // write FirstThunks (allocated in .data section) + ftbase = dynamic->value - datsect->VirtualAddress - PEBASE; + seek(cout, datsect->PointerToRawData + ftbase, 0); + for(d = dr; d != nil; d = d->next) { + for(m = d->ms; m != nil; m = m->next) + put(m->off); + put(0); + } + cflush(); + + // finally write import descriptor table seek(cout, fileoff, 0); - - dynamic = lookup(".windynamic", 0); - iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off; - oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; - - noff = va + 20*ndll + 20; - aoff = noff + 4*nimp + 4*ndll; - last_fn = 0; - last_name_off = aoff; for(d = dr; d != nil; d = d->next) { - lputl(noff); + lputl(isect->VirtualAddress + oftbase + d->thunkoff); lputl(0); lputl(0); - lputl(last_name_off); - lputl(iat_off); - last_fn = d->count; - noff += 4*last_fn + 4; - aoff += 4*last_fn + 4; - iat_off += 4*last_fn + 4; - last_name_off += strlen(d->name)+1; + lputl(isect->VirtualAddress + d->nameoff); + lputl(datsect->VirtualAddress + ftbase + d->thunkoff); } lputl(0); //end lputl(0); lputl(0); lputl(0); lputl(0); + cflush(); - // put OriginalFirstThunk - o = last_name_off; - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - lputl(o); - o += 2 + strlen(m->s->dynimpname) + 1; - } - lputl(0); - } - // put names - for(d = dr; d != nil; d = d->next) { - strput(d->name); - } - // put hint+name - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - wputl(0); - strput(m->s->dynimpname); + // update data directory + dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize; + dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE; + dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size; + + seek(cout, 0, 2); +} + +static int +scmp(const void *p1, const void *p2) +{ + Sym *s1, *s2; + + s1 = *(Sym**)p1; + s2 = *(Sym**)p2; + return strcmp(s1->dynimpname, s2->dynimpname); +} + +static void +initdynexport(void) +{ + int i; + Sym *s; + + nexport = 0; + for(i=0; i<NHASH; i++) + for(s = hash[i]; s != S; s = s->hash) { + if(!s->reachable || !s->dynimpname || !s->dynexport) + continue; + if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) { + diag("pe dynexport table is full"); + errorexit(); } + + dexport[nexport] = s; + nexport++; } - strnput("", isect->SizeOfRawData - nsize); - cflush(); + qsort(dexport, nexport, sizeof dexport[0], scmp); +} - // put FirstThunk - o = last_name_off; - seek(cout, datsect->PointerToRawData + dynamic->value - PEBASE - datsect->VirtualAddress, 0); - for(d = dr; d != nil; d = d->next) { - for(m = d->ms; m != nil; m = m->next) { - lputl(o); - o += 2 + strlen(m->s->dynimpname) + 1; - } - lputl(0); +void +addexports(vlong fileoff) +{ + IMAGE_SECTION_HEADER *sect; + IMAGE_EXPORT_DIRECTORY e; + int size, i, va, va_name, va_addr, va_na, v; + + size = sizeof e + 10*nexport + strlen(outfile) + 1; + for(i=0; i<nexport; i++) + size += strlen(dexport[i]->dynimpname) + 1; + + if (nexport == 0) + return; + + sect = addpesection(".edata", size, size, 0); + sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ; + va = sect->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va; + dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize; + + seek(cout, fileoff, 0); + va_name = va + sizeof e + nexport*4; + va_addr = va + sizeof e; + va_na = va + sizeof e + nexport*8; + + e.Characteristics = 0; + e.MajorVersion = 0; + e.MinorVersion = 0; + e.NumberOfFunctions = nexport; + e.NumberOfNames = nexport; + e.Name = va + sizeof e + nexport*10; // Program names. + e.Base = 1; + e.AddressOfFunctions = va_addr; + e.AddressOfNames = va_name; + e.AddressOfNameOrdinals = va_na; + // put IMAGE_EXPORT_DIRECTORY + for (i=0; i<sizeof(e); i++) + cput(((char*)&e)[i]); + // put EXPORT Address Table + for(i=0; i<nexport; i++) + lputl(dexport[i]->value - PEBASE); + // put EXPORT Name Pointer Table + v = e.Name + strlen(outfile)+1; + for(i=0; i<nexport; i++) { + lputl(v); + v += strlen(dexport[i]->dynimpname)+1; } + // put EXPORT Ordinal Table + for(i=0; i<nexport; i++) + wputl(i); + // put Names + strnput(outfile, strlen(outfile)+1); + for(i=0; i<nexport; i++) + strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1); + strnput("", sect->SizeOfRawData - size); cflush(); + seek(cout, 0, 2); } void dope(void) { + Sym *rel; + + /* relocation table */ + rel = lookup(".rel", 0); + rel->reachable = 1; + rel->type = SELFDATA; + initdynimport(); + initdynexport(); +} + +/* + * For more than 8 characters section names, name contains a slash (/) that is + * followed by an ASCII representation of a decimal number that is an offset into + * the string table. + * reference: pecoff_v8.docx Page 24. + * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx> + */ +IMAGE_SECTION_HEADER* +newPEDWARFSection(char *name, vlong size) +{ + IMAGE_SECTION_HEADER *h; + char s[8]; + + if(nextsymoff+strlen(name)+1 > sizeof(symnames)) { + diag("pe string table is full"); + errorexit(); + } + + strcpy(&symnames[nextsymoff], name); + sprint(s, "/%d\0", nextsymoff+4); + nextsymoff += strlen(name); + symnames[nextsymoff] = 0; + nextsymoff ++; + h = addpesection(s, size, size, 0); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_DISCARDABLE; + + return h; +} + +static void +addsymtable(void) +{ + IMAGE_SECTION_HEADER *h; + int i, size; + + if(nextsymoff == 0) + return; + + size = nextsymoff + 4; + h = addpesection(".symtab", size, size, 0); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_DISCARDABLE; + fh.PointerToSymbolTable = cpos(); + fh.NumberOfSymbols = 0; + // put symbol string table + lputl(size); + for (i=0; i<nextsymoff; i++) + cput(symnames[i]); + strnput("", h->SizeOfRawData - size); + cflush(); } void @@ -324,42 +486,51 @@ asmbpe(void) IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE; addimports(nextfileoff, d); + + addexports(nextfileoff); + + if(!debug['s']) + dwarfaddpeheaders(); + addsymtable(); + fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); - fh.SizeOfOptionalHeader = sizeof(oh); fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED; - if(thechar == '8') + if (pe64) { + fh.SizeOfOptionalHeader = sizeof(oh64); + set(Magic, 0x20b); // PE32+ + } else { + fh.SizeOfOptionalHeader = sizeof(oh); fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE; - - oh.Magic = 0x10b; // PE32 - oh.MajorLinkerVersion = 1; - oh.MinorLinkerVersion = 0; - oh.SizeOfCode = t->SizeOfRawData; - oh.SizeOfInitializedData = d->SizeOfRawData; - oh.SizeOfUninitializedData = 0; - oh.AddressOfEntryPoint = entryvalue()-PEBASE; - oh.BaseOfCode = t->VirtualAddress; - oh.BaseOfData = d->VirtualAddress; - - oh.ImageBase = PEBASE; - oh.SectionAlignment = PESECTALIGN; - oh.FileAlignment = PEFILEALIGN; - oh.MajorOperatingSystemVersion = 4; - oh.MinorOperatingSystemVersion = 0; - oh.MajorImageVersion = 1; - oh.MinorImageVersion = 0; - oh.MajorSubsystemVersion = 4; - oh.MinorSubsystemVersion = 0; - oh.SizeOfImage = nextsectoff; - oh.SizeOfHeaders = PEFILEHEADR; - oh.Subsystem = 3; // WINDOWS_CUI - oh.SizeOfStackReserve = 0x00200000; - oh.SizeOfStackCommit = 0x00001000; - oh.SizeOfHeapReserve = 0x00100000; - oh.SizeOfHeapCommit = 0x00001000; - oh.NumberOfRvaAndSizes = 16; + set(Magic, 0x10b); // PE32 + oh.BaseOfData = d->VirtualAddress; + } + set(MajorLinkerVersion, 1); + set(MinorLinkerVersion, 0); + set(SizeOfCode, t->SizeOfRawData); + set(SizeOfInitializedData, d->SizeOfRawData); + set(SizeOfUninitializedData, 0); + set(AddressOfEntryPoint, entryvalue()-PEBASE); + set(BaseOfCode, t->VirtualAddress); + set(ImageBase, PEBASE); + set(SectionAlignment, PESECTALIGN); + set(FileAlignment, PEFILEALIGN); + set(MajorOperatingSystemVersion, 4); + set(MinorOperatingSystemVersion, 0); + set(MajorImageVersion, 1); + set(MinorImageVersion, 0); + set(MajorSubsystemVersion, 4); + set(MinorSubsystemVersion, 0); + set(SizeOfImage, nextsectoff); + set(SizeOfHeaders, PEFILEHEADR); + set(Subsystem, 3); // WINDOWS_CUI + set(SizeOfStackReserve, 0x00200000); + set(SizeOfStackCommit, 0x00001000); + set(SizeOfHeapReserve, 0x00100000); + set(SizeOfHeapCommit, 0x00001000); + set(NumberOfRvaAndSizes, 16); pewrite(); } diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index f8161cc4a..6dbf6a5be 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -72,6 +72,20 @@ typedef struct { uint32 FirstThunk; } IMAGE_IMPORT_DESCRIPTOR; +typedef struct _IMAGE_EXPORT_DIRECTORY { + uint32 Characteristics; + uint32 TimeDateStamp; + uint16 MajorVersion; + uint16 MinorVersion; + uint32 Name; + uint32 Base; + uint32 NumberOfFunctions; + uint32 NumberOfNames; + uint32 AddressOfFunctions; + uint32 AddressOfNames; + uint32 AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY; + #define PEBASE 0x00400000 // SectionAlignment must be greater than or equal to FileAlignment. // The default is the page size for the architecture. @@ -99,6 +113,7 @@ enum { IMAGE_SCN_MEM_EXECUTE = 0x20000000, IMAGE_SCN_MEM_READ = 0x40000000, IMAGE_SCN_MEM_WRITE = 0x80000000, + IMAGE_SCN_MEM_DISCARDABLE = 0x2000000, IMAGE_DIRECTORY_ENTRY_EXPORT = 0, IMAGE_DIRECTORY_ENTRY_IMPORT = 1, @@ -122,3 +137,38 @@ void peinit(void); void asmbpe(void); void dope(void); +IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size); + +// X64 +typedef struct { + uint16 Magic; + uint8 MajorLinkerVersion; + uint8 MinorLinkerVersion; + uint32 SizeOfCode; + uint32 SizeOfInitializedData; + uint32 SizeOfUninitializedData; + uint32 AddressOfEntryPoint; + uint32 BaseOfCode; + uint64 ImageBase; + uint32 SectionAlignment; + uint32 FileAlignment; + uint16 MajorOperatingSystemVersion; + uint16 MinorOperatingSystemVersion; + uint16 MajorImageVersion; + uint16 MinorImageVersion; + uint16 MajorSubsystemVersion; + uint16 MinorSubsystemVersion; + uint32 Win32VersionValue; + uint32 SizeOfImage; + uint32 SizeOfHeaders; + uint32 CheckSum; + uint16 Subsystem; + uint16 DllCharacteristics; + uint64 SizeOfStackReserve; + uint64 SizeOfStackCommit; + uint64 SizeOfHeapReserve; + uint64 SizeOfHeapCommit; + uint32 LoaderFlags; + uint32 NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; +} PE64_IMAGE_OPTIONAL_HEADER; diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile index bd15f9eab..c3b9ec5d0 100644 --- a/src/lib9/utf/Makefile +++ b/src/lib9/utf/Makefile @@ -14,3 +14,19 @@ OFILES=\ mkrunetype.$O\ include ../../Make.ccmd + +UnicodeData-%.txt: + curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@ + mv _$@ $@ + +runetypebody-%.c: mkrunetype UnicodeData-%.txt + mkrunetype -p UnicodeData-$*.txt >_$@ + mv _$@ $@ + +CLEANFILES+=UnicodeData.txt + +UNICODE_VERSION=6.0.0 + +test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt + mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt + diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c index 848056451..06d52b572 100644 --- a/src/lib9/utf/mkrunetype.c +++ b/src/lib9/utf/mkrunetype.c @@ -93,8 +93,9 @@ usage(void) exit(1); } -int -main(int argc, char *argv[]){ +void +main(int argc, char *argv[]) +{ FILE *in; char buf[MAX_LINE], buf2[MAX_LINE]; char *fields[NFIELDS + 1], *fields2[NFIELDS + 1]; @@ -239,7 +240,7 @@ main(int argc, char *argv[]){ }else{ mktables(argv[0], usepairs); } - return 0; + exit(0); } /* @@ -562,7 +563,8 @@ mkto(const char* label, int* map, int usepairs) // Make only range tables and a function for is<label>rune. static void -mkisronly(const char* label, char* prop) { +mkisronly(const char* label, char* prop) +{ mkisrange(label, prop, 1); printf( "int\n" diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c index 19cf433e5..27867430b 100644 --- a/src/lib9/utf/runetype.c +++ b/src/lib9/utf/runetype.c @@ -35,49 +35,4 @@ rbsearch(Rune c, Rune *t, int n, int ne) return 0; } -/* - * The "ideographic" property is hard to extract from UnicodeData.txt, - * so it is hard coded here. - * - * It is defined in the Unicode PropList.txt file, for example - * PropList-3.0.0.txt. Unlike the UnicodeData.txt file, the format of - * PropList changes between versions. This property appears relatively static; - * it is the same in version 4.0.1, except that version defines some >16 bit - * chars as ideographic as well: 20000..2a6d6, and 2f800..2Fa1d. - */ -static Rune __isideographicr[] = { - 0x3006, 0x3007, /* 0x3006 added in 2.0.14 */ - 0x3021, 0x3029, - 0x3038, 0x303a, /* added in 3.0.0 */ - 0x3400, 0x4db5, /* added in 3.0.0 */ - - /* consecutive */ - 0x4e00, 0x9fa5, - 0x9fa6, 0x9fbb, /* added in 4.1.0 */ - 0x9fbc, 0x9fc3, /* added in 5.1.0 */ - 0x9fc4, 0x9fcb, /* added in 5.2.0 */ - - 0xf900, 0xfa2d, - - /* consecutive */ - 0xfa30, 0xfa6a, /* added in 5.1.0 */ - 0xfa6b, 0xfa6d, /* added in 5.2.0 */ - - 0xfa70, 0xfad9, /* added in 4.1.0 */ - 0x20000, 0x2a6d6, /* added in 3.1.0 */ - 0x2a700, 0x2b734, /* added in 5.2.0 */ - 0x2f800, 0x2fa1d, /* added in 3.1.0 */ -}; - -int -isideographicrune(Rune c) -{ - Rune *p; - - p = rbsearch(c, __isideographicr, nelem(__isideographicr)/2, 2); - if(p && c >= p[0] && c <= p[1]) - return 1; - return 0; -} - -#include "runetypebody-5.2.0.c" +#include "runetypebody-6.0.0.c" diff --git a/src/lib9/utf/runetypebody-6.0.0.c b/src/lib9/utf/runetypebody-6.0.0.c new file mode 100644 index 000000000..47c0faf73 --- /dev/null +++ b/src/lib9/utf/runetypebody-6.0.0.c @@ -0,0 +1,1565 @@ +/* generated automatically by mkrunetype.c from UnicodeData-6.0.0.txt */ + +static Rune __isspacer[] = { + 0x0009, 0x000d, + 0x0020, 0x0020, + 0x0085, 0x0085, + 0x00a0, 0x00a0, + 0x1680, 0x1680, + 0x180e, 0x180e, + 0x2000, 0x200a, + 0x2028, 0x2029, + 0x202f, 0x202f, + 0x205f, 0x205f, + 0x3000, 0x3000, + 0xfeff, 0xfeff, +}; + +int +isspacerune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} + +static Rune __isdigitr[] = { + 0x0030, 0x0039, + 0x0660, 0x0669, + 0x06f0, 0x06f9, + 0x07c0, 0x07c9, + 0x0966, 0x096f, + 0x09e6, 0x09ef, + 0x0a66, 0x0a6f, + 0x0ae6, 0x0aef, + 0x0b66, 0x0b6f, + 0x0be6, 0x0bef, + 0x0c66, 0x0c6f, + 0x0ce6, 0x0cef, + 0x0d66, 0x0d6f, + 0x0e50, 0x0e59, + 0x0ed0, 0x0ed9, + 0x0f20, 0x0f29, + 0x1040, 0x1049, + 0x1090, 0x1099, + 0x17e0, 0x17e9, + 0x1810, 0x1819, + 0x1946, 0x194f, + 0x19d0, 0x19d9, + 0x1a80, 0x1a89, + 0x1a90, 0x1a99, + 0x1b50, 0x1b59, + 0x1bb0, 0x1bb9, + 0x1c40, 0x1c49, + 0x1c50, 0x1c59, + 0xa620, 0xa629, + 0xa8d0, 0xa8d9, + 0xa900, 0xa909, + 0xa9d0, 0xa9d9, + 0xaa50, 0xaa59, + 0xabf0, 0xabf9, + 0xff10, 0xff19, + 0x104a0, 0x104a9, + 0x11066, 0x1106f, + 0x1d7ce, 0x1d7ff, +}; + +int +isdigitrune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + return 0; +} + +static Rune __isalphar[] = { + 0x0041, 0x005a, + 0x0061, 0x007a, + 0x00c0, 0x00d6, + 0x00d8, 0x00f6, + 0x00f8, 0x02c1, + 0x02c6, 0x02d1, + 0x02e0, 0x02e4, + 0x0370, 0x0374, + 0x0376, 0x0377, + 0x037a, 0x037d, + 0x0388, 0x038a, + 0x038e, 0x03a1, + 0x03a3, 0x03f5, + 0x03f7, 0x0481, + 0x048a, 0x0527, + 0x0531, 0x0556, + 0x0561, 0x0587, + 0x05d0, 0x05ea, + 0x05f0, 0x05f2, + 0x0620, 0x064a, + 0x066e, 0x066f, + 0x0671, 0x06d3, + 0x06e5, 0x06e6, + 0x06ee, 0x06ef, + 0x06fa, 0x06fc, + 0x0712, 0x072f, + 0x074d, 0x07a5, + 0x07ca, 0x07ea, + 0x07f4, 0x07f5, + 0x0800, 0x0815, + 0x0840, 0x0858, + 0x0904, 0x0939, + 0x0958, 0x0961, + 0x0971, 0x0977, + 0x0979, 0x097f, + 0x0985, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09a8, + 0x09aa, 0x09b0, + 0x09b6, 0x09b9, + 0x09dc, 0x09dd, + 0x09df, 0x09e1, + 0x09f0, 0x09f1, + 0x0a05, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a28, + 0x0a2a, 0x0a30, + 0x0a32, 0x0a33, + 0x0a35, 0x0a36, + 0x0a38, 0x0a39, + 0x0a59, 0x0a5c, + 0x0a72, 0x0a74, + 0x0a85, 0x0a8d, + 0x0a8f, 0x0a91, + 0x0a93, 0x0aa8, + 0x0aaa, 0x0ab0, + 0x0ab2, 0x0ab3, + 0x0ab5, 0x0ab9, + 0x0ae0, 0x0ae1, + 0x0b05, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b28, + 0x0b2a, 0x0b30, + 0x0b32, 0x0b33, + 0x0b35, 0x0b39, + 0x0b5c, 0x0b5d, + 0x0b5f, 0x0b61, + 0x0b85, 0x0b8a, + 0x0b8e, 0x0b90, + 0x0b92, 0x0b95, + 0x0b99, 0x0b9a, + 0x0b9e, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0c05, 0x0c0c, + 0x0c0e, 0x0c10, + 0x0c12, 0x0c28, + 0x0c2a, 0x0c33, + 0x0c35, 0x0c39, + 0x0c58, 0x0c59, + 0x0c60, 0x0c61, + 0x0c85, 0x0c8c, + 0x0c8e, 0x0c90, + 0x0c92, 0x0ca8, + 0x0caa, 0x0cb3, + 0x0cb5, 0x0cb9, + 0x0ce0, 0x0ce1, + 0x0cf1, 0x0cf2, + 0x0d05, 0x0d0c, + 0x0d0e, 0x0d10, + 0x0d12, 0x0d3a, + 0x0d60, 0x0d61, + 0x0d7a, 0x0d7f, + 0x0d85, 0x0d96, + 0x0d9a, 0x0db1, + 0x0db3, 0x0dbb, + 0x0dc0, 0x0dc6, + 0x0e01, 0x0e30, + 0x0e32, 0x0e33, + 0x0e40, 0x0e46, + 0x0e81, 0x0e82, + 0x0e87, 0x0e88, + 0x0e94, 0x0e97, + 0x0e99, 0x0e9f, + 0x0ea1, 0x0ea3, + 0x0eaa, 0x0eab, + 0x0ead, 0x0eb0, + 0x0eb2, 0x0eb3, + 0x0ec0, 0x0ec4, + 0x0edc, 0x0edd, + 0x0f40, 0x0f47, + 0x0f49, 0x0f6c, + 0x0f88, 0x0f8c, + 0x1000, 0x102a, + 0x1050, 0x1055, + 0x105a, 0x105d, + 0x1065, 0x1066, + 0x106e, 0x1070, + 0x1075, 0x1081, + 0x10a0, 0x10c5, + 0x10d0, 0x10fa, + 0x1100, 0x1248, + 0x124a, 0x124d, + 0x1250, 0x1256, + 0x125a, 0x125d, + 0x1260, 0x1288, + 0x128a, 0x128d, + 0x1290, 0x12b0, + 0x12b2, 0x12b5, + 0x12b8, 0x12be, + 0x12c2, 0x12c5, + 0x12c8, 0x12d6, + 0x12d8, 0x1310, + 0x1312, 0x1315, + 0x1318, 0x135a, + 0x1380, 0x138f, + 0x13a0, 0x13f4, + 0x1401, 0x166c, + 0x166f, 0x167f, + 0x1681, 0x169a, + 0x16a0, 0x16ea, + 0x1700, 0x170c, + 0x170e, 0x1711, + 0x1720, 0x1731, + 0x1740, 0x1751, + 0x1760, 0x176c, + 0x176e, 0x1770, + 0x1780, 0x17b3, + 0x1820, 0x1877, + 0x1880, 0x18a8, + 0x18b0, 0x18f5, + 0x1900, 0x191c, + 0x1950, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19c1, 0x19c7, + 0x1a00, 0x1a16, + 0x1a20, 0x1a54, + 0x1b05, 0x1b33, + 0x1b45, 0x1b4b, + 0x1b83, 0x1ba0, + 0x1bae, 0x1baf, + 0x1bc0, 0x1be5, + 0x1c00, 0x1c23, + 0x1c4d, 0x1c4f, + 0x1c5a, 0x1c7d, + 0x1ce9, 0x1cec, + 0x1cee, 0x1cf1, + 0x1d00, 0x1dbf, + 0x1e00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f57, + 0x1f5f, 0x1f7d, + 0x1f80, 0x1fb4, + 0x1fb6, 0x1fbc, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fcc, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fdb, + 0x1fe0, 0x1fec, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ffc, + 0x2090, 0x209c, + 0x210a, 0x2113, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x212f, 0x2139, + 0x213c, 0x213f, + 0x2145, 0x2149, + 0x2183, 0x2184, + 0x2c00, 0x2c2e, + 0x2c30, 0x2c5e, + 0x2c60, 0x2ce4, + 0x2ceb, 0x2cee, + 0x2d00, 0x2d25, + 0x2d30, 0x2d65, + 0x2d80, 0x2d96, + 0x2da0, 0x2da6, + 0x2da8, 0x2dae, + 0x2db0, 0x2db6, + 0x2db8, 0x2dbe, + 0x2dc0, 0x2dc6, + 0x2dc8, 0x2dce, + 0x2dd0, 0x2dd6, + 0x2dd8, 0x2dde, + 0x3005, 0x3006, + 0x3031, 0x3035, + 0x303b, 0x303c, + 0x3041, 0x3096, + 0x309d, 0x309f, + 0x30a1, 0x30fa, + 0x30fc, 0x30ff, + 0x3105, 0x312d, + 0x3131, 0x318e, + 0x31a0, 0x31ba, + 0x31f0, 0x31ff, + 0x3400, 0x4db5, + 0x4e00, 0x9fcb, + 0xa000, 0xa48c, + 0xa4d0, 0xa4fd, + 0xa500, 0xa60c, + 0xa610, 0xa61f, + 0xa62a, 0xa62b, + 0xa640, 0xa66e, + 0xa67f, 0xa697, + 0xa6a0, 0xa6e5, + 0xa717, 0xa71f, + 0xa722, 0xa788, + 0xa78b, 0xa78e, + 0xa790, 0xa791, + 0xa7a0, 0xa7a9, + 0xa7fa, 0xa801, + 0xa803, 0xa805, + 0xa807, 0xa80a, + 0xa80c, 0xa822, + 0xa840, 0xa873, + 0xa882, 0xa8b3, + 0xa8f2, 0xa8f7, + 0xa90a, 0xa925, + 0xa930, 0xa946, + 0xa960, 0xa97c, + 0xa984, 0xa9b2, + 0xaa00, 0xaa28, + 0xaa40, 0xaa42, + 0xaa44, 0xaa4b, + 0xaa60, 0xaa76, + 0xaa80, 0xaaaf, + 0xaab5, 0xaab6, + 0xaab9, 0xaabd, + 0xaadb, 0xaadd, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab26, + 0xab28, 0xab2e, + 0xabc0, 0xabe2, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa2d, + 0xfa30, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1f, 0xfb28, + 0xfb2a, 0xfb36, + 0xfb38, 0xfb3c, + 0xfb40, 0xfb41, + 0xfb43, 0xfb44, + 0xfb46, 0xfbb1, + 0xfbd3, 0xfd3d, + 0xfd50, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdf0, 0xfdfb, + 0xfe70, 0xfe74, + 0xfe76, 0xfefc, + 0xff21, 0xff3a, + 0xff41, 0xff5a, + 0xff66, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0x10000, 0x1000b, + 0x1000d, 0x10026, + 0x10028, 0x1003a, + 0x1003c, 0x1003d, + 0x1003f, 0x1004d, + 0x10050, 0x1005d, + 0x10080, 0x100fa, + 0x10280, 0x1029c, + 0x102a0, 0x102d0, + 0x10300, 0x1031e, + 0x10330, 0x10340, + 0x10342, 0x10349, + 0x10380, 0x1039d, + 0x103a0, 0x103c3, + 0x103c8, 0x103cf, + 0x10400, 0x1049d, + 0x10800, 0x10805, + 0x1080a, 0x10835, + 0x10837, 0x10838, + 0x1083f, 0x10855, + 0x10900, 0x10915, + 0x10920, 0x10939, + 0x10a10, 0x10a13, + 0x10a15, 0x10a17, + 0x10a19, 0x10a33, + 0x10a60, 0x10a7c, + 0x10b00, 0x10b35, + 0x10b40, 0x10b55, + 0x10b60, 0x10b72, + 0x10c00, 0x10c48, + 0x11003, 0x11037, + 0x11083, 0x110af, + 0x12000, 0x1236e, + 0x13000, 0x1342e, + 0x16800, 0x16a38, + 0x1b000, 0x1b001, + 0x1d400, 0x1d454, + 0x1d456, 0x1d49c, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d51e, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d552, 0x1d6a5, + 0x1d6a8, 0x1d6c0, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6fa, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d734, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d76e, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d7a8, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7cb, + 0x20000, 0x2a6d6, + 0x2a700, 0x2b734, + 0x2b740, 0x2b81d, + 0x2f800, 0x2fa1d, +}; + +static Rune __isalphas[] = { + 0x00aa, + 0x00b5, + 0x00ba, + 0x02ec, + 0x02ee, + 0x0386, + 0x038c, + 0x0559, + 0x06d5, + 0x06ff, + 0x0710, + 0x07b1, + 0x07fa, + 0x081a, + 0x0824, + 0x0828, + 0x093d, + 0x0950, + 0x09b2, + 0x09bd, + 0x09ce, + 0x0a5e, + 0x0abd, + 0x0ad0, + 0x0b3d, + 0x0b71, + 0x0b83, + 0x0b9c, + 0x0bd0, + 0x0c3d, + 0x0cbd, + 0x0cde, + 0x0d3d, + 0x0d4e, + 0x0dbd, + 0x0e84, + 0x0e8a, + 0x0e8d, + 0x0ea5, + 0x0ea7, + 0x0ebd, + 0x0ec6, + 0x0f00, + 0x103f, + 0x1061, + 0x108e, + 0x10fc, + 0x1258, + 0x12c0, + 0x17d7, + 0x17dc, + 0x18aa, + 0x1aa7, + 0x1f59, + 0x1f5b, + 0x1f5d, + 0x1fbe, + 0x2071, + 0x207f, + 0x2102, + 0x2107, + 0x2115, + 0x2124, + 0x2126, + 0x2128, + 0x214e, + 0x2d6f, + 0x2e2f, + 0xa8fb, + 0xa9cf, + 0xaa7a, + 0xaab1, + 0xaac0, + 0xaac2, + 0xfb1d, + 0xfb3e, + 0x10808, + 0x1083c, + 0x10a00, + 0x1d4a2, + 0x1d4bb, + 0x1d546, +}; + +int +isalpharune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = rbsearch(c, __isalphas, nelem(__isalphas), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __isupperr[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03d2, 0x03d4, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x210b, 0x210d, + 0x2110, 0x2112, + 0x2119, 0x211d, + 0x212a, 0x212d, + 0x2130, 0x2133, + 0x213e, 0x213f, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xff21, 0xff3a, + 0x10400, 0x10427, + 0x1d400, 0x1d419, + 0x1d434, 0x1d44d, + 0x1d468, 0x1d481, + 0x1d49e, 0x1d49f, + 0x1d4a5, 0x1d4a6, + 0x1d4a9, 0x1d4ac, + 0x1d4ae, 0x1d4b5, + 0x1d4d0, 0x1d4e9, + 0x1d504, 0x1d505, + 0x1d507, 0x1d50a, + 0x1d50d, 0x1d514, + 0x1d516, 0x1d51c, + 0x1d538, 0x1d539, + 0x1d53b, 0x1d53e, + 0x1d540, 0x1d544, + 0x1d54a, 0x1d550, + 0x1d56c, 0x1d585, + 0x1d5a0, 0x1d5b9, + 0x1d5d4, 0x1d5ed, + 0x1d608, 0x1d621, + 0x1d63c, 0x1d655, + 0x1d670, 0x1d689, + 0x1d6a8, 0x1d6c0, + 0x1d6e2, 0x1d6fa, + 0x1d71c, 0x1d734, + 0x1d756, 0x1d76e, + 0x1d790, 0x1d7a8, +}; + +static Rune __isupperp[] = { + 0x0100, 0x0136, + 0x0139, 0x0147, + 0x014a, 0x0176, + 0x017b, 0x017d, + 0x01a2, 0x01a4, + 0x01cd, 0x01db, + 0x01de, 0x01ee, + 0x01fa, 0x0232, + 0x0248, 0x024e, + 0x0370, 0x0372, + 0x03d8, 0x03ee, + 0x0460, 0x0480, + 0x048a, 0x04be, + 0x04c3, 0x04cd, + 0x04d0, 0x0526, + 0x1e00, 0x1e94, + 0x1e9e, 0x1efe, + 0x1f59, 0x1f5f, + 0x2124, 0x2128, + 0x2c67, 0x2c6b, + 0x2c82, 0x2ce2, + 0x2ceb, 0x2ced, + 0xa640, 0xa66c, + 0xa680, 0xa696, + 0xa722, 0xa72e, + 0xa732, 0xa76e, + 0xa779, 0xa77b, + 0xa780, 0xa786, + 0xa78b, 0xa78d, + 0xa7a0, 0xa7a8, +}; + +static Rune __isuppers[] = { + 0x0184, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c4, + 0x01c7, + 0x01ca, + 0x01f1, + 0x01f4, + 0x0241, + 0x0376, + 0x0386, + 0x038c, + 0x03cf, + 0x03f4, + 0x03f7, + 0x2102, + 0x2107, + 0x2115, + 0x2145, + 0x2183, + 0x2c60, + 0x2c72, + 0x2c75, + 0xa790, + 0x1d49c, + 0x1d4a2, + 0x1d546, + 0x1d7ca, +}; + +int +isupperrune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = rbsearch(c, __isuppers, nelem(__isuppers), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __islowerr[] = { + 0x0061, 0x007a, + 0x00df, 0x00f6, + 0x00f8, 0x00ff, + 0x0137, 0x0138, + 0x0148, 0x0149, + 0x017e, 0x0180, + 0x018c, 0x018d, + 0x0199, 0x019b, + 0x01aa, 0x01ab, + 0x01b9, 0x01ba, + 0x01bd, 0x01bf, + 0x01dc, 0x01dd, + 0x01ef, 0x01f0, + 0x0233, 0x0239, + 0x023f, 0x0240, + 0x024f, 0x0293, + 0x0295, 0x02af, + 0x037b, 0x037d, + 0x03ac, 0x03ce, + 0x03d0, 0x03d1, + 0x03d5, 0x03d7, + 0x03ef, 0x03f3, + 0x03fb, 0x03fc, + 0x0430, 0x045f, + 0x04ce, 0x04cf, + 0x0561, 0x0587, + 0x1d00, 0x1d2b, + 0x1d62, 0x1d77, + 0x1d79, 0x1d9a, + 0x1e95, 0x1e9d, + 0x1eff, 0x1f07, + 0x1f10, 0x1f15, + 0x1f20, 0x1f27, + 0x1f30, 0x1f37, + 0x1f40, 0x1f45, + 0x1f50, 0x1f57, + 0x1f60, 0x1f67, + 0x1f70, 0x1f7d, + 0x1f80, 0x1f87, + 0x1f90, 0x1f97, + 0x1fa0, 0x1fa7, + 0x1fb0, 0x1fb4, + 0x1fb6, 0x1fb7, + 0x1fc2, 0x1fc4, + 0x1fc6, 0x1fc7, + 0x1fd0, 0x1fd3, + 0x1fd6, 0x1fd7, + 0x1fe0, 0x1fe7, + 0x1ff2, 0x1ff4, + 0x1ff6, 0x1ff7, + 0x210e, 0x210f, + 0x213c, 0x213d, + 0x2146, 0x2149, + 0x2170, 0x217f, + 0x24d0, 0x24e9, + 0x2c30, 0x2c5e, + 0x2c65, 0x2c66, + 0x2c73, 0x2c74, + 0x2c76, 0x2c7c, + 0x2ce3, 0x2ce4, + 0x2d00, 0x2d25, + 0xa72f, 0xa731, + 0xa771, 0xa778, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xff41, 0xff5a, + 0x10428, 0x1044f, + 0x1d41a, 0x1d433, + 0x1d44e, 0x1d454, + 0x1d456, 0x1d467, + 0x1d482, 0x1d49b, + 0x1d4b6, 0x1d4b9, + 0x1d4bd, 0x1d4c3, + 0x1d4c5, 0x1d4cf, + 0x1d4ea, 0x1d503, + 0x1d51e, 0x1d537, + 0x1d552, 0x1d56b, + 0x1d586, 0x1d59f, + 0x1d5ba, 0x1d5d3, + 0x1d5ee, 0x1d607, + 0x1d622, 0x1d63b, + 0x1d656, 0x1d66f, + 0x1d68a, 0x1d6a5, + 0x1d6c2, 0x1d6da, + 0x1d6dc, 0x1d6e1, + 0x1d6fc, 0x1d714, + 0x1d716, 0x1d71b, + 0x1d736, 0x1d74e, + 0x1d750, 0x1d755, + 0x1d770, 0x1d788, + 0x1d78a, 0x1d78f, + 0x1d7aa, 0x1d7c2, + 0x1d7c4, 0x1d7c9, +}; + +static Rune __islowerp[] = { + 0x0101, 0x0135, + 0x013a, 0x0146, + 0x014b, 0x0177, + 0x017a, 0x017c, + 0x0183, 0x0185, + 0x01a1, 0x01a5, + 0x01b4, 0x01b6, + 0x01cc, 0x01da, + 0x01df, 0x01ed, + 0x01f3, 0x01f5, + 0x01f9, 0x0231, + 0x0247, 0x024d, + 0x0371, 0x0373, + 0x03d9, 0x03ed, + 0x0461, 0x0481, + 0x048b, 0x04bf, + 0x04c2, 0x04cc, + 0x04d1, 0x0527, + 0x1e01, 0x1e93, + 0x1e9f, 0x1efd, + 0x2c68, 0x2c6c, + 0x2c81, 0x2ce1, + 0x2cec, 0x2cee, + 0xa641, 0xa66d, + 0xa681, 0xa697, + 0xa723, 0xa72d, + 0xa733, 0xa76f, + 0xa77a, 0xa77c, + 0xa77f, 0xa787, + 0xa78c, 0xa78e, + 0xa7a1, 0xa7a9, +}; + +static Rune __islowers[] = { + 0x00aa, + 0x00b5, + 0x00ba, + 0x0188, + 0x0192, + 0x0195, + 0x019e, + 0x01a8, + 0x01ad, + 0x01b0, + 0x01c6, + 0x01c9, + 0x023c, + 0x0242, + 0x0377, + 0x0390, + 0x03f5, + 0x03f8, + 0x1fbe, + 0x210a, + 0x2113, + 0x212f, + 0x2134, + 0x2139, + 0x214e, + 0x2184, + 0x2c61, + 0x2c71, + 0xa791, + 0xa7fa, + 0x1d4bb, + 0x1d7cb, +}; + +int +islowerrune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = rbsearch(c, __islowers, nelem(__islowers), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __istitler[] = { + 0x0041, 0x005a, + 0x00c0, 0x00d6, + 0x00d8, 0x00de, + 0x0178, 0x0179, + 0x0181, 0x0182, + 0x0186, 0x0187, + 0x0189, 0x018b, + 0x018e, 0x0191, + 0x0193, 0x0194, + 0x0196, 0x0198, + 0x019c, 0x019d, + 0x019f, 0x01a0, + 0x01a6, 0x01a7, + 0x01ae, 0x01af, + 0x01b1, 0x01b3, + 0x01b7, 0x01b8, + 0x01f6, 0x01f8, + 0x023a, 0x023b, + 0x023d, 0x023e, + 0x0243, 0x0246, + 0x0388, 0x038a, + 0x038e, 0x038f, + 0x0391, 0x03a1, + 0x03a3, 0x03ab, + 0x03f9, 0x03fa, + 0x03fd, 0x042f, + 0x04c0, 0x04c1, + 0x0531, 0x0556, + 0x10a0, 0x10c5, + 0x1f08, 0x1f0f, + 0x1f18, 0x1f1d, + 0x1f28, 0x1f2f, + 0x1f38, 0x1f3f, + 0x1f48, 0x1f4d, + 0x1f68, 0x1f6f, + 0x1f88, 0x1f8f, + 0x1f98, 0x1f9f, + 0x1fa8, 0x1faf, + 0x1fb8, 0x1fbc, + 0x1fc8, 0x1fcc, + 0x1fd8, 0x1fdb, + 0x1fe8, 0x1fec, + 0x1ff8, 0x1ffc, + 0x2160, 0x216f, + 0x24b6, 0x24cf, + 0x2c00, 0x2c2e, + 0x2c62, 0x2c64, + 0x2c6d, 0x2c70, + 0x2c7e, 0x2c80, + 0xa77d, 0xa77e, + 0xff21, 0xff3a, + 0x10400, 0x10427, +}; + +static Rune __istitlep[] = { + 0x0100, 0x012e, + 0x0132, 0x0136, + 0x0139, 0x0147, + 0x014a, 0x0176, + 0x017b, 0x017d, + 0x01a2, 0x01a4, + 0x01cb, 0x01db, + 0x01de, 0x01ee, + 0x01f2, 0x01f4, + 0x01fa, 0x0232, + 0x0248, 0x024e, + 0x0370, 0x0372, + 0x03d8, 0x03ee, + 0x0460, 0x0480, + 0x048a, 0x04be, + 0x04c3, 0x04cd, + 0x04d0, 0x0526, + 0x1e00, 0x1e94, + 0x1ea0, 0x1efe, + 0x1f59, 0x1f5f, + 0x2c67, 0x2c6b, + 0x2c82, 0x2ce2, + 0x2ceb, 0x2ced, + 0xa640, 0xa66c, + 0xa680, 0xa696, + 0xa722, 0xa72e, + 0xa732, 0xa76e, + 0xa779, 0xa77b, + 0xa780, 0xa786, + 0xa78b, 0xa78d, + 0xa7a0, 0xa7a8, +}; + +static Rune __istitles[] = { + 0x0184, + 0x01a9, + 0x01ac, + 0x01b5, + 0x01bc, + 0x01c5, + 0x01c8, + 0x0241, + 0x0376, + 0x0386, + 0x038c, + 0x03cf, + 0x03f7, + 0x2132, + 0x2183, + 0x2c60, + 0x2c72, + 0x2c75, + 0xa790, +}; + +int +istitlerune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __istitler, nelem(__istitler)/2, 2); + if(p && c >= p[0] && c <= p[1]) + return 1; + p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return 1; + p = rbsearch(c, __istitles, nelem(__istitles), 1); + if(p && c == p[0]) + return 1; + return 0; +} + +static Rune __toupperr[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, +}; + +static Rune __toupperp[] = { + 0x0101, 0x012f, 1048575, + 0x0133, 0x0137, 1048575, + 0x013a, 0x0148, 1048575, + 0x014b, 0x0177, 1048575, + 0x017a, 0x017e, 1048575, + 0x0183, 0x0185, 1048575, + 0x01a1, 0x01a5, 1048575, + 0x01b4, 0x01b6, 1048575, + 0x01ce, 0x01dc, 1048575, + 0x01df, 0x01ef, 1048575, + 0x01f9, 0x021f, 1048575, + 0x0223, 0x0233, 1048575, + 0x0247, 0x024f, 1048575, + 0x0371, 0x0373, 1048575, + 0x03d9, 0x03ef, 1048575, + 0x0461, 0x0481, 1048575, + 0x048b, 0x04bf, 1048575, + 0x04c2, 0x04ce, 1048575, + 0x04d1, 0x0527, 1048575, + 0x1e01, 0x1e95, 1048575, + 0x1ea1, 0x1eff, 1048575, + 0x1f51, 0x1f57, 1048584, + 0x2c68, 0x2c6c, 1048575, + 0x2c81, 0x2ce3, 1048575, + 0x2cec, 0x2cee, 1048575, + 0xa641, 0xa66d, 1048575, + 0xa681, 0xa697, 1048575, + 0xa723, 0xa72f, 1048575, + 0xa733, 0xa76f, 1048575, + 0xa77a, 0xa77c, 1048575, + 0xa77f, 0xa787, 1048575, + 0xa7a1, 0xa7a9, 1048575, +}; + +static Rune __touppers[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0131, 1048344, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c5, 1048575, + 0x01c6, 1048574, + 0x01c8, 1048575, + 0x01c9, 1048574, + 0x01cb, 1048575, + 0x01cc, 1048574, + 0x01dd, 1048497, + 0x01f2, 1048575, + 0x01f3, 1048574, + 0x01f5, 1048575, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x0260, 1048371, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x0345, 1048660, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x04cf, 1048561, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e9b, 1048517, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, +}; + +Rune +toupperrune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = rbsearch(c, __touppers, nelem(__touppers)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + +static Rune __tolowerr[] = { + 0x0041, 0x005a, 1048608, + 0x00c0, 0x00d6, 1048608, + 0x00d8, 0x00de, 1048608, + 0x0189, 0x018a, 1048781, + 0x01b1, 0x01b2, 1048793, + 0x0388, 0x038a, 1048613, + 0x038e, 0x038f, 1048639, + 0x0391, 0x03a1, 1048608, + 0x03a3, 0x03ab, 1048608, + 0x03fd, 0x03ff, 1048446, + 0x0400, 0x040f, 1048656, + 0x0410, 0x042f, 1048608, + 0x0531, 0x0556, 1048624, + 0x10a0, 0x10c5, 1055840, + 0x1f08, 0x1f0f, 1048568, + 0x1f18, 0x1f1d, 1048568, + 0x1f28, 0x1f2f, 1048568, + 0x1f38, 0x1f3f, 1048568, + 0x1f48, 0x1f4d, 1048568, + 0x1f68, 0x1f6f, 1048568, + 0x1f88, 0x1f8f, 1048568, + 0x1f98, 0x1f9f, 1048568, + 0x1fa8, 0x1faf, 1048568, + 0x1fb8, 0x1fb9, 1048568, + 0x1fba, 0x1fbb, 1048502, + 0x1fc8, 0x1fcb, 1048490, + 0x1fd8, 0x1fd9, 1048568, + 0x1fda, 0x1fdb, 1048476, + 0x1fe8, 0x1fe9, 1048568, + 0x1fea, 0x1feb, 1048464, + 0x1ff8, 0x1ff9, 1048448, + 0x1ffa, 0x1ffb, 1048450, + 0x2160, 0x216f, 1048592, + 0x24b6, 0x24cf, 1048602, + 0x2c00, 0x2c2e, 1048624, + 0x2c7e, 0x2c7f, 1037761, + 0xff21, 0xff3a, 1048608, + 0x10400, 0x10427, 1048616, +}; + +static Rune __tolowerp[] = { + 0x0100, 0x012e, 1048577, + 0x0132, 0x0136, 1048577, + 0x0139, 0x0147, 1048577, + 0x014a, 0x0176, 1048577, + 0x017b, 0x017d, 1048577, + 0x01a2, 0x01a4, 1048577, + 0x01b3, 0x01b5, 1048577, + 0x01cd, 0x01db, 1048577, + 0x01de, 0x01ee, 1048577, + 0x01f8, 0x021e, 1048577, + 0x0222, 0x0232, 1048577, + 0x0248, 0x024e, 1048577, + 0x0370, 0x0372, 1048577, + 0x03d8, 0x03ee, 1048577, + 0x0460, 0x0480, 1048577, + 0x048a, 0x04be, 1048577, + 0x04c3, 0x04cd, 1048577, + 0x04d0, 0x0526, 1048577, + 0x1e00, 0x1e94, 1048577, + 0x1ea0, 0x1efe, 1048577, + 0x1f59, 0x1f5f, 1048568, + 0x2c67, 0x2c6b, 1048577, + 0x2c80, 0x2ce2, 1048577, + 0x2ceb, 0x2ced, 1048577, + 0xa640, 0xa66c, 1048577, + 0xa680, 0xa696, 1048577, + 0xa722, 0xa72e, 1048577, + 0xa732, 0xa76e, 1048577, + 0xa779, 0xa77b, 1048577, + 0xa780, 0xa786, 1048577, + 0xa7a0, 0xa7a8, 1048577, +}; + +static Rune __tolowers[] = { + 0x0130, 1048377, + 0x0178, 1048455, + 0x0179, 1048577, + 0x0181, 1048786, + 0x0182, 1048577, + 0x0184, 1048577, + 0x0186, 1048782, + 0x0187, 1048577, + 0x018b, 1048577, + 0x018e, 1048655, + 0x018f, 1048778, + 0x0190, 1048779, + 0x0191, 1048577, + 0x0193, 1048781, + 0x0194, 1048783, + 0x0196, 1048787, + 0x0197, 1048785, + 0x0198, 1048577, + 0x019c, 1048787, + 0x019d, 1048789, + 0x019f, 1048790, + 0x01a0, 1048577, + 0x01a6, 1048794, + 0x01a7, 1048577, + 0x01a9, 1048794, + 0x01ac, 1048577, + 0x01ae, 1048794, + 0x01af, 1048577, + 0x01b7, 1048795, + 0x01b8, 1048577, + 0x01bc, 1048577, + 0x01c4, 1048578, + 0x01c5, 1048577, + 0x01c7, 1048578, + 0x01c8, 1048577, + 0x01ca, 1048578, + 0x01cb, 1048577, + 0x01f1, 1048578, + 0x01f2, 1048577, + 0x01f4, 1048577, + 0x01f6, 1048479, + 0x01f7, 1048520, + 0x0220, 1048446, + 0x023a, 1059371, + 0x023b, 1048577, + 0x023d, 1048413, + 0x023e, 1059368, + 0x0241, 1048577, + 0x0243, 1048381, + 0x0244, 1048645, + 0x0245, 1048647, + 0x0246, 1048577, + 0x0376, 1048577, + 0x0386, 1048614, + 0x038c, 1048640, + 0x03cf, 1048584, + 0x03f4, 1048516, + 0x03f7, 1048577, + 0x03f9, 1048569, + 0x03fa, 1048577, + 0x04c0, 1048591, + 0x04c1, 1048577, + 0x1e9e, 1040961, + 0x1fbc, 1048567, + 0x1fcc, 1048567, + 0x1fec, 1048569, + 0x1ffc, 1048567, + 0x2126, 1041059, + 0x212a, 1040193, + 0x212b, 1040314, + 0x2132, 1048604, + 0x2183, 1048577, + 0x2c60, 1048577, + 0x2c62, 1037833, + 0x2c63, 1044762, + 0x2c64, 1037849, + 0x2c6d, 1037796, + 0x2c6e, 1037827, + 0x2c6f, 1037793, + 0x2c70, 1037794, + 0x2c72, 1048577, + 0x2c75, 1048577, + 0xa77d, 1013244, + 0xa77e, 1048577, + 0xa78b, 1048577, + 0xa78d, 1006296, + 0xa790, 1048577, +}; + +Rune +tolowerrune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + +static Rune __totitler[] = { + 0x0061, 0x007a, 1048544, + 0x00e0, 0x00f6, 1048544, + 0x00f8, 0x00fe, 1048544, + 0x023f, 0x0240, 1059391, + 0x0256, 0x0257, 1048371, + 0x028a, 0x028b, 1048359, + 0x037b, 0x037d, 1048706, + 0x03ad, 0x03af, 1048539, + 0x03b1, 0x03c1, 1048544, + 0x03c3, 0x03cb, 1048544, + 0x03cd, 0x03ce, 1048513, + 0x0430, 0x044f, 1048544, + 0x0450, 0x045f, 1048496, + 0x0561, 0x0586, 1048528, + 0x1f00, 0x1f07, 1048584, + 0x1f10, 0x1f15, 1048584, + 0x1f20, 0x1f27, 1048584, + 0x1f30, 0x1f37, 1048584, + 0x1f40, 0x1f45, 1048584, + 0x1f60, 0x1f67, 1048584, + 0x1f70, 0x1f71, 1048650, + 0x1f72, 0x1f75, 1048662, + 0x1f76, 0x1f77, 1048676, + 0x1f78, 0x1f79, 1048704, + 0x1f7a, 0x1f7b, 1048688, + 0x1f7c, 0x1f7d, 1048702, + 0x1f80, 0x1f87, 1048584, + 0x1f90, 0x1f97, 1048584, + 0x1fa0, 0x1fa7, 1048584, + 0x1fb0, 0x1fb1, 1048584, + 0x1fd0, 0x1fd1, 1048584, + 0x1fe0, 0x1fe1, 1048584, + 0x2170, 0x217f, 1048560, + 0x24d0, 0x24e9, 1048550, + 0x2c30, 0x2c5e, 1048528, + 0x2d00, 0x2d25, 1041312, + 0xff41, 0xff5a, 1048544, + 0x10428, 0x1044f, 1048536, +}; + +static Rune __totitlep[] = { + 0x0101, 0x012f, 1048575, + 0x0133, 0x0137, 1048575, + 0x013a, 0x0148, 1048575, + 0x014b, 0x0177, 1048575, + 0x017a, 0x017e, 1048575, + 0x0183, 0x0185, 1048575, + 0x01a1, 0x01a5, 1048575, + 0x01b4, 0x01b6, 1048575, + 0x01cc, 0x01dc, 1048575, + 0x01df, 0x01ef, 1048575, + 0x01f3, 0x01f5, 1048575, + 0x01f9, 0x021f, 1048575, + 0x0223, 0x0233, 1048575, + 0x0247, 0x024f, 1048575, + 0x0371, 0x0373, 1048575, + 0x03d9, 0x03ef, 1048575, + 0x0461, 0x0481, 1048575, + 0x048b, 0x04bf, 1048575, + 0x04c2, 0x04ce, 1048575, + 0x04d1, 0x0527, 1048575, + 0x1e01, 0x1e95, 1048575, + 0x1ea1, 0x1eff, 1048575, + 0x1f51, 0x1f57, 1048584, + 0x2c68, 0x2c6c, 1048575, + 0x2c81, 0x2ce3, 1048575, + 0x2cec, 0x2cee, 1048575, + 0xa641, 0xa66d, 1048575, + 0xa681, 0xa697, 1048575, + 0xa723, 0xa72f, 1048575, + 0xa733, 0xa76f, 1048575, + 0xa77a, 0xa77c, 1048575, + 0xa77f, 0xa787, 1048575, + 0xa7a1, 0xa7a9, 1048575, +}; + +static Rune __totitles[] = { + 0x00b5, 1049319, + 0x00ff, 1048697, + 0x0131, 1048344, + 0x017f, 1048276, + 0x0180, 1048771, + 0x0188, 1048575, + 0x018c, 1048575, + 0x0192, 1048575, + 0x0195, 1048673, + 0x0199, 1048575, + 0x019a, 1048739, + 0x019e, 1048706, + 0x01a8, 1048575, + 0x01ad, 1048575, + 0x01b0, 1048575, + 0x01b9, 1048575, + 0x01bd, 1048575, + 0x01bf, 1048632, + 0x01c4, 1048577, + 0x01c6, 1048575, + 0x01c7, 1048577, + 0x01c9, 1048575, + 0x01ca, 1048577, + 0x01dd, 1048497, + 0x01f1, 1048577, + 0x023c, 1048575, + 0x0242, 1048575, + 0x0250, 1059359, + 0x0251, 1059356, + 0x0252, 1059358, + 0x0253, 1048366, + 0x0254, 1048370, + 0x0259, 1048374, + 0x025b, 1048373, + 0x0260, 1048371, + 0x0263, 1048369, + 0x0265, 1090856, + 0x0268, 1048367, + 0x0269, 1048365, + 0x026b, 1059319, + 0x026f, 1048365, + 0x0271, 1059325, + 0x0272, 1048363, + 0x0275, 1048362, + 0x027d, 1059303, + 0x0280, 1048358, + 0x0283, 1048358, + 0x0288, 1048358, + 0x0289, 1048507, + 0x028c, 1048505, + 0x0292, 1048357, + 0x0345, 1048660, + 0x0377, 1048575, + 0x03ac, 1048538, + 0x03c2, 1048545, + 0x03cc, 1048512, + 0x03d0, 1048514, + 0x03d1, 1048519, + 0x03d5, 1048529, + 0x03d6, 1048522, + 0x03d7, 1048568, + 0x03f0, 1048490, + 0x03f1, 1048496, + 0x03f2, 1048583, + 0x03f5, 1048480, + 0x03f8, 1048575, + 0x03fb, 1048575, + 0x04cf, 1048561, + 0x1d79, 1083908, + 0x1d7d, 1052390, + 0x1e9b, 1048517, + 0x1fb3, 1048585, + 0x1fbe, 1041371, + 0x1fc3, 1048585, + 0x1fe5, 1048583, + 0x1ff3, 1048585, + 0x214e, 1048548, + 0x2184, 1048575, + 0x2c61, 1048575, + 0x2c65, 1037781, + 0x2c66, 1037784, + 0x2c73, 1048575, + 0x2c76, 1048575, + 0xa78c, 1048575, + 0xa791, 1048575, +}; + +Rune +totitlerune(Rune c) +{ + Rune *p; + + p = rbsearch(c, __totitler, nelem(__totitler)/3, 3); + if(p && c >= p[0] && c <= p[1]) + return c + p[2] - 1048576; + p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3); + if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1)) + return c + p[2] - 1048576; + p = rbsearch(c, __totitles, nelem(__totitles)/2, 2); + if(p && c == p[0]) + return c + p[1] - 1048576; + return c; +} + diff --git a/src/lib9/utf/utf.h b/src/lib9/utf/utf.h index 1479e9f21..8a79828bc 100644 --- a/src/lib9/utf/utf.h +++ b/src/lib9/utf/utf.h @@ -224,12 +224,6 @@ int isalpharune(Rune r); int isdigitrune(Rune r); -// isideographicrune tests for ideographic characters and numbers, as -// defined by the Unicode standard. - -int isideographicrune(Rune r); - - // isspacerune tests for whitespace characters, including "C" locale // whitespace, Unicode defined whitespace, and the "zero-width // non-break space" character. diff --git a/src/make.bash b/src/make.bash index 0d0dae61f..43c70a87b 100755 --- a/src/make.bash +++ b/src/make.bash @@ -36,7 +36,7 @@ rm -f "$GOBIN"/gomake ) >"$GOBIN"/gomake chmod +x "$GOBIN"/gomake -if [ -d /selinux -a -f /selinux/booleans/allow_execstack ] ; then +if [ -d /selinux -a -f /selinux/booleans/allow_execstack -a -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then if ! cat /selinux/booleans/allow_execstack | grep -c '^1 1$' >> /dev/null ; then echo "WARNING: the default SELinux policy on, at least, Fedora 12 breaks " echo "Go. You can enable the features that Go needs via the following " diff --git a/src/pkg/Makefile b/src/pkg/Makefile index 05e2a26d1..6ba6951af 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -28,11 +28,13 @@ DIRS=\ container/list\ container/ring\ container/vector\ + crypto\ crypto/aes\ crypto/block\ crypto/blowfish\ crypto/cast5\ crypto/cipher\ + crypto/dsa\ crypto/elliptic\ crypto/hmac\ crypto/md4\ @@ -58,6 +60,7 @@ DIRS=\ debug/proc\ ebnf\ encoding/ascii85\ + encoding/base32\ encoding/base64\ encoding/binary\ encoding/git85\ @@ -113,6 +116,7 @@ DIRS=\ rpc/jsonrpc\ runtime\ runtime/cgo\ + runtime/debug\ runtime/pprof\ scanner\ smtp\ @@ -150,11 +154,8 @@ DIRS+=\ endif -ifeq ($(GOOS),windows) -DIRS:=$(filter-out runtime/cgo,$(DIRS)) -endif - NOTEST=\ + crypto\ debug/proc\ exp/draw/x11\ go/ast\ diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go index c13456a63..eae5c5ce9 100644 --- a/src/pkg/bufio/bufio.go +++ b/src/pkg/bufio/bufio.go @@ -286,7 +286,8 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) { // returning a slice containing the data up to and including the delimiter. // If ReadBytes encounters an error before finding a delimiter, // it returns the data read before the error and the error itself (often os.EOF). -// ReadBytes returns err != nil if and only if line does not end in delim. +// ReadBytes returns err != nil if and only if the returned data does not end in +// delim. func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) { // Use ReadSlice to look for array, // accumulating full buffers. @@ -332,7 +333,8 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) { // returning a string containing the data up to and including the delimiter. // If ReadString encounters an error before finding a delimiter, // it returns the data read before the error and the error itself (often os.EOF). -// ReadString returns err != nil if and only if line does not end in delim. +// ReadString returns err != nil if and only if the returned data does not end in +// delim. func (b *Reader) ReadString(delim byte) (line string, err os.Error) { bytes, e := b.ReadBytes(delim) return string(bytes), e @@ -383,6 +385,9 @@ func (b *Writer) Flush() os.Error { if b.err != nil { return b.err } + if b.n == 0 { + return nil + } n, e := b.wr.Write(b.buf[0:b.n]) if n < b.n && e == nil { e = io.ErrShortWrite diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go index 2574b4f43..4aa74371f 100644 --- a/src/pkg/bytes/buffer.go +++ b/src/pkg/bytes/buffer.go @@ -301,9 +301,38 @@ func (b *Buffer) UnreadByte() os.Error { return nil } +// ReadBytes reads until the first occurrence of delim in the input, +// returning a slice containing the data up to and including the delimiter. +// If ReadBytes encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often os.EOF). +// ReadBytes returns err != nil if and only if the returned data does not end in +// delim. +func (b *Buffer) ReadBytes(delim byte) (line []byte, err os.Error) { + i := IndexByte(b.buf[b.off:], delim) + size := i + 1 - b.off + if i < 0 { + size = len(b.buf) - b.off + err = os.EOF + } + line = make([]byte, size) + copy(line, b.buf[b.off:]) + return +} + +// ReadString reads until the first occurrence of delim in the input, +// returning a string containing the data up to and including the delimiter. +// If ReadString encounters an error before finding a delimiter, +// it returns the data read before the error and the error itself (often os.EOF). +// ReadString returns err != nil if and only if the returned data does not end +// in delim. +func (b *Buffer) ReadString(delim byte) (line string, err os.Error) { + bytes, err := b.ReadBytes(delim) + return string(bytes), err +} + // NewBuffer creates and initializes a new Buffer using buf as its initial // contents. It is intended to prepare a Buffer to read existing data. It -// can also be used to to size the internal buffer for writing. To do that, +// can also be used to size the internal buffer for writing. To do that, // buf should have the desired capacity but a length of zero. func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go index 509793d24..2af9ffdef 100644 --- a/src/pkg/bytes/buffer_test.go +++ b/src/pkg/bytes/buffer_test.go @@ -6,6 +6,7 @@ package bytes_test import ( . "bytes" + "os" "rand" "testing" "utf8" @@ -238,7 +239,7 @@ func TestMixedReadsAndWrites(t *testing.T) { func TestNil(t *testing.T) { var b *Buffer if b.String() != "<nil>" { - t.Errorf("expcted <nil>; got %q", b.String()) + t.Errorf("expected <nil>; got %q", b.String()) } } @@ -347,3 +348,27 @@ func TestNext(t *testing.T) { } } } + +var readBytesTests = []struct { + buffer []byte + delim byte + expected []byte + err os.Error +}{ + {err: os.EOF}, + {[]byte{}, 0, []byte{}, os.EOF}, + {[]byte("a\x00"), 0, []byte("a\x00"), nil}, + {[]byte("hello\x01world"), 1, []byte("hello\x01"), nil}, + {[]byte("foo\nbar"), 0, []byte("foo\nbar"), os.EOF}, + {[]byte("alpha beta gamma"), ' ', []byte("alpha "), nil}, +} + +func TestReadBytes(t *testing.T) { + for _, test := range readBytesTests { + buf := NewBuffer(test.buffer) + bytes, err := buf.ReadBytes(test.delim) + if !Equal(bytes, test.expected) || err != test.err { + t.Errorf("expected %q, %v got %q, %v", test.expected, test.err, bytes, err) + } + } +} diff --git a/src/pkg/cmath/asin.go b/src/pkg/cmath/asin.go index eb87ba5e5..d6a3ca480 100644 --- a/src/pkg/cmath/asin.go +++ b/src/pkg/cmath/asin.go @@ -51,16 +51,16 @@ import "math" func Asin(x complex128) complex128 { if imag(x) == 0 { if math.Fabs(real(x)) > 1 { - return cmplx(math.Pi/2, 0) // DOMAIN error + return complex(math.Pi/2, 0) // DOMAIN error } - return cmplx(math.Asin(real(x)), 0) + return complex(math.Asin(real(x)), 0) } - ct := cmplx(-imag(x), real(x)) // i * x + ct := complex(-imag(x), real(x)) // i * x xx := x * x - x1 := cmplx(1-real(xx), -imag(xx)) // 1 - x*x - x2 := Sqrt(x1) // x2 = sqrt(1 - x*x) + x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x + x2 := Sqrt(x1) // x2 = sqrt(1 - x*x) w := Log(ct + x2) - return cmplx(imag(w), -real(w)) // -i * w + return complex(imag(w), -real(w)) // -i * w } // Asinh returns the inverse hyperbolic sine of x. @@ -68,13 +68,13 @@ func Asinh(x complex128) complex128 { // TODO check range if imag(x) == 0 { if math.Fabs(real(x)) > 1 { - return cmplx(math.Pi/2, 0) // DOMAIN error + return complex(math.Pi/2, 0) // DOMAIN error } - return cmplx(math.Asinh(real(x)), 0) + return complex(math.Asinh(real(x)), 0) } xx := x * x - x1 := cmplx(1+real(xx), imag(xx)) // 1 + x*x - return Log(x + Sqrt(x1)) // log(x + sqrt(1 + x*x)) + x1 := complex(1+real(xx), imag(xx)) // 1 + x*x + return Log(x + Sqrt(x1)) // log(x + sqrt(1 + x*x)) } // Complex circular arc cosine @@ -93,16 +93,16 @@ func Asinh(x complex128) complex128 { // Acos returns the inverse cosine of x. func Acos(x complex128) complex128 { w := Asin(x) - return cmplx(math.Pi/2-real(w), -imag(w)) + return complex(math.Pi/2-real(w), -imag(w)) } // Acosh returns the inverse hyperbolic cosine of x. func Acosh(x complex128) complex128 { w := Acos(x) if imag(w) <= 0 { - return cmplx(-imag(w), real(w)) // i * w + return complex(-imag(w), real(w)) // i * w } - return cmplx(imag(w), -real(w)) // -i * w + return complex(imag(w), -real(w)) // -i * w } // Complex circular arc tangent @@ -159,12 +159,12 @@ func Atan(x complex128) complex128 { } t = imag(x) + 1 c := (x2 + t*t) / b - return cmplx(w, 0.25*math.Log(c)) + return complex(w, 0.25*math.Log(c)) } // Atanh returns the inverse hyperbolic tangent of x. func Atanh(x complex128) complex128 { - z := cmplx(-imag(x), real(x)) // z = i * x + z := complex(-imag(x), real(x)) // z = i * x z = Atan(z) - return cmplx(imag(z), -real(z)) // z = -i * z + return complex(imag(z), -real(z)) // z = -i * z } diff --git a/src/pkg/cmath/cmath_test.go b/src/pkg/cmath/cmath_test.go index 93fac4e20..6a595b0a6 100644 --- a/src/pkg/cmath/cmath_test.go +++ b/src/pkg/cmath/cmath_test.go @@ -355,15 +355,15 @@ var expSC = []complex128{ NaN(), } var vcIsNaNSC = []complex128{ - cmplx(math.Inf(-1), math.Inf(-1)), - cmplx(math.Inf(-1), math.NaN()), - cmplx(math.NaN(), math.Inf(-1)), - cmplx(0, math.NaN()), - cmplx(math.NaN(), 0), - cmplx(math.Inf(1), math.Inf(1)), - cmplx(math.Inf(1), math.NaN()), - cmplx(math.NaN(), math.Inf(1)), - cmplx(math.NaN(), math.NaN()), + complex(math.Inf(-1), math.Inf(-1)), + complex(math.Inf(-1), math.NaN()), + complex(math.NaN(), math.Inf(-1)), + complex(0, math.NaN()), + complex(math.NaN(), 0), + complex(math.Inf(1), math.Inf(1)), + complex(math.Inf(1), math.NaN()), + complex(math.NaN(), math.Inf(1)), + complex(math.NaN(), math.NaN()), } var isNaNSC = []bool{ false, @@ -615,7 +615,7 @@ func TestExp(t *testing.T) { func TestIsNaN(t *testing.T) { for i := 0; i < len(vcIsNaNSC); i++ { if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f { - t.Errorf("IsNaN(%g) = %g, want %g", vcIsNaNSC[i], f, isNaNSC[i]) + t.Errorf("IsNaN(%v) = %v, want %v", vcIsNaNSC[i], f, isNaNSC[i]) } } } @@ -656,7 +656,7 @@ func TestPolar(t *testing.T) { } } func TestPow(t *testing.T) { - var a = cmplx(float64(3), float64(3)) + var a = complex(3.0, 3.0) for i := 0; i < len(vc); i++ { if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) { t.Errorf("Pow(%g, %g) = %g, want %g", a, vc[i], f, pow[i]) @@ -743,82 +743,82 @@ func TestTanh(t *testing.T) { func BenchmarkAbs(b *testing.B) { for i := 0; i < b.N; i++ { - Abs(cmplx(2.5, 3.5)) + Abs(complex(2.5, 3.5)) } } func BenchmarkAcos(b *testing.B) { for i := 0; i < b.N; i++ { - Acos(cmplx(2.5, 3.5)) + Acos(complex(2.5, 3.5)) } } func BenchmarkAcosh(b *testing.B) { for i := 0; i < b.N; i++ { - Acosh(cmplx(2.5, 3.5)) + Acosh(complex(2.5, 3.5)) } } func BenchmarkAsin(b *testing.B) { for i := 0; i < b.N; i++ { - Asin(cmplx(2.5, 3.5)) + Asin(complex(2.5, 3.5)) } } func BenchmarkAsinh(b *testing.B) { for i := 0; i < b.N; i++ { - Asinh(cmplx(2.5, 3.5)) + Asinh(complex(2.5, 3.5)) } } func BenchmarkAtan(b *testing.B) { for i := 0; i < b.N; i++ { - Atan(cmplx(2.5, 3.5)) + Atan(complex(2.5, 3.5)) } } func BenchmarkAtanh(b *testing.B) { for i := 0; i < b.N; i++ { - Atanh(cmplx(2.5, 3.5)) + Atanh(complex(2.5, 3.5)) } } func BenchmarkConj(b *testing.B) { for i := 0; i < b.N; i++ { - Conj(cmplx(2.5, 3.5)) + Conj(complex(2.5, 3.5)) } } func BenchmarkCos(b *testing.B) { for i := 0; i < b.N; i++ { - Cos(cmplx(2.5, 3.5)) + Cos(complex(2.5, 3.5)) } } func BenchmarkCosh(b *testing.B) { for i := 0; i < b.N; i++ { - Cosh(cmplx(2.5, 3.5)) + Cosh(complex(2.5, 3.5)) } } func BenchmarkExp(b *testing.B) { for i := 0; i < b.N; i++ { - Exp(cmplx(2.5, 3.5)) + Exp(complex(2.5, 3.5)) } } func BenchmarkLog(b *testing.B) { for i := 0; i < b.N; i++ { - Log(cmplx(2.5, 3.5)) + Log(complex(2.5, 3.5)) } } func BenchmarkLog10(b *testing.B) { for i := 0; i < b.N; i++ { - Log10(cmplx(2.5, 3.5)) + Log10(complex(2.5, 3.5)) } } func BenchmarkPhase(b *testing.B) { for i := 0; i < b.N; i++ { - Phase(cmplx(2.5, 3.5)) + Phase(complex(2.5, 3.5)) } } func BenchmarkPolar(b *testing.B) { for i := 0; i < b.N; i++ { - Polar(cmplx(2.5, 3.5)) + Polar(complex(2.5, 3.5)) } } func BenchmarkPow(b *testing.B) { for i := 0; i < b.N; i++ { - Pow(cmplx(2.5, 3.5), cmplx(2.5, 3.5)) + Pow(complex(2.5, 3.5), complex(2.5, 3.5)) } } func BenchmarkRect(b *testing.B) { @@ -828,26 +828,26 @@ func BenchmarkRect(b *testing.B) { } func BenchmarkSin(b *testing.B) { for i := 0; i < b.N; i++ { - Sin(cmplx(2.5, 3.5)) + Sin(complex(2.5, 3.5)) } } func BenchmarkSinh(b *testing.B) { for i := 0; i < b.N; i++ { - Sinh(cmplx(2.5, 3.5)) + Sinh(complex(2.5, 3.5)) } } func BenchmarkSqrt(b *testing.B) { for i := 0; i < b.N; i++ { - Sqrt(cmplx(2.5, 3.5)) + Sqrt(complex(2.5, 3.5)) } } func BenchmarkTan(b *testing.B) { for i := 0; i < b.N; i++ { - Tan(cmplx(2.5, 3.5)) + Tan(complex(2.5, 3.5)) } } func BenchmarkTanh(b *testing.B) { for i := 0; i < b.N; i++ { - Tanh(cmplx(2.5, 3.5)) + Tanh(complex(2.5, 3.5)) } } diff --git a/src/pkg/cmath/conj.go b/src/pkg/cmath/conj.go index 7a19e8631..776b57da7 100644 --- a/src/pkg/cmath/conj.go +++ b/src/pkg/cmath/conj.go @@ -5,4 +5,4 @@ package cmath // Conj returns the complex conjugate of x. -func Conj(x complex128) complex128 { return cmplx(real(x), -imag(x)) } +func Conj(x complex128) complex128 { return complex(real(x), -imag(x)) } diff --git a/src/pkg/cmath/exp.go b/src/pkg/cmath/exp.go index 1a639c596..64c1ef409 100644 --- a/src/pkg/cmath/exp.go +++ b/src/pkg/cmath/exp.go @@ -51,5 +51,5 @@ import "math" func Exp(x complex128) complex128 { r := math.Exp(real(x)) s, c := math.Sincos(imag(x)) - return cmplx(r*c, r*s) + return complex(r*c, r*s) } diff --git a/src/pkg/cmath/isinf.go b/src/pkg/cmath/isinf.go index f17a752ec..f23d2dea7 100644 --- a/src/pkg/cmath/isinf.go +++ b/src/pkg/cmath/isinf.go @@ -14,8 +14,8 @@ func IsInf(x complex128) bool { return false } -// Inf returns a complex infinity, cmplx(+Inf, +Inf). +// Inf returns a complex infinity, complex(+Inf, +Inf). func Inf() complex128 { inf := math.Inf(1) - return cmplx(inf, inf) + return complex(inf, inf) } diff --git a/src/pkg/cmath/isnan.go b/src/pkg/cmath/isnan.go index 8e971dbd3..2063bb835 100644 --- a/src/pkg/cmath/isnan.go +++ b/src/pkg/cmath/isnan.go @@ -21,5 +21,5 @@ func IsNaN(x complex128) bool { // NaN returns a complex ``not-a-number'' value. func NaN() complex128 { nan := math.NaN() - return cmplx(nan, nan) + return complex(nan, nan) } diff --git a/src/pkg/cmath/log.go b/src/pkg/cmath/log.go index b42062b2a..8e6964fee 100644 --- a/src/pkg/cmath/log.go +++ b/src/pkg/cmath/log.go @@ -55,7 +55,7 @@ import "math" // Log returns the natural logarithm of x. func Log(x complex128) complex128 { - return cmplx(math.Log(Abs(x)), Phase(x)) + return complex(math.Log(Abs(x)), Phase(x)) } // Log10 returns the decimal logarithm of x. diff --git a/src/pkg/cmath/pow.go b/src/pkg/cmath/pow.go index de2c4db56..68e1207c6 100644 --- a/src/pkg/cmath/pow.go +++ b/src/pkg/cmath/pow.go @@ -46,7 +46,7 @@ import "math" func Pow(x, y complex128) complex128 { modulus := Abs(x) if modulus == 0 { - return cmplx(0, 0) + return complex(0, 0) } r := math.Pow(modulus, real(y)) arg := Phase(x) @@ -56,5 +56,5 @@ func Pow(x, y complex128) complex128 { theta += imag(y) * math.Log(modulus) } s, c := math.Sincos(theta) - return cmplx(r*c, r*s) + return complex(r*c, r*s) } diff --git a/src/pkg/cmath/rect.go b/src/pkg/cmath/rect.go index 1a88d8679..b955f0bf7 100644 --- a/src/pkg/cmath/rect.go +++ b/src/pkg/cmath/rect.go @@ -9,5 +9,5 @@ import "math" // Rect returns the complex number x with polar coordinates r, θ. func Rect(r, θ float64) complex128 { s, c := math.Sincos(θ) - return cmplx(r*c, r*s) + return complex(r*c, r*s) } diff --git a/src/pkg/cmath/sin.go b/src/pkg/cmath/sin.go index 1b79da493..8900ecdde 100644 --- a/src/pkg/cmath/sin.go +++ b/src/pkg/cmath/sin.go @@ -53,7 +53,7 @@ import "math" func Sin(x complex128) complex128 { s, c := math.Sincos(real(x)) sh, ch := sinhcosh(imag(x)) - return cmplx(s*ch, c*sh) + return complex(s*ch, c*sh) } // Complex hyperbolic sine @@ -73,7 +73,7 @@ func Sin(x complex128) complex128 { func Sinh(x complex128) complex128 { s, c := math.Sincos(imag(x)) sh, ch := sinhcosh(real(x)) - return cmplx(c*sh, s*ch) + return complex(c*sh, s*ch) } // Complex circular cosine @@ -98,7 +98,7 @@ func Sinh(x complex128) complex128 { func Cos(x complex128) complex128 { s, c := math.Sincos(real(x)) sh, ch := sinhcosh(imag(x)) - return cmplx(c*ch, -s*sh) + return complex(c*ch, -s*sh) } // Complex hyperbolic cosine @@ -117,7 +117,7 @@ func Cos(x complex128) complex128 { func Cosh(x complex128) complex128 { s, c := math.Sincos(imag(x)) sh, ch := sinhcosh(real(x)) - return cmplx(c*ch, s*sh) + return complex(c*ch, s*sh) } // calculate sinh and cosh diff --git a/src/pkg/cmath/sqrt.go b/src/pkg/cmath/sqrt.go index 58bc4b691..e77a9b9df 100644 --- a/src/pkg/cmath/sqrt.go +++ b/src/pkg/cmath/sqrt.go @@ -57,20 +57,20 @@ import "math" func Sqrt(x complex128) complex128 { if imag(x) == 0 { if real(x) == 0 { - return cmplx(0, 0) + return complex(0, 0) } if real(x) < 0 { - return cmplx(0, math.Sqrt(-real(x))) + return complex(0, math.Sqrt(-real(x))) } - return cmplx(math.Sqrt(real(x)), 0) + return complex(math.Sqrt(real(x)), 0) } if real(x) == 0 { if imag(x) < 0 { r := math.Sqrt(-0.5 * imag(x)) - return cmplx(r, -r) + return complex(r, -r) } r := math.Sqrt(0.5 * imag(x)) - return cmplx(r, r) + return complex(r, r) } a := real(x) b := imag(x) @@ -97,7 +97,7 @@ func Sqrt(x complex128) complex128 { r *= scale } if b < 0 { - return cmplx(t, -r) + return complex(t, -r) } - return cmplx(t, r) + return complex(t, r) } diff --git a/src/pkg/cmath/tan.go b/src/pkg/cmath/tan.go index d1945cd79..94b517521 100644 --- a/src/pkg/cmath/tan.go +++ b/src/pkg/cmath/tan.go @@ -64,7 +64,7 @@ func Tan(x complex128) complex128 { if d == 0 { return Inf() } - return cmplx(math.Sin(2*real(x))/d, math.Sinh(2*imag(x))/d) + return complex(math.Sin(2*real(x))/d, math.Sinh(2*imag(x))/d) } // Complex hyperbolic tangent @@ -85,7 +85,7 @@ func Tanh(x complex128) complex128 { if d == 0 { return Inf() } - return cmplx(math.Sinh(2*real(x))/d, math.Sin(2*imag(x))/d) + return complex(math.Sinh(2*real(x))/d, math.Sin(2*imag(x))/d) } // Program to subtract nearest integer multiple of PI @@ -114,11 +114,11 @@ func tanSeries(z complex128) float64 { x = reducePi(x) x = x * x y = y * y - x2 := float64(1) - y2 := float64(1) - f := float64(1) - rn := float64(0) - d := float64(0) + x2 := 1.0 + y2 := 1.0 + f := 1.0 + rn := 0.0 + d := 0.0 for { rn += 1 f *= rn @@ -180,5 +180,5 @@ func Cot(x complex128) complex128 { if d == 0 { return Inf() } - return cmplx(math.Sin(2*real(x))/d, -math.Sinh(2*imag(x))/d) + return complex(math.Sin(2*real(x))/d, -math.Sinh(2*imag(x))/d) } diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go index 3db955609..68dcd7bcc 100644 --- a/src/pkg/compress/flate/deflate_test.go +++ b/src/pkg/compress/flate/deflate_test.go @@ -116,9 +116,16 @@ func (b *syncBuffer) Read(p []byte) (n int, err os.Error) { panic("unreachable") } +func (b *syncBuffer) signal() { + select { + case b.ready <- true: + default: + } +} + func (b *syncBuffer) Write(p []byte) (n int, err os.Error) { n, err = b.buf.Write(p) - _ = b.ready <- true + b.signal() return } @@ -128,12 +135,12 @@ func (b *syncBuffer) WriteMode() { func (b *syncBuffer) ReadMode() { b.mu.Unlock() - _ = b.ready <- true + b.signal() } func (b *syncBuffer) Close() os.Error { b.closed = true - _ = b.ready <- true + b.signal() return nil } diff --git a/src/pkg/container/vector/numbers_test.go b/src/pkg/container/vector/numbers_test.go index 93335ca60..d540ace05 100644 --- a/src/pkg/container/vector/numbers_test.go +++ b/src/pkg/container/vector/numbers_test.go @@ -46,7 +46,7 @@ func TestVectorNums(t *testing.T) { v.Resize(0, 0) runtime.GC() n := m.Alloc - m0.Alloc - t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN) + t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } @@ -64,7 +64,7 @@ func TestIntVectorNums(t *testing.T) { v.Resize(0, 0) runtime.GC() n := m.Alloc - m0.Alloc - t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN) + t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } @@ -82,7 +82,7 @@ func TestStringVectorNums(t *testing.T) { v.Resize(0, 0) runtime.GC() n := m.Alloc - m0.Alloc - t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float(n)/memTestN) + t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } diff --git a/src/pkg/crypto/Makefile b/src/pkg/crypto/Makefile new file mode 100644 index 000000000..738a52062 --- /dev/null +++ b/src/pkg/crypto/Makefile @@ -0,0 +1,11 @@ +# Copyright 2011 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. + +include ../../Make.inc + +TARG=crypto +GOFILES=\ + crypto.go\ + +include ../../Make.pkg diff --git a/src/pkg/crypto/cipher/Makefile b/src/pkg/crypto/cipher/Makefile index d7e8a7a13..8f61cf20b 100644 --- a/src/pkg/crypto/cipher/Makefile +++ b/src/pkg/crypto/cipher/Makefile @@ -7,10 +7,11 @@ include ../../../Make.inc TARG=crypto/cipher GOFILES=\ cbc.go\ + cfb.go\ cipher.go\ ctr.go\ io.go\ ocfb.go\ - cfb.go + ofb.go include ../../../Make.pkg diff --git a/src/pkg/crypto/cipher/ofb.go b/src/pkg/crypto/cipher/ofb.go new file mode 100644 index 000000000..85e5f02b0 --- /dev/null +++ b/src/pkg/crypto/cipher/ofb.go @@ -0,0 +1,44 @@ +// Copyright 2011 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. + +// OFB (Output Feedback) Mode. + +package cipher + +type ofb struct { + b Block + out []byte + outUsed int +} + +// NewOFB returns a Stream that encrypts or decrypts using the block cipher b +// in output feedback mode. The initialization vector iv's length must be equal +// to b's block size. +func NewOFB(b Block, iv []byte) Stream { + blockSize := b.BlockSize() + if len(iv) != blockSize { + return nil + } + + x := &ofb{ + b: b, + out: make([]byte, blockSize), + outUsed: 0, + } + b.Encrypt(x.out, iv) + + return x +} + +func (x *ofb) XORKeyStream(dst, src []byte) { + for i, s := range src { + if x.outUsed == len(x.out) { + x.b.Encrypt(x.out, x.out) + x.outUsed = 0 + } + + dst[i] = s ^ x.out[x.outUsed] + x.outUsed++ + } +} diff --git a/src/pkg/crypto/cipher/ofb_test.go b/src/pkg/crypto/cipher/ofb_test.go new file mode 100644 index 000000000..9b4495c88 --- /dev/null +++ b/src/pkg/crypto/cipher/ofb_test.go @@ -0,0 +1,101 @@ +// Copyright 2009 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. + +// OFB AES test vectors. + +// See U.S. National Institute of Standards and Technology (NIST) +// Special Publication 800-38A, ``Recommendation for Block Cipher +// Modes of Operation,'' 2001 Edition, pp. 52-55. + +package cipher + +import ( + "bytes" + "crypto/aes" + "testing" +) + +type ofbTest struct { + name string + key []byte + iv []byte + in []byte + out []byte +} + +var ofbTests = []ofbTest{ + // NIST SP 800-38A pp 52-55 + { + "OFB-AES128", + commonKey128, + commonIV, + commonInput, + []byte{ + 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e, + }, + }, + { + "OFB-AES192", + commonKey192, + commonIV, + commonInput, + []byte{ + 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a, + }, + }, + { + "OFB-AES256", + commonKey256, + commonIV, + commonInput, + []byte{ + 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84, + }, + }, +} + +func TestOFB(t *testing.T) { + for _, tt := range ofbTests { + test := tt.name + + c, err := aes.NewCipher(tt.key) + if err != nil { + t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err) + continue + } + + for j := 0; j <= 5; j += 5 { + plaintext := tt.in[0 : len(tt.in)-j] + ofb := NewOFB(c, tt.iv) + ciphertext := make([]byte, len(plaintext)) + ofb.XORKeyStream(ciphertext, plaintext) + if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) { + t.Errorf("%s/%d: encrypting\ninput % x\nhave % x\nwant % x", test, len(plaintext), plaintext, ciphertext, tt.out) + } + } + + for j := 0; j <= 5; j += 5 { + ciphertext := tt.out[0 : len(tt.in)-j] + ofb := NewOFB(c, tt.iv) + plaintext := make([]byte, len(ciphertext)) + ofb.XORKeyStream(plaintext, ciphertext) + if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) { + t.Errorf("%s/%d: decrypting\nhave % x\nwant % x", test, len(ciphertext), plaintext, tt.in) + } + } + + if t.Failed() { + break + } + } +} diff --git a/src/pkg/crypto/crypto.go b/src/pkg/crypto/crypto.go new file mode 100644 index 000000000..be6b34adf --- /dev/null +++ b/src/pkg/crypto/crypto.go @@ -0,0 +1,73 @@ +// Copyright 2011 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. + +// The crypto package collects common cryptographic constants. +package crypto + +import ( + "hash" +) + +// Hash identifies a cryptographic hash function that is implemented in another +// package. +type Hash uint + +const ( + MD4 Hash = 1 + iota // in package crypto/md4 + MD5 // in package crypto/md5 + SHA1 // in package crypto/sha1 + SHA224 // in package crypto/sha256 + SHA256 // in package crypto/sha256 + SHA384 // in package crypto/sha512 + SHA512 // in package crypto/sha512 + MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA + RIPEMD160 // in package crypto/ripemd160 + maxHash +) + +var digestSizes = []uint8{ + MD4: 16, + MD5: 16, + SHA1: 20, + SHA224: 28, + SHA256: 32, + SHA384: 48, + SHA512: 64, + MD5SHA1: 36, + RIPEMD160: 20, +} + +// Size returns the length, in bytes, of a digest resulting from the given hash +// function. It doesn't require that the hash function in question be linked +// into the program. +func (h Hash) Size() int { + if h > 0 && h < maxHash { + return int(digestSizes[h]) + } + panic("crypto: Size of unknown hash function") +} + +var hashes = make([]func() hash.Hash, maxHash) + +// New returns a new hash.Hash calculating the given hash function. If the +// hash function is not linked into the binary, New returns nil. +func (h Hash) New() hash.Hash { + if h > 0 && h < maxHash { + f := hashes[h] + if f != nil { + return f() + } + } + return nil +} + +// RegisterHash registers a function that returns a new instance of the given +// hash function. This is intended to be called from the init function in +// packages that implement hash functions. +func RegisterHash(h Hash, f func() hash.Hash) { + if h >= maxHash { + panic("crypto: RegisterHash of unknown hash function") + } + hashes[h] = f +} diff --git a/src/pkg/crypto/dsa/Makefile b/src/pkg/crypto/dsa/Makefile new file mode 100644 index 000000000..fa89d4ab2 --- /dev/null +++ b/src/pkg/crypto/dsa/Makefile @@ -0,0 +1,11 @@ +# Copyright 2011 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. + +include ../../../Make.inc + +TARG=crypto/dsa +GOFILES=\ + dsa.go\ + +include ../../../Make.pkg diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go new file mode 100644 index 000000000..f0af8bb42 --- /dev/null +++ b/src/pkg/crypto/dsa/dsa.go @@ -0,0 +1,276 @@ +// Copyright 2011 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. + +// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3 +package dsa + +import ( + "big" + "io" + "os" +) + +// Parameters represents the domain parameters for a key. These parameters can +// be shared across many keys. The bit length of Q must be a multiple of 8. +type Parameters struct { + P, Q, G *big.Int +} + +// PublicKey represents a DSA public key. +type PublicKey struct { + Parameters + Y *big.Int +} + +// PrivateKey represents a DSA private key. +type PrivateKey struct { + PublicKey + X *big.Int +} + +type invalidPublicKeyError int + +func (invalidPublicKeyError) String() string { + return "crypto/dsa: invalid public key" +} + +// InvalidPublicKeyError results when a public key is not usable by this code. +// FIPS is quite strict about the format of DSA keys, but other code may be +// less so. Thus, when using keys which may have been generated by other code, +// this error must be handled. +var InvalidPublicKeyError = invalidPublicKeyError(0) + +// ParameterSizes is a enumeration of the acceptable bit lengths of the primes +// in a set of DSA parameters. See FIPS 186-3, section 4.2. +type ParameterSizes int + +const ( + L1024N160 ParameterSizes = iota + L2048N224 + L2048N256 + L3072N256 +) + +// numMRTests is the number of Miller-Rabin primality tests that we perform. We +// pick the largest recommended number from table C.1 of FIPS 186-3. +const numMRTests = 64 + +// GenerateParameters puts a random, valid set of DSA parameters into params. +// This function takes many seconds, even on fast machines. +func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err os.Error) { + // This function doesn't follow FIPS 186-3 exactly in that it doesn't + // use a verification seed to generate the primes. The verification + // seed doesn't appear to be exported or used by other code and + // omitting it makes the code cleaner. + + var L, N int + switch sizes { + case L1024N160: + L = 1024 + N = 160 + case L2048N224: + L = 2048 + N = 224 + case L2048N256: + L = 2048 + N = 256 + case L3072N256: + L = 3072 + N = 256 + default: + return os.ErrorString("crypto/dsa: invalid ParameterSizes") + } + + qBytes := make([]byte, N/8) + pBytes := make([]byte, L/8) + + q := new(big.Int) + p := new(big.Int) + rem := new(big.Int) + one := new(big.Int) + one.SetInt64(1) + +GeneratePrimes: + for { + _, err = io.ReadFull(rand, qBytes) + if err != nil { + return + } + + qBytes[len(qBytes)-1] |= 1 + qBytes[0] |= 0x80 + q.SetBytes(qBytes) + + if !big.ProbablyPrime(q, numMRTests) { + continue + } + + for i := 0; i < 4*L; i++ { + _, err = io.ReadFull(rand, pBytes) + if err != nil { + return + } + + pBytes[len(pBytes)-1] |= 1 + pBytes[0] |= 0x80 + + p.SetBytes(pBytes) + rem.Mod(p, q) + rem.Sub(rem, one) + p.Sub(p, rem) + if p.BitLen() < L { + continue + } + + if !big.ProbablyPrime(p, numMRTests) { + continue + } + + params.P = p + params.Q = q + break GeneratePrimes + } + } + + h := new(big.Int) + h.SetInt64(2) + g := new(big.Int) + + pm1 := new(big.Int).Sub(p, one) + e := new(big.Int).Div(pm1, q) + + for { + g.Exp(h, e, p) + if g.Cmp(one) == 0 { + h.Add(h, one) + continue + } + + params.G = g + return + } + + panic("unreachable") +} + +// GenerateKey generates a public&private key pair. The Parameters of the +// PrivateKey must already be valid (see GenerateParameters). +func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error { + if priv.P == nil || priv.Q == nil || priv.G == nil { + return os.ErrorString("crypto/dsa: parameters not set up before generating key") + } + + x := new(big.Int) + xBytes := make([]byte, priv.Q.BitLen()/8) + + for { + _, err := io.ReadFull(rand, xBytes) + if err != nil { + return err + } + x.SetBytes(xBytes) + if x.Sign() != 0 && x.Cmp(priv.Q) < 0 { + break + } + } + + priv.X = x + priv.Y = new(big.Int) + priv.Y.Exp(priv.G, x, priv.P) + return nil +} + +// Sign signs an arbitrary length hash (which should be the result of hashing a +// larger message) using the private key, priv. It returns the signature as a +// pair of integers. The security of the private key depends on the entropy of +// rand. +func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) { + // FIPS 186-3, section 4.6 + + n := priv.Q.BitLen() + if n&7 != 0 { + err = InvalidPublicKeyError + return + } + n >>= 3 + + for { + k := new(big.Int) + buf := make([]byte, n) + for { + _, err = io.ReadFull(rand, buf) + if err != nil { + return + } + k.SetBytes(buf) + if k.Sign() > 0 && k.Cmp(priv.Q) < 0 { + break + } + } + + kInv := new(big.Int).ModInverse(k, priv.Q) + + r = new(big.Int).Exp(priv.G, k, priv.P) + r.Mod(r, priv.Q) + + if r.Sign() == 0 { + continue + } + + if n > len(hash) { + n = len(hash) + } + z := k.SetBytes(hash[:n]) + + s = new(big.Int).Mul(priv.X, r) + s.Add(s, z) + s.Mod(s, priv.Q) + s.Mul(s, kInv) + s.Mod(s, priv.Q) + + if s.Sign() != 0 { + break + } + } + + return +} + +// Verify verifies the signature in r, s of hash using the public key, pub. It +// returns true iff the signature is valid. +func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { + // FIPS 186-3, section 4.7 + + if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 { + return false + } + if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 { + return false + } + + w := new(big.Int).ModInverse(s, pub.Q) + + n := pub.Q.BitLen() + if n&7 != 0 { + return false + } + n >>= 3 + + if n > len(hash) { + n = len(hash) + } + z := new(big.Int).SetBytes(hash[:n]) + + u1 := new(big.Int).Mul(z, w) + u1.Mod(u1, pub.Q) + u2 := w.Mul(r, w) + u2.Mod(u2, pub.Q) + v := u1.Exp(pub.G, u1, pub.P) + u2.Exp(pub.Y, u2, pub.P) + v.Mul(v, u2) + v.Mod(v, pub.P) + v.Mod(v, pub.Q) + + return v.Cmp(r) == 0 +} diff --git a/src/pkg/crypto/dsa/dsa_test.go b/src/pkg/crypto/dsa/dsa_test.go new file mode 100644 index 000000000..deec08dfd --- /dev/null +++ b/src/pkg/crypto/dsa/dsa_test.go @@ -0,0 +1,84 @@ +// Copyright 2011 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. + +package dsa + +import ( + "big" + "crypto/rand" + "testing" +) + +func testSignAndVerify(t *testing.T, i int, priv *PrivateKey) { + hashed := []byte("testing") + r, s, err := Sign(rand.Reader, priv, hashed) + if err != nil { + t.Errorf("%d: error signing: %s", i, err) + return + } + + if !Verify(&priv.PublicKey, hashed, r, s) { + t.Errorf("%d: Verify failed", i) + } +} + +func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) { + var priv PrivateKey + params := &priv.Parameters + + err := GenerateParameters(params, rand.Reader, sizes) + if err != nil { + t.Errorf("%d: %s", int(sizes), err) + return + } + + if params.P.BitLen() != L { + t.Errorf("%d: params.BitLen got:%d want:%d", int(sizes), params.P.BitLen(), L) + } + + if params.Q.BitLen() != N { + t.Errorf("%d: q.BitLen got:%d want:%d", int(sizes), params.Q.BitLen(), L) + } + + one := new(big.Int) + one.SetInt64(1) + pm1 := new(big.Int).Sub(params.P, one) + quo, rem := new(big.Int).DivMod(pm1, params.Q, new(big.Int)) + if rem.Sign() != 0 { + t.Errorf("%d: p-1 mod q != 0", int(sizes)) + } + x := new(big.Int).Exp(params.G, quo, params.P) + if x.Cmp(one) == 0 { + t.Errorf("%d: invalid generator", int(sizes)) + } + + err = GenerateKey(&priv, rand.Reader) + if err != nil { + t.Errorf("error generating key: %s", err) + return + } + + testSignAndVerify(t, int(sizes), &priv) +} + +func TestParameterGeneration(t *testing.T) { + // This test is too slow to run all the time. + return + + testParameterGeneration(t, L1024N160, 1024, 160) + testParameterGeneration(t, L2048N224, 2048, 224) + testParameterGeneration(t, L2048N256, 2048, 256) + testParameterGeneration(t, L3072N256, 3072, 256) +} + +func TestSignAndVerify(t *testing.T) { + var priv PrivateKey + priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) + priv.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16) + priv.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) + priv.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) + priv.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16) + + testSignAndVerify(t, 0, &priv) +} diff --git a/src/pkg/crypto/md4/md4.go b/src/pkg/crypto/md4/md4.go index e13c986e6..ee46544a9 100644 --- a/src/pkg/crypto/md4/md4.go +++ b/src/pkg/crypto/md4/md4.go @@ -6,10 +6,15 @@ package md4 import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.MD4, New) +} + // The size of an MD4 checksum in bytes. const Size = 16 diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go index 54fddb63b..8f93fc4b3 100644 --- a/src/pkg/crypto/md5/md5.go +++ b/src/pkg/crypto/md5/md5.go @@ -6,10 +6,15 @@ package md5 import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.MD5, New) +} + // The size of an MD5 checksum in bytes. const Size = 16 diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go index f3fa3bc83..f42d80888 100644 --- a/src/pkg/crypto/ocsp/ocsp.go +++ b/src/pkg/crypto/ocsp/ocsp.go @@ -9,8 +9,9 @@ package ocsp import ( "asn1" + "crypto" "crypto/rsa" - "crypto/sha1" + _ "crypto/sha1" "crypto/x509" "os" "time" @@ -168,8 +169,8 @@ func ParseResponse(bytes []byte) (*Response, os.Error) { return nil, x509.UnsupportedAlgorithmError{} } - h := sha1.New() - hashType := rsa.HashSHA1 + hashType := crypto.SHA1 + h := hashType.New() pub := ret.Certificate.PublicKey.(*rsa.PublicKey) h.Write(basicResp.TBSResponseData.Raw) diff --git a/src/pkg/crypto/openpgp/s2k/Makefile b/src/pkg/crypto/openpgp/s2k/Makefile new file mode 100644 index 000000000..731d53431 --- /dev/null +++ b/src/pkg/crypto/openpgp/s2k/Makefile @@ -0,0 +1,11 @@ +# Copyright 2011 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. + +include ../../../../Make.inc + +TARG=crypto/openpgp/s2k +GOFILES=\ + s2k.go\ + +include ../../../../Make.pkg diff --git a/src/pkg/crypto/openpgp/s2k/s2k.go b/src/pkg/crypto/openpgp/s2k/s2k.go new file mode 100644 index 000000000..f369d7ed4 --- /dev/null +++ b/src/pkg/crypto/openpgp/s2k/s2k.go @@ -0,0 +1,146 @@ +// Copyright 2011 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 package implements the various OpenPGP string-to-key transforms as +// specified in RFC 4800 section 3.7.1. +package s2k + +import ( + "crypto/md5" + "crypto/openpgp/error" + "crypto/ripemd160" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" + "hash" + "io" + "os" +) + +// Simple writes to out the result of computing the Simple S2K function (RFC +// 4880, section 3.7.1.1) using the given hash and input passphrase. +func Simple(out []byte, h hash.Hash, in []byte) { + Salted(out, h, in, nil) +} + +var zero [1]byte + +// Salted writes to out the result of computing the Salted S2K function (RFC +// 4880, section 3.7.1.2) using the given hash, input passphrase and salt. +func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { + done := 0 + + for i := 0; done < len(out); i++ { + h.Reset() + for j := 0; j < i; j++ { + h.Write(zero[:]) + } + h.Write(salt) + h.Write(in) + n := copy(out[done:], h.Sum()) + done += n + } +} + +// Iterated writes to out the result of computing the Iterated and Salted S2K +// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase, +// salt and iteration count. +func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { + combined := make([]byte, len(in)+len(salt)) + copy(combined, salt) + copy(combined[len(salt):], in) + + if count < len(combined) { + count = len(combined) + } + + done := 0 + for i := 0; done < len(out); i++ { + h.Reset() + for j := 0; j < i; j++ { + h.Write(zero[:]) + } + written := 0 + for written < count { + if written+len(combined) > count { + todo := count - written + h.Write(combined[:todo]) + written = count + } else { + h.Write(combined) + written += len(combined) + } + } + n := copy(out[done:], h.Sum()) + done += n + } +} + +// Parse reads a binary specification for a string-to-key transformation from r +// and returns a function which performs that transform. +func Parse(r io.Reader) (f func(out, in []byte), err os.Error) { + var buf [9]byte + + _, err = io.ReadFull(r, buf[:2]) + if err != nil { + return + } + + h := hashFuncFromType(buf[1]) + if h == nil { + return nil, error.UnsupportedError("hash for S2K function") + } + + switch buf[0] { + case 1: + f := func(out, in []byte) { + Simple(out, h, in) + } + return f, nil + case 2: + _, err := io.ReadFull(r, buf[:8]) + if err != nil { + return + } + f := func(out, in []byte) { + Salted(out, h, in, buf[:8]) + } + return f, nil + case 3: + _, err := io.ReadFull(r, buf[:9]) + if err != nil { + return + } + count := (16 + int(buf[8]&15)) << (uint32(buf[8]>>4) + 6) + f := func(out, in []byte) { + Iterated(out, h, in, buf[:8], count) + } + return f, nil + } + + return nil, error.UnsupportedError("S2K function") +} + +// hashFuncFromType returns a hash.Hash which corresponds to the given hash +// type byte. See RFC 4880, section 9.4. +func hashFuncFromType(hashType byte) hash.Hash { + switch hashType { + case 1: + return md5.New() + case 2: + return sha1.New() + case 3: + return ripemd160.New() + case 8: + return sha256.New() + case 9: + return sha512.New384() + case 10: + return sha512.New() + case 11: + return sha256.New224() + } + + return nil +} diff --git a/src/pkg/crypto/openpgp/s2k/s2k_test.go b/src/pkg/crypto/openpgp/s2k/s2k_test.go new file mode 100644 index 000000000..814b78627 --- /dev/null +++ b/src/pkg/crypto/openpgp/s2k/s2k_test.go @@ -0,0 +1,94 @@ +// Copyright 2011 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. + +package s2k + +import ( + "bytes" + "crypto/sha1" + "encoding/hex" + "testing" +) + +var saltedTests = []struct { + in, out string +}{ + {"hello", "10295ac1"}, + {"world", "ac587a5e"}, + {"foo", "4dda8077"}, + {"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"}, + {"x", "f1d3f289"}, + {"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"}, +} + +func TestSalted(t *testing.T) { + h := sha1.New() + salt := [4]byte{1, 2, 3, 4} + + for i, test := range saltedTests { + expected, _ := hex.DecodeString(test.out) + out := make([]byte, len(expected)) + Salted(out, h, []byte(test.in), salt[:]) + if !bytes.Equal(expected, out) { + t.Errorf("#%d, got: %x want: %x", i, out, expected) + } + } +} + + +var iteratedTests = []struct { + in, out string +}{ + {"hello", "83126105"}, + {"world", "6fa317f9"}, + {"foo", "8fbc35b9"}, + {"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"}, + {"x", "5a684dfe"}, + {"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"}, +} + +func TestIterated(t *testing.T) { + h := sha1.New() + salt := [4]byte{4, 3, 2, 1} + + for i, test := range iteratedTests { + expected, _ := hex.DecodeString(test.out) + out := make([]byte, len(expected)) + Iterated(out, h, []byte(test.in), salt[:], 31) + if !bytes.Equal(expected, out) { + t.Errorf("#%d, got: %x want: %x", i, out, expected) + } + } +} + + +var parseTests = []struct { + spec, in, out string +}{ + /* Simple with SHA1 */ + {"0102", "hello", "aaf4c61d"}, + /* Salted with SHA1 */ + {"02020102030405060708", "hello", "f4f7d67e"}, + /* Iterated with SHA1 */ + {"03020102030405060708f1", "hello", "f2a57b7c"}, +} + +func TestParse(t *testing.T) { + for i, test := range parseTests { + spec, _ := hex.DecodeString(test.spec) + buf := bytes.NewBuffer(spec) + f, err := Parse(buf) + if err != nil { + t.Errorf("%d: Parse returned error: %s", i, err) + continue + } + + expected, _ := hex.DecodeString(test.out) + out := make([]byte, len(expected)) + f(out, []byte(test.in)) + if !bytes.Equal(out, expected) { + t.Errorf("%d: output got: %x want: %x", i, out, expected) + } + } +} diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go index ff16f2554..900b57330 100644 --- a/src/pkg/crypto/rand/rand_unix.go +++ b/src/pkg/crypto/rand/rand_unix.go @@ -29,15 +29,14 @@ type devReader struct { func (r *devReader) Read(b []byte) (n int, err os.Error) { r.mu.Lock() + defer r.mu.Unlock() if r.f == nil { f, err := os.Open(r.name, os.O_RDONLY, 0) if f == nil { - r.mu.Unlock() return 0, err } r.f = f } - r.mu.Unlock() return r.f.Read(b) } diff --git a/src/pkg/crypto/ripemd160/ripemd160.go b/src/pkg/crypto/ripemd160/ripemd160.go index 5614f1360..6e88521c3 100644 --- a/src/pkg/crypto/ripemd160/ripemd160.go +++ b/src/pkg/crypto/ripemd160/ripemd160.go @@ -10,10 +10,15 @@ package ripemd160 // http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.RIPEMD160, New) +} + // The size of the checksum in bytes. const Size = 20 diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go index 714046250..2eaadee24 100644 --- a/src/pkg/crypto/rsa/pkcs1v15.go +++ b/src/pkg/crypto/rsa/pkcs1v15.go @@ -6,6 +6,7 @@ package rsa import ( "big" + "crypto" "crypto/subtle" "io" "os" @@ -139,19 +140,6 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) { return } -// Due to the design of PKCS#1 v1.5, we need to know the exact hash function in -// use. A generic hash.Hash will not do. -type PKCS1v15Hash int - -const ( - HashMD5 PKCS1v15Hash = iota - HashSHA1 - HashSHA256 - HashSHA384 - HashSHA512 - HashMD5SHA1 // combined MD5 and SHA1 hash used for RSA signing in TLS. -) - // These are ASN1 DER structures: // DigestInfo ::= SEQUENCE { // digestAlgorithm AlgorithmIdentifier, @@ -160,25 +148,20 @@ const ( // For performance, we don't use the generic ASN1 encoder. Rather, we // precompute a prefix of the digest value that makes a valid ASN1 DER string // with the correct contents. -var hashPrefixes = [][]byte{ - // HashMD5 - {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, - // HashSHA1 - {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, - // HashSHA256 - {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, - // HashSHA384 - {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, - // HashSHA512 - {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, - // HashMD5SHA1 - {}, // A special TLS case which doesn't use an ASN1 prefix. +var hashPrefixes = map[crypto.Hash][]byte{ + crypto.MD5: []byte{0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, + crypto.SHA1: []byte{0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}, + crypto.SHA256: []byte{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, + crypto.SHA384: []byte{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, + crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, + crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix. + crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14}, } -// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5. +// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. // Note that hashed must be the result of hashing the input message using the // given hash function. -func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed []byte) (s []byte, err os.Error) { +func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err os.Error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { return @@ -211,7 +194,7 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash PKCS1v15Hash, hashed [] // hashed is the result of hashing the input message using the given hash // function and sig is the signature. A valid signature is indicated by // returning a nil error. -func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte) (err os.Error) { +func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err os.Error) { hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) if err != nil { return @@ -246,28 +229,14 @@ func VerifyPKCS1v15(pub *PublicKey, hash PKCS1v15Hash, hashed []byte, sig []byte return nil } -func pkcs1v15HashInfo(hash PKCS1v15Hash, inLen int) (hashLen int, prefix []byte, err os.Error) { - switch hash { - case HashMD5: - hashLen = 16 - case HashSHA1: - hashLen = 20 - case HashSHA256: - hashLen = 32 - case HashSHA384: - hashLen = 48 - case HashSHA512: - hashLen = 64 - case HashMD5SHA1: - hashLen = 36 - default: - return 0, nil, os.ErrorString("unknown hash function") - } - +func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) { + hashLen = hash.Size() if inLen != hashLen { return 0, nil, os.ErrorString("input must be hashed message") } - - prefix = hashPrefixes[int(hash)] + prefix, ok := hashPrefixes[hash] + if !ok { + return 0, nil, os.ErrorString("unsupported hash function") + } return } diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go index bf6306dc2..7b2ce08cb 100644 --- a/src/pkg/crypto/rsa/pkcs1v15_test.go +++ b/src/pkg/crypto/rsa/pkcs1v15_test.go @@ -7,6 +7,7 @@ package rsa import ( "big" "bytes" + "crypto" "crypto/rand" "crypto/sha1" "encoding/base64" @@ -165,7 +166,7 @@ func TestSignPKCS1v15(t *testing.T) { h.Write([]byte(test.in)) digest := h.Sum() - s, err := SignPKCS1v15(nil, rsaPrivateKey, HashSHA1, digest) + s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest) if err != nil { t.Errorf("#%d %s", i, err) } @@ -185,7 +186,7 @@ func TestVerifyPKCS1v15(t *testing.T) { sig, _ := hex.DecodeString(test.out) - err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, HashSHA1, digest, sig) + err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA1, digest, sig) if err != nil { t.Errorf("#%d %s", i, err) } diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go index 8716c3591..e6aa096e2 100644 --- a/src/pkg/crypto/sha1/sha1.go +++ b/src/pkg/crypto/sha1/sha1.go @@ -6,10 +6,15 @@ package sha1 import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.SHA1, New) +} + // The size of a SHA1 checksum in bytes. const Size = 20 diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go index 57a8ffa0d..69b356b4e 100644 --- a/src/pkg/crypto/sha256/sha256.go +++ b/src/pkg/crypto/sha256/sha256.go @@ -6,10 +6,16 @@ package sha256 import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.SHA224, New224) + crypto.RegisterHash(crypto.SHA256, New) +} + // The size of a SHA256 checksum in bytes. const Size = 32 diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go index c3cda97d9..7e9f330e5 100644 --- a/src/pkg/crypto/sha512/sha512.go +++ b/src/pkg/crypto/sha512/sha512.go @@ -6,10 +6,16 @@ package sha512 import ( + "crypto" "hash" "os" ) +func init() { + crypto.RegisterHash(crypto.SHA384, New384) + crypto.RegisterHash(crypto.SHA512, New) +} + // The size of a SHA512 checksum in bytes. const Size = 64 diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go index 1ca33f59d..19d2bfa3b 100644 --- a/src/pkg/crypto/tls/handshake_client.go +++ b/src/pkg/crypto/tls/handshake_client.go @@ -5,6 +5,7 @@ package tls import ( + "crypto" "crypto/rsa" "crypto/subtle" "crypto/x509" @@ -248,7 +249,7 @@ func (c *Conn) clientHandshake() os.Error { var digest [36]byte copy(digest[0:16], finishedHash.serverMD5.Sum()) copy(digest[16:36], finishedHash.serverSHA1.Sum()) - signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:]) + signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:]) if err != nil { return c.sendAlert(alertInternalError) } diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go index 955811ada..af46ea511 100644 --- a/src/pkg/crypto/tls/handshake_server.go +++ b/src/pkg/crypto/tls/handshake_server.go @@ -5,6 +5,7 @@ package tls import ( + "crypto" "crypto/rsa" "crypto/subtle" "crypto/x509" @@ -213,7 +214,7 @@ Curves: digest := make([]byte, 36) copy(digest[0:16], finishedHash.serverMD5.Sum()) copy(digest[16:36], finishedHash.serverSHA1.Sum()) - err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature) + err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature) if err != nil { c.sendAlert(alertBadCertificate) return os.ErrorString("could not validate signature of connection nonces: " + err.String()) diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go index 861c64f04..8edbb1190 100644 --- a/src/pkg/crypto/tls/key_agreement.go +++ b/src/pkg/crypto/tls/key_agreement.go @@ -6,6 +6,7 @@ package tls import ( "big" + "crypto" "crypto/elliptic" "crypto/md5" "crypto/rsa" @@ -143,7 +144,7 @@ Curve: copy(serverECDHParams[4:], ecdhePublic) md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams) - sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, md5sha1) + sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1) if err != nil { return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String()) } @@ -216,7 +217,7 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH sig = sig[2:] md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams) - return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), rsa.HashMD5SHA1, md5sha1, sig) + return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig) Error: return os.ErrorString("invalid ServerKeyExchange") diff --git a/src/pkg/crypto/twofish/twofish.go b/src/pkg/crypto/twofish/twofish.go index b362c44d2..62253e797 100644 --- a/src/pkg/crypto/twofish/twofish.go +++ b/src/pkg/crypto/twofish/twofish.go @@ -51,9 +51,9 @@ func NewCipher(key []byte) (*Cipher, os.Error) { var S [4 * 4]byte for i := 0; i < k; i++ { // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7] - for j := 0; j < 4; j++ { - for k := 0; k < 8; k++ { - S[4*i+j] ^= gfMult(key[8*i+k], rs[j][k], rsPolynomial) + for j, rsRow := range rs { + for k, rsVal := range rsRow { + S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial) } } } @@ -63,13 +63,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) { var tmp [4]byte for i := byte(0); i < 20; i++ { // A = h(p * 2x, Me) - for j := 0; j < 4; j++ { + for j := range tmp { tmp[j] = 2 * i } A := h(tmp[:], key, 0) // B = rolc(h(p * (2x + 1), Mo), 8) - for j := 0; j < 4; j++ { + for j := range tmp { tmp[j] = 2*i + 1 } B := h(tmp[:], key, 1) @@ -84,21 +84,21 @@ func NewCipher(key []byte) (*Cipher, os.Error) { // Calculate sboxes switch k { case 2: - for i := 0; i <= 255; i++ { + for i := range c.s[0] { c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0) c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1) c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2) c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3) } case 3: - for i := 0; i < 256; i++ { + for i := range c.s[0] { c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0) c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1) c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2) c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3) } default: - for i := 0; i < 256; i++ { + for i := range c.s[0] { c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0) c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1) c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2) @@ -112,10 +112,10 @@ func NewCipher(key []byte) (*Cipher, os.Error) { // Reset zeros the key data, so that it will no longer appear in the process's // memory. func (c *Cipher) Reset() { - for i := 0; i < 40; i++ { + for i := range c.k { c.k[i] = 0 } - for i := 0; i < 4; i++ { + for i := range c.s { for j := 0; j < 265; j++ { c.s[i][j] = 0 } @@ -213,7 +213,7 @@ func gfMult(a, b byte, p uint32) byte { return byte(result) } -// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS . [x0] +// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0] func mdsColumnMult(in byte, col int) uint32 { mul01 := in mul5B := gfMult(in, 0x5B, mdsPolynomial) @@ -236,7 +236,7 @@ func mdsColumnMult(in byte, col int) uint32 { // h implements the S-box generation function. See [TWOFISH] 4.3.5 func h(in, key []byte, offset int) uint32 { var y [4]byte - for x := 0; x < 4; x++ { + for x := range y { y[x] = in[x] } switch len(key) / 8 { @@ -260,7 +260,7 @@ func h(in, key []byte, offset int) uint32 { } // [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3] var mdsMult uint32 - for i := 0; i < 4; i++ { + for i := range y { mdsMult ^= mdsColumnMult(y[i], i) } return mdsMult @@ -270,42 +270,42 @@ func h(in, key []byte, offset int) uint32 { // Note that for amounts of data larger than a block, // it is not safe to just call Encrypt on successive blocks; // instead, use an encryption mode like CBC (see crypto/block/cbc.go). -func (skey *Cipher) Encrypt(dst, src []byte) { - S1 := skey.s[0] - S2 := skey.s[1] - S3 := skey.s[2] - S4 := skey.s[3] +func (c *Cipher) Encrypt(dst, src []byte) { + S1 := c.s[0] + S2 := c.s[1] + S3 := c.s[2] + S4 := c.s[3] // Load input - a := load32l(src[0:4]) - b := load32l(src[4:8]) - c := load32l(src[8:12]) - d := load32l(src[12:16]) + ia := load32l(src[0:4]) + ib := load32l(src[4:8]) + ic := load32l(src[8:12]) + id := load32l(src[12:16]) // Pre-whitening - a ^= skey.k[0] - b ^= skey.k[1] - c ^= skey.k[2] - d ^= skey.k[3] + ia ^= c.k[0] + ib ^= c.k[1] + ic ^= c.k[2] + id ^= c.k[3] for i := 0; i < 8; i++ { - k := skey.k[8+i*4 : 12+i*4] - t2 := S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)] - t1 := S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2 - c = ror(c^(t1+k[0]), 1) - d = rol(d, 1) ^ (t2 + t1 + k[1]) - - t2 = S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)] - t1 = S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2 - a = ror(a^(t1+k[2]), 1) - b = rol(b, 1) ^ (t2 + t1 + k[3]) + k := c.k[8+i*4 : 12+i*4] + t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)] + t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2 + ic = ror(ic^(t1+k[0]), 1) + id = rol(id, 1) ^ (t2 + t1 + k[1]) + + t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)] + t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2 + ia = ror(ia^(t1+k[2]), 1) + ib = rol(ib, 1) ^ (t2 + t1 + k[3]) } // Output with "undo last swap" - ta := c ^ skey.k[4] - tb := d ^ skey.k[5] - tc := a ^ skey.k[6] - td := b ^ skey.k[7] + ta := ic ^ c.k[4] + tb := id ^ c.k[5] + tc := ia ^ c.k[6] + td := ib ^ c.k[7] store32l(dst[0:4], ta) store32l(dst[4:8], tb) @@ -314,11 +314,11 @@ func (skey *Cipher) Encrypt(dst, src []byte) { } // Decrypt decrypts a 16-byte block from src to dst, which may overlap. -func (skey *Cipher) Decrypt(dst, src []byte) { - S1 := skey.s[0] - S2 := skey.s[1] - S3 := skey.s[2] - S4 := skey.s[3] +func (c *Cipher) Decrypt(dst, src []byte) { + S1 := c.s[0] + S2 := c.s[1] + S3 := c.s[2] + S4 := c.s[3] // Load input ta := load32l(src[0:4]) @@ -327,32 +327,32 @@ func (skey *Cipher) Decrypt(dst, src []byte) { td := load32l(src[12:16]) // Undo undo final swap - a := tc ^ skey.k[6] - b := td ^ skey.k[7] - c := ta ^ skey.k[4] - d := tb ^ skey.k[5] + ia := tc ^ c.k[6] + ib := td ^ c.k[7] + ic := ta ^ c.k[4] + id := tb ^ c.k[5] for i := 8; i > 0; i-- { - k := skey.k[4+i*4 : 8+i*4] - t2 := S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)] - t1 := S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2 - a = rol(a, 1) ^ (t1 + k[2]) - b = ror(b^(t2+t1+k[3]), 1) - - t2 = S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)] - t1 = S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2 - c = rol(c, 1) ^ (t1 + k[0]) - d = ror(d^(t2+t1+k[1]), 1) + k := c.k[4+i*4 : 8+i*4] + t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)] + t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2 + ia = rol(ia, 1) ^ (t1 + k[2]) + ib = ror(ib^(t2+t1+k[3]), 1) + + t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)] + t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2 + ic = rol(ic, 1) ^ (t1 + k[0]) + id = ror(id^(t2+t1+k[1]), 1) } // Undo pre-whitening - a ^= skey.k[0] - b ^= skey.k[1] - c ^= skey.k[2] - d ^= skey.k[3] - - store32l(dst[0:4], a) - store32l(dst[4:8], b) - store32l(dst[8:12], c) - store32l(dst[12:16], d) + ia ^= c.k[0] + ib ^= c.k[1] + ic ^= c.k[2] + id ^= c.k[3] + + store32l(dst[0:4], ia) + store32l(dst[4:8], ib) + store32l(dst[8:12], ic) + store32l(dst[12:16], id) } diff --git a/src/pkg/crypto/twofish/twofish_test.go b/src/pkg/crypto/twofish/twofish_test.go index 96ca6797a..303081f3f 100644 --- a/src/pkg/crypto/twofish/twofish_test.go +++ b/src/pkg/crypto/twofish/twofish_test.go @@ -37,8 +37,8 @@ func genSbox(qi int, x byte) byte { } func TestSbox(t *testing.T) { - for n := 0; n < 2; n++ { - for m := 0; m < 256; m++ { + for n := range sbox { + for m := range sbox[n] { if genSbox(n, byte(m)) != sbox[n][m] { t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m))) } diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go index 6199e8db9..599263432 100644 --- a/src/pkg/crypto/x509/x509.go +++ b/src/pkg/crypto/x509/x509.go @@ -9,6 +9,7 @@ import ( "asn1" "big" "container/vector" + "crypto" "crypto/rsa" "crypto/sha1" "hash" @@ -374,12 +375,12 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) { // TODO(agl): don't ignore the path length constraint. var h hash.Hash - var hashType rsa.PKCS1v15Hash + var hashType crypto.Hash switch c.SignatureAlgorithm { case SHA1WithRSA: h = sha1.New() - hashType = rsa.HashSHA1 + hashType = crypto.SHA1 default: return UnsupportedAlgorithmError{} } @@ -840,7 +841,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P h.Write(tbsCertContents) digest := h.Sum() - signature, err := rsa.SignPKCS1v15(rand, priv, rsa.HashSHA1, digest) + signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) if err != nil { return } diff --git a/src/pkg/debug/dwarf/testdata/typedef.c b/src/pkg/debug/dwarf/testdata/typedef.c index 2ceb00ced..664d021ce 100644 --- a/src/pkg/debug/dwarf/testdata/typedef.c +++ b/src/pkg/debug/dwarf/testdata/typedef.c @@ -9,6 +9,7 @@ gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o OS X Mach-O: gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho */ +#include <complex.h> typedef volatile int* t_ptr_volatile_int; typedef const char *t_ptr_const_char; @@ -16,6 +17,9 @@ typedef long t_long; typedef unsigned short t_ushort; typedef int t_func_int_of_float_double(float, double); typedef int (*t_ptr_func_int_of_float_double)(float, double); +typedef int (*t_ptr_func_int_of_float_complex)(float complex); +typedef int (*t_ptr_func_int_of_double_complex)(double complex); +typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex); typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char); typedef void t_func_void_of_char(char); typedef void t_func_void_of_void(void); @@ -65,6 +69,9 @@ t_my_union *a12a; t_my_enum *a13; t_my_list *a14; t_my_tree *a15; +t_ptr_func_int_of_float_complex *a16; +t_ptr_func_int_of_double_complex *a17; +t_ptr_func_int_of_long_double_complex *a18; int main() { diff --git a/src/pkg/debug/dwarf/testdata/typedef.elf b/src/pkg/debug/dwarf/testdata/typedef.elf Binary files differindex ea9291fce..44df8da9b 100755 --- a/src/pkg/debug/dwarf/testdata/typedef.elf +++ b/src/pkg/debug/dwarf/testdata/typedef.elf diff --git a/src/pkg/debug/dwarf/testdata/typedef.macho b/src/pkg/debug/dwarf/testdata/typedef.macho Binary files differindex bf1dfd20e..41019c1e1 100644 --- a/src/pkg/debug/dwarf/testdata/typedef.macho +++ b/src/pkg/debug/dwarf/testdata/typedef.macho diff --git a/src/pkg/debug/dwarf/type_test.go b/src/pkg/debug/dwarf/type_test.go index 6c2daaa56..e01f7353a 100644 --- a/src/pkg/debug/dwarf/type_test.go +++ b/src/pkg/debug/dwarf/type_test.go @@ -12,21 +12,24 @@ import ( ) var typedefTests = map[string]string{ - "t_ptr_volatile_int": "*volatile int", - "t_ptr_const_char": "*const char", - "t_long": "long int", - "t_ushort": "short unsigned int", - "t_func_int_of_float_double": "func(float, double) int", - "t_ptr_func_int_of_float_double": "*func(float, double) int", - "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int", - "t_func_void_of_char": "func(char) void", - "t_func_void_of_void": "func() void", - "t_func_void_of_ptr_char_dots": "func(*char, ...) void", - "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}", - "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}", - "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}", - "t_my_list": "struct list {val short int@0; next *t_my_list@8}", - "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}", + "t_ptr_volatile_int": "*volatile int", + "t_ptr_const_char": "*const char", + "t_long": "long int", + "t_ushort": "short unsigned int", + "t_func_int_of_float_double": "func(float, double) int", + "t_ptr_func_int_of_float_double": "*func(float, double) int", + "t_ptr_func_int_of_float_complex": "*func(complex float) int", + "t_ptr_func_int_of_double_complex": "*func(complex double) int", + "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int", + "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int", + "t_func_void_of_char": "func(char) void", + "t_func_void_of_void": "func() void", + "t_func_void_of_ptr_char_dots": "func(*char, ...) void", + "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; array [40]long long int@8}", + "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}", + "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}", + "t_my_list": "struct list {val short int@0; next *t_my_list@8}", + "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}", } func elfData(t *testing.T, name string) *Data { diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go index 904d2f863..82c02407b 100644 --- a/src/pkg/debug/pe/file.go +++ b/src/pkg/debug/pe/file.go @@ -49,6 +49,17 @@ type Section struct { sr *io.SectionReader } +type ImportDirectory struct { + OriginalFirstThunk uint32 + TimeDateStamp uint32 + ForwarderChain uint32 + Name uint32 + FirstThunk uint32 + + dll string + rva []uint32 +} + // Data reads and returns the contents of the PE section. func (s *Section) Data() ([]byte, os.Error) { dat := make([]byte, s.sr.Size()) @@ -229,3 +240,70 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { abbrev, info, str := dat[0], dat[1], dat[2] return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) } + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +// It does not return weak symbols. +func (f *File) ImportedSymbols() ([]string, os.Error) { + ds := f.Section(".idata") + if ds == nil { + // not dynamic, so no libraries + return nil, nil + } + d, err := ds.Data() + if err != nil { + return nil, err + } + var ida []ImportDirectory + for len(d) > 0 { + var dt ImportDirectory + dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4]) + dt.Name = binary.LittleEndian.Uint32(d[12:16]) + dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20]) + d = d[20:] + if dt.OriginalFirstThunk == 0 { + break + } + ida = append(ida, dt) + } + for i, _ := range ida { + for len(d) > 0 { + va := binary.LittleEndian.Uint32(d[0:4]) + d = d[4:] + if va == 0 { + break + } + ida[i].rva = append(ida[i].rva, va) + } + } + for _, _ = range ida { + for len(d) > 0 { + va := binary.LittleEndian.Uint32(d[0:4]) + d = d[4:] + if va == 0 { + break + } + } + } + names, _ := ds.Data() + var all []string + for _, dt := range ida { + dt.dll, _ = getString(names, int(dt.Name-ds.VirtualAddress)) + for _, va := range dt.rva { + fn, _ := getString(names, int(va-ds.VirtualAddress+2)) + all = append(all, fn+":"+dt.dll) + } + } + + return all, nil +} + +// ImportedLibraries returns the names of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, os.Error) { + // TODO + // cgo -dynimport don't use this for windows PE, so just return. + return nil, nil +} diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go index ef72d91fd..c38530177 100644 --- a/src/pkg/ebnf/parser.go +++ b/src/pkg/ebnf/parser.go @@ -177,7 +177,7 @@ func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar // initialize parser p.fset = fset p.ErrorVector.Reset() - p.scanner.Init(fset, filename, src, p, 0) + p.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, 0) p.next() // initializes pos, tok, lit grammar := make(Grammar) diff --git a/src/pkg/encoding/base32/Makefile b/src/pkg/encoding/base32/Makefile new file mode 100644 index 000000000..c0e85b644 --- /dev/null +++ b/src/pkg/encoding/base32/Makefile @@ -0,0 +1,11 @@ +# Copyright 2009 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. + +include $(GOROOT)/src/Make.inc + +TARG=encoding/base32 +GOFILES=\ + base32.go\ + +include $(GOROOT)/src/Make.pkg diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go new file mode 100644 index 000000000..acace30d6 --- /dev/null +++ b/src/pkg/encoding/base32/base32.go @@ -0,0 +1,368 @@ +// Copyright 2011 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. + +// Package base32 implements base32 encoding as specified by RFC 4648. +package base32 + +import ( + "io" + "os" + "strconv" +) + +/* + * Encodings + */ + +// An Encoding is a radix 32 encoding/decoding scheme, defined by a +// 32-character alphabet. The most common is the "base32" encoding +// introduced for SASL GSSAPI and standardized in RFC 4648. +// The alternate "base32hex" encoding is used in DNSSEC. +type Encoding struct { + encode string + decodeMap [256]byte +} + +const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" +const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV" + +// NewEncoding returns a new Encoding defined by the given alphabet, +// which must be a 32-byte string. +func NewEncoding(encoder string) *Encoding { + e := new(Encoding) + e.encode = encoder + for i := 0; i < len(e.decodeMap); i++ { + e.decodeMap[i] = 0xFF + } + for i := 0; i < len(encoder); i++ { + e.decodeMap[encoder[i]] = byte(i) + } + return e +} + +// StdEncoding is the standard base32 encoding, as defined in +// RFC 4648. +var StdEncoding = NewEncoding(encodeStd) + +// HexEncoding is the ``Extended Hex Alphabet'' defined in RFC 4648. +// It is typically used in DNS. +var HexEncoding = NewEncoding(encodeHex) + +/* + * Encoder + */ + +// Encode encodes src using the encoding enc, writing +// EncodedLen(len(src)) bytes to dst. +// +// The encoding pads the output to a multiple of 8 bytes, +// so Encode is not appropriate for use on individual blocks +// of a large data stream. Use NewEncoder() instead. +func (enc *Encoding) Encode(dst, src []byte) { + if len(src) == 0 { + return + } + + for len(src) > 0 { + dst[0] = 0 + dst[1] = 0 + dst[2] = 0 + dst[3] = 0 + dst[4] = 0 + dst[5] = 0 + dst[6] = 0 + dst[7] = 0 + + // Unpack 8x 5-bit source blocks into a 5 byte + // destination quantum + switch len(src) { + default: + dst[7] |= src[4] & 0x1F + dst[6] |= src[4] >> 5 + fallthrough + case 4: + dst[6] |= (src[3] << 3) & 0x1F + dst[5] |= (src[3] >> 2) & 0x1F + dst[4] |= src[3] >> 7 + fallthrough + case 3: + dst[4] |= (src[2] << 1) & 0x1F + dst[3] |= (src[2] >> 4) & 0x1F + fallthrough + case 2: + dst[3] |= (src[1] << 4) & 0x1F + dst[2] |= (src[1] >> 1) & 0x1F + dst[1] |= (src[1] >> 6) & 0x1F + fallthrough + case 1: + dst[1] |= (src[0] << 2) & 0x1F + dst[0] |= src[0] >> 3 + } + + // Encode 5-bit blocks using the base32 alphabet + for j := 0; j < 8; j++ { + dst[j] = enc.encode[dst[j]] + } + + // Pad the final quantum + if len(src) < 5 { + dst[7] = '=' + if len(src) < 4 { + dst[6] = '=' + dst[5] = '=' + if len(src) < 3 { + dst[4] = '=' + if len(src) < 2 { + dst[3] = '=' + dst[2] = '=' + } + } + } + break + } + src = src[5:] + dst = dst[8:] + } +} + +type encoder struct { + err os.Error + enc *Encoding + w io.Writer + buf [5]byte // buffered data waiting to be encoded + nbuf int // number of bytes in buf + out [1024]byte // output buffer +} + +func (e *encoder) Write(p []byte) (n int, err os.Error) { + if e.err != nil { + return 0, e.err + } + + // Leading fringe. + if e.nbuf > 0 { + var i int + for i = 0; i < len(p) && e.nbuf < 5; i++ { + e.buf[e.nbuf] = p[i] + e.nbuf++ + } + n += i + p = p[i:] + if e.nbuf < 5 { + return + } + e.enc.Encode(e.out[0:], e.buf[0:]) + if _, e.err = e.w.Write(e.out[0:8]); e.err != nil { + return n, e.err + } + e.nbuf = 0 + } + + // Large interior chunks. + for len(p) >= 5 { + nn := len(e.out) / 8 * 5 + if nn > len(p) { + nn = len(p) + } + nn -= nn % 5 + if nn > 0 { + e.enc.Encode(e.out[0:], p[0:nn]) + if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil { + return n, e.err + } + } + n += nn + p = p[nn:] + } + + // Trailing fringe. + for i := 0; i < len(p); i++ { + e.buf[i] = p[i] + } + e.nbuf = len(p) + n += len(p) + return +} + +// Close flushes any pending output from the encoder. +// It is an error to call Write after calling Close. +func (e *encoder) Close() os.Error { + // If there's anything left in the buffer, flush it out + if e.err == nil && e.nbuf > 0 { + e.enc.Encode(e.out[0:], e.buf[0:e.nbuf]) + e.nbuf = 0 + _, e.err = e.w.Write(e.out[0:8]) + } + return e.err +} + +// NewEncoder returns a new base32 stream encoder. Data written to +// the returned writer will be encoded using enc and then written to w. +// Base32 encodings operate in 5-byte blocks; when finished +// writing, the caller must Close the returned encoder to flush any +// partially written blocks. +func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser { + return &encoder{enc: enc, w: w} +} + +// EncodedLen returns the length in bytes of the base32 encoding +// of an input buffer of length n. +func (enc *Encoding) EncodedLen(n int) int { return (n + 4) / 5 * 8 } + +/* + * Decoder + */ + +type CorruptInputError int64 + +func (e CorruptInputError) String() string { + return "illegal base32 data at input byte " + strconv.Itoa64(int64(e)) +} + +// decode is like Decode but returns an additional 'end' value, which +// indicates if end-of-message padding was encountered and thus any +// additional data is an error. decode also assumes len(src)%8==0, +// since it is meant for internal use. +func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err os.Error) { + for i := 0; i < len(src)/8 && !end; i++ { + // Decode quantum using the base32 alphabet + var dbuf [8]byte + dlen := 8 + + // do the top bytes contain any data? + dbufloop: + for j := 0; j < 8; j++ { + in := src[i*8+j] + if in == '=' && j >= 2 && i == len(src)/8-1 { + // We've reached the end and there's + // padding, the rest should be padded + for k := j; k < 8; k++ { + if src[i*8+k] != '=' { + return n, false, CorruptInputError(i*8 + j) + } + } + dlen = j + end = true + break dbufloop + } + dbuf[j] = enc.decodeMap[in] + if dbuf[j] == 0xFF { + return n, false, CorruptInputError(i*8 + j) + } + } + + // Pack 8x 5-bit source blocks into 5 byte destination + // quantum + switch dlen { + case 7, 8: + dst[i*5+4] = dbuf[6]<<5 | dbuf[7] + fallthrough + case 6, 5: + dst[i*5+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3 + fallthrough + case 4: + dst[i*5+2] = dbuf[3]<<4 | dbuf[4]>>1 + fallthrough + case 3: + dst[i*5+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4 + fallthrough + case 2: + dst[i*5+0] = dbuf[0]<<3 | dbuf[1]>>2 + } + switch dlen { + case 2: + n += 1 + case 3, 4: + n += 2 + case 5: + n += 3 + case 6, 7: + n += 4 + case 8: + n += 5 + } + } + return n, end, nil +} + +// Decode decodes src using the encoding enc. It writes at most +// DecodedLen(len(src)) bytes to dst and returns the number of bytes +// written. If src contains invalid base32 data, it will return the +// number of bytes successfully written and CorruptInputError. +func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) { + if len(src)%8 != 0 { + return 0, CorruptInputError(len(src) / 8 * 8) + } + + n, _, err = enc.decode(dst, src) + return +} + +type decoder struct { + err os.Error + enc *Encoding + r io.Reader + end bool // saw end of message + buf [1024]byte // leftover input + nbuf int + out []byte // leftover decoded output + outbuf [1024 / 8 * 5]byte +} + +func (d *decoder) Read(p []byte) (n int, err os.Error) { + if d.err != nil { + return 0, d.err + } + + // Use leftover decoded output from last read. + if len(d.out) > 0 { + n = copy(p, d.out) + d.out = d.out[n:] + return n, nil + } + + // Read a chunk. + nn := len(p) / 5 * 8 + if nn < 8 { + nn = 8 + } + if nn > len(d.buf) { + nn = len(d.buf) + } + nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf) + d.nbuf += nn + if d.nbuf < 8 { + return 0, d.err + } + + // Decode chunk into p, or d.out and then p if p is too small. + nr := d.nbuf / 8 * 8 + nw := d.nbuf / 8 * 5 + if nw > len(p) { + nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr]) + d.out = d.outbuf[0:nw] + n = copy(p, d.out) + d.out = d.out[n:] + } else { + n, d.end, d.err = d.enc.decode(p, d.buf[0:nr]) + } + d.nbuf -= nr + for i := 0; i < d.nbuf; i++ { + d.buf[i] = d.buf[i+nr] + } + + if d.err == nil { + d.err = err + } + return n, d.err +} + +// NewDecoder constructs a new base32 stream decoder. +func NewDecoder(enc *Encoding, r io.Reader) io.Reader { + return &decoder{enc: enc, r: r} +} + +// DecodedLen returns the maximum length in bytes of the decoded data +// corresponding to n bytes of base32-encoded data. +func (enc *Encoding) DecodedLen(n int) int { return n / 8 * 5 } diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go new file mode 100644 index 000000000..792e4dc63 --- /dev/null +++ b/src/pkg/encoding/base32/base32_test.go @@ -0,0 +1,194 @@ +// Copyright 2009 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. + +package base32 + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +type testpair struct { + decoded, encoded string +} + +var pairs = []testpair{ + // RFC 4648 examples + {"", ""}, + {"f", "MY======"}, + {"fo", "MZXQ===="}, + {"foo", "MZXW6==="}, + {"foob", "MZXW6YQ="}, + {"fooba", "MZXW6YTB"}, + {"foobar", "MZXW6YTBOI======"}, + + + // Wikipedia examples, converted to base32 + {"sure.", "ON2XEZJO"}, + {"sure", "ON2XEZI="}, + {"sur", "ON2XE==="}, + {"su", "ON2Q===="}, + {"leasure.", "NRSWC43VOJSS4==="}, + {"easure.", "MVQXG5LSMUXA===="}, + {"asure.", "MFZXK4TFFY======"}, + {"sure.", "ON2XEZJO"}, +} + +var bigtest = testpair{ + "Twas brillig, and the slithy toves", + "KR3WC4ZAMJZGS3DMNFTSYIDBNZSCA5DIMUQHG3DJORUHSIDUN53GK4Y=", +} + +func testEqual(t *testing.T, msg string, args ...interface{}) bool { + if args[len(args)-2] != args[len(args)-1] { + t.Errorf(msg, args...) + return false + } + return true +} + +func TestEncode(t *testing.T) { + for _, p := range pairs { + buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded))) + StdEncoding.Encode(buf, []byte(p.decoded)) + testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded) + } +} + +func TestEncoder(t *testing.T) { + for _, p := range pairs { + bb := &bytes.Buffer{} + encoder := NewEncoder(StdEncoding, bb) + encoder.Write([]byte(p.decoded)) + encoder.Close() + testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded) + } +} + +func TestEncoderBuffering(t *testing.T) { + input := []byte(bigtest.decoded) + for bs := 1; bs <= 12; bs++ { + bb := &bytes.Buffer{} + encoder := NewEncoder(StdEncoding, bb) + for pos := 0; pos < len(input); pos += bs { + end := pos + bs + if end > len(input) { + end = len(input) + } + n, err := encoder.Write(input[pos:end]) + testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, os.Error(nil)) + testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos) + } + err := encoder.Close() + testEqual(t, "Close gave error %v, want %v", err, os.Error(nil)) + testEqual(t, "Encoding/%d of %q = %q, want %q", bs, bigtest.decoded, bb.String(), bigtest.encoded) + } +} + +func TestDecode(t *testing.T) { + for _, p := range pairs { + dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded))) + count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded)) + testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, os.Error(nil)) + testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded)) + if len(p.encoded) > 0 { + testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '=')) + } + testEqual(t, "Decode(%q) = %q, want %q", p.encoded, + string(dbuf[0:count]), + p.decoded) + } +} + +func TestDecoder(t *testing.T) { + for _, p := range pairs { + decoder := NewDecoder(StdEncoding, bytes.NewBufferString(p.encoded)) + dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded))) + count, err := decoder.Read(dbuf) + if err != nil && err != os.EOF { + t.Fatal("Read failed", err) + } + testEqual(t, "Read from %q = length %v, want %v", p.encoded, count, len(p.decoded)) + testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) + if err != os.EOF { + count, err = decoder.Read(dbuf) + } + testEqual(t, "Read from %q = %v, want %v", p.encoded, err, os.EOF) + } +} + +func TestDecoderBuffering(t *testing.T) { + for bs := 1; bs <= 12; bs++ { + decoder := NewDecoder(StdEncoding, bytes.NewBufferString(bigtest.encoded)) + buf := make([]byte, len(bigtest.decoded)+12) + var total int + for total = 0; total < len(bigtest.decoded); { + n, err := decoder.Read(buf[total : total+bs]) + testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", bigtest.encoded, total, n, err, os.Error(nil)) + total += n + } + testEqual(t, "Decoding/%d of %q = %q, want %q", bs, bigtest.encoded, string(buf[0:total]), bigtest.decoded) + } +} + +func TestDecodeCorrupt(t *testing.T) { + type corrupt struct { + e string + p int + } + examples := []corrupt{ + {"!!!!", 0}, + {"x===", 0}, + {"AA=A====", 2}, + {"AAA=AAAA", 3}, + {"MMMMMMMMM", 8}, + {"MMMMMM", 0}, + } + + for _, e := range examples { + dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e))) + _, err := StdEncoding.Decode(dbuf, []byte(e.e)) + switch err := err.(type) { + case CorruptInputError: + testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p) + default: + t.Error("Decoder failed to detect corruption in", e) + } + } +} + +func TestBig(t *testing.T) { + n := 3*1000 + 1 + raw := make([]byte, n) + const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + for i := 0; i < n; i++ { + raw[i] = alpha[i%len(alpha)] + } + encoded := new(bytes.Buffer) + w := NewEncoder(StdEncoding, encoded) + nn, err := w.Write(raw) + if nn != n || err != nil { + t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n) + } + err = w.Close() + if err != nil { + t.Fatalf("Encoder.Close() = %v want nil", err) + } + decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded)) + if err != nil { + t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err) + } + + if !bytes.Equal(raw, decoded) { + var i int + for i = 0; i < len(decoded) && i < len(raw); i++ { + if decoded[i] != raw[i] { + break + } + } + t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i) + } +} diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go index 6bbe7eb89..77ff3a9f3 100644 --- a/src/pkg/encoding/binary/binary.go +++ b/src/pkg/encoding/binary/binary.go @@ -199,7 +199,7 @@ func sizeof(v reflect.Type) int { case *reflect.UintType, *reflect.IntType, *reflect.FloatType, *reflect.ComplexType: switch t := t.Kind(); t { - case reflect.Int, reflect.Uint, reflect.Uintptr, reflect.Float, reflect.Complex: + case reflect.Int, reflect.Uint, reflect.Uintptr: return -1 } return int(v.Size()) @@ -331,12 +331,12 @@ func (d *decoder) value(v reflect.Value) { case *reflect.ComplexValue: switch v.Type().Kind() { case reflect.Complex64: - v.Set(cmplx( + v.Set(complex( float64(math.Float32frombits(d.uint32())), float64(math.Float32frombits(d.uint32())), )) case reflect.Complex128: - v.Set(cmplx( + v.Set(complex( math.Float64frombits(d.uint64()), math.Float64frombits(d.uint64()), )) diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go index c378413f1..e09ec489f 100644 --- a/src/pkg/encoding/binary/binary_test.go +++ b/src/pkg/encoding/binary/binary_test.go @@ -31,8 +31,6 @@ type Struct struct { type T struct { Int int Uint uint - Float float - Complex complex Uintptr uintptr Array [4]int } @@ -49,11 +47,11 @@ var s = Struct{ math.Float32frombits(0x1f202122), math.Float64frombits(0x232425262728292a), - cmplx( + complex( math.Float32frombits(0x2b2c2d2e), math.Float32frombits(0x2f303132), ), - cmplx( + complex( math.Float64frombits(0x333435363738393a), math.Float64frombits(0x3b3c3d3e3f404142), ), diff --git a/src/pkg/encoding/line/line.go b/src/pkg/encoding/line/line.go index 92dddcb99..779b5758a 100644 --- a/src/pkg/encoding/line/line.go +++ b/src/pkg/encoding/line/line.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This package implements a Reader which handles reading \r and \r\n -// deliminated lines. +// The line package implements a Reader that reads lines delimited by '\n' or ' \r\n'. package line import ( @@ -11,8 +10,7 @@ import ( "os" ) -// Reader reads lines from an io.Reader (which may use either '\n' or -// '\r\n'). +// Reader reads lines, delimited by '\n' or \r\n', from an io.Reader. type Reader struct { buf []byte consumed int @@ -20,11 +18,33 @@ type Reader struct { err os.Error } -func NewReader(in io.Reader, maxLineLength int) *Reader { +// NewReader returns a new Reader that will read successive +// lines from the input Reader. +func NewReader(input io.Reader, maxLineLength int) *Reader { return &Reader{ buf: make([]byte, 0, maxLineLength), consumed: 0, - in: in, + in: input, + } +} + +// Read reads from any buffered data past the last line read, or from the underlying +// io.Reader if the buffer is empty. +func (l *Reader) Read(p []byte) (n int, err os.Error) { + l.removeConsumedFromBuffer() + if len(l.buf) > 0 { + n = copy(p, l.buf) + l.consumed += n + return + } + return l.in.Read(p) +} + +func (l *Reader) removeConsumedFromBuffer() { + if l.consumed > 0 { + n := copy(l.buf, l.buf[l.consumed:]) + l.buf = l.buf[:n] + l.consumed = 0 } } @@ -36,11 +56,7 @@ func NewReader(in io.Reader, maxLineLength int) *Reader { // the Reader and is only valid until the next call to ReadLine. ReadLine // either returns a non-nil line or it returns an error, never both. func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) { - if l.consumed > 0 { - n := copy(l.buf, l.buf[l.consumed:]) - l.buf = l.buf[:n] - l.consumed = 0 - } + l.removeConsumedFromBuffer() if len(l.buf) == 0 && l.err != nil { err = l.err diff --git a/src/pkg/encoding/line/line_test.go b/src/pkg/encoding/line/line_test.go index 68d13b586..ff16d10c7 100644 --- a/src/pkg/encoding/line/line_test.go +++ b/src/pkg/encoding/line/line_test.go @@ -6,6 +6,7 @@ package line import ( "bytes" + "io" "os" "testing" ) @@ -87,3 +88,23 @@ func TestLineTooLong(t *testing.T) { t.Errorf("bad result for third line: %x", line) } } + +func TestReadAfterLines(t *testing.T) { + line1 := "line1" + restData := "line2\nline 3\n" + inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData)) + outbuf := new(bytes.Buffer) + maxLineLength := len(line1) + len(restData)/2 + l := NewReader(inbuf, maxLineLength) + line, isPrefix, err := l.ReadLine() + if isPrefix || err != nil || string(line) != line1 { + t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line)) + } + n, err := io.Copy(outbuf, l) + if int(n) != len(restData) || err != nil { + t.Errorf("bad result for Read: n=%d err=%v", n, err) + } + if outbuf.String() != restData { + t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData) + } +} diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go index ba9bd2472..4f4c8c777 100644 --- a/src/pkg/exec/exec.go +++ b/src/pkg/exec/exec.go @@ -7,6 +7,7 @@ package exec import ( "os" + "strconv" ) // Arguments to Run. @@ -29,6 +30,16 @@ type Cmd struct { Pid int } +// PathError records the name of a binary that was not +// found on the current $PATH. +type PathError struct { + Name string +} + +func (e *PathError) String() string { + return "command " + strconv.Quote(e.Name) + " not found in $PATH" +} + // Given mode (DevNull, etc), return file for child // and file to record in Cmd structure. func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { diff --git a/src/pkg/exec/lp_test.go b/src/pkg/exec/lp_test.go new file mode 100644 index 000000000..54081771e --- /dev/null +++ b/src/pkg/exec/lp_test.go @@ -0,0 +1,33 @@ +// Copyright 2011 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. + +package exec + +import ( + "testing" +) + +var nonExistentPaths = []string{ + "some-non-existent-path", + "non-existent-path/slashed", +} + +func TestLookPathNotFound(t *testing.T) { + for _, name := range nonExistentPaths { + path, err := LookPath(name) + if err == nil { + t.Fatalf("LookPath found %q in $PATH", name) + } + if path != "" { + t.Fatalf("LookPath path == %q when err != nil", path) + } + perr, ok := err.(*PathError) + if !ok { + t.Fatal("LookPath error is not a PathError") + } + if perr.Name != name { + t.Fatalf("want PathError name %q, got %q", name, perr.Name) + } + } +} diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go index 292e24fcc..44f84347b 100644 --- a/src/pkg/exec/lp_unix.go +++ b/src/pkg/exec/lp_unix.go @@ -29,7 +29,7 @@ func LookPath(file string) (string, os.Error) { if canExec(file) { return file, nil } - return "", &os.PathError{"lookpath", file, os.ENOENT} + return "", &PathError{file} } pathenv := os.Getenv("PATH") for _, dir := range strings.Split(pathenv, ":", -1) { @@ -41,5 +41,5 @@ func LookPath(file string) (string, os.Error) { return dir + "/" + file, nil } } - return "", &os.PathError{"lookpath", file, os.ENOENT} + return "", &PathError{file} } diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go index 7b56afa85..d357575fd 100644 --- a/src/pkg/exec/lp_windows.go +++ b/src/pkg/exec/lp_windows.go @@ -49,7 +49,7 @@ func LookPath(file string) (string, os.Error) { if f, ok := canExec(file, exts); ok { return f, nil } - return ``, &os.PathError{"lookpath", file, os.ENOENT} + return ``, &PathError{file} } if pathenv := os.Getenv(`PATH`); pathenv == `` { if f, ok := canExec(`.\`+file, exts); ok { @@ -62,5 +62,5 @@ func LookPath(file string) (string, os.Error) { } } } - return ``, &os.PathError{"lookpath", file, os.ENOENT} + return ``, &PathError{file} } diff --git a/src/pkg/exp/datafmt/datafmt_test.go b/src/pkg/exp/datafmt/datafmt_test.go index f6a09f820..d7c70b21d 100644 --- a/src/pkg/exp/datafmt/datafmt_test.go +++ b/src/pkg/exp/datafmt/datafmt_test.go @@ -80,10 +80,10 @@ func TestCustomFormatters(t *testing.T) { f = parse(t, ``, fmap1) verify(t, f, `even odd even odd `, 0, 1, 2, 3) - f = parse(t, `/ =@:blank; float="#"`, fmap1) + f = parse(t, `/ =@:blank; float64="#"`, fmap1) verify(t, f, `# # #`, 0.0, 1.0, 2.0) - f = parse(t, `float=@:nil`, fmap1) + f = parse(t, `float64=@:nil`, fmap1) verify(t, f, ``, 0.0, 1.0, 2.0) f = parse(t, `testing "testing"; ptr=*`, fmap2) @@ -139,7 +139,7 @@ func TestBasicTypes(t *testing.T) { const f = 3.141592 const fs = `3.141592` - check(t, `float ="%g"`, fs, f) + check(t, `float64="%g"`, fs, f) check(t, `float32="%g"`, fs, float32(f)) check(t, `float64="%g"`, fs, float64(f)) } diff --git a/src/pkg/exp/datafmt/parser.go b/src/pkg/exp/datafmt/parser.go index a01378ea5..c6d140264 100644 --- a/src/pkg/exp/datafmt/parser.go +++ b/src/pkg/exp/datafmt/parser.go @@ -42,8 +42,9 @@ func (p *parser) next() { func (p *parser) init(fset *token.FileSet, filename string, src []byte) { p.ErrorVector.Reset() - p.file = p.scanner.Init(fset, filename, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message - p.next() // initializes pos, tok, lit + p.file = fset.AddFile(filename, fset.Base(), len(src)) + p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message + p.next() // initializes pos, tok, lit p.packs = make(map[string]string) p.rules = make(map[string]expr) } diff --git a/src/pkg/exp/draw/x11/conn.go b/src/pkg/exp/draw/x11/conn.go index da2181536..e28fb2170 100644 --- a/src/pkg/exp/draw/x11/conn.go +++ b/src/pkg/exp/draw/x11/conn.go @@ -122,10 +122,13 @@ func (c *conn) writeSocket() { func (c *conn) Screen() draw.Image { return c.img } func (c *conn) FlushImage() { - // We do the send (the <- operator) in an expression context, rather than in - // a statement context, so that it does not block, and fails if the buffered - // channel is full (in which case there already is a flush request pending). - _ = c.flush <- false + select { + case c.flush <- false: + // Flush notification sent. + default: + // Could not send. + // Flush notification must be pending already. + } } func (c *conn) Close() os.Error { diff --git a/src/pkg/exp/eval/Makefile b/src/pkg/exp/eval/Makefile index 2b716b14c..872316cad 100644 --- a/src/pkg/exp/eval/Makefile +++ b/src/pkg/exp/eval/Makefile @@ -30,7 +30,7 @@ eval: main.$O gen.$O: gen.go $(GC) $< -generate: gen.$O $(pkgdir)/$(TARG).a +generate: gen.$O $(LD) -o $@ $<;\ ./generate > expr1.go;\ gofmt -w expr1.go diff --git a/src/pkg/exp/eval/bridge.go b/src/pkg/exp/eval/bridge.go index 3fa498d68..12835c4c0 100644 --- a/src/pkg/exp/eval/bridge.go +++ b/src/pkg/exp/eval/bridge.go @@ -43,8 +43,6 @@ func TypeFromNative(t reflect.Type) Type { et = Float32Type case reflect.Float64: et = Float64Type - case reflect.Float: - et = FloatType } case *reflect.IntType: switch t.Kind() { diff --git a/src/pkg/exp/eval/eval_test.go b/src/pkg/exp/eval/eval_test.go index 6bfe9089d..ff28cf1a9 100644 --- a/src/pkg/exp/eval/eval_test.go +++ b/src/pkg/exp/eval/eval_test.go @@ -173,8 +173,8 @@ func toValue(val interface{}) Value { return &r case *big.Int: return &idealIntV{val} - case float: - r := floatV(val) + case float64: + r := float64V(val) return &r case *big.Rat: return &idealFloatV{val} @@ -244,7 +244,7 @@ func newTestWorld() *World { def("i", IntType, 1) def("i2", IntType, 2) def("u", UintType, uint(1)) - def("f", FloatType, 1.0) + def("f", Float64Type, 1.0) def("s", StringType, "abc") def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1}) def("ai", NewArrayType(2, IntType), varray{1, 2}) diff --git a/src/pkg/exp/eval/expr.go b/src/pkg/exp/eval/expr.go index 70f63cf2d..e65f47617 100644 --- a/src/pkg/exp/eval/expr.go +++ b/src/pkg/exp/eval/expr.go @@ -1981,7 +1981,7 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) { case tempType.isInteger(): tempType = IntType case tempType.isFloat(): - tempType = FloatType + tempType = Float64Type default: log.Panicf("unexpected ideal type %v", tempType) } diff --git a/src/pkg/exp/eval/expr1.go b/src/pkg/exp/eval/expr1.go index ae0cfc723..5d0e50000 100755 --- a/src/pkg/exp/eval/expr1.go +++ b/src/pkg/exp/eval/expr1.go @@ -9,8 +9,8 @@ import ( ) /* -* "As" functions. These retrieve evaluator functions from an -* expr, panicking if the requested evaluator has the wrong type. + * "As" functions. These retrieve evaluator functions from an + * expr, panicking if the requested evaluator has the wrong type. */ func (a *expr) asBool() func(*Thread) bool { return a.eval.(func(*Thread) bool) @@ -90,7 +90,7 @@ func (a *expr) asInterface() func(*Thread) interface{} { } /* -* Operator generators. + * Operator generators. */ func (a *expr) genConstant(v Value) { @@ -392,13 +392,6 @@ func (a *expr) genBinOpAdd(l, r *expr) { ret = l + r return float64(float64(ret)) } - case 0: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l + r - return float64(float(ret)) - } default: log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) } @@ -528,13 +521,6 @@ func (a *expr) genBinOpSub(l, r *expr) { ret = l - r return float64(float64(ret)) } - case 0: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l - r - return float64(float(ret)) - } default: log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) } @@ -657,13 +643,6 @@ func (a *expr) genBinOpMul(l, r *expr) { ret = l * r return float64(float64(ret)) } - case 0: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l * r - return float64(float(ret)) - } default: log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) } @@ -822,16 +801,6 @@ func (a *expr) genBinOpQuo(l, r *expr) { ret = l / r return float64(float64(ret)) } - case 0: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return float64(float(ret)) - } default: log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) } diff --git a/src/pkg/exp/eval/gen.go b/src/pkg/exp/eval/gen.go index 81863dd6f..a2b119846 100644 --- a/src/pkg/exp/eval/gen.go +++ b/src/pkg/exp/eval/gen.go @@ -47,7 +47,7 @@ var ( } idealIntType = &Type{Repr: "*idealIntType", Value: "IdealIntValue", Native: "*big.Int", As: "asIdealInt", IsIdeal: true} floatType = &Type{Repr: "*floatType", Value: "FloatValue", Native: "float64", As: "asFloat", - Sizes: []Size{{32, "float32"}, {64, "float64"}, {0, "float"}}, + Sizes: []Size{{32, "float32"}, {64, "float64"}}, } idealFloatType = &Type{Repr: "*idealFloatType", Value: "IdealFloatValue", Native: "*big.Rat", As: "asIdealFloat", IsIdeal: true} stringType = &Type{Repr: "*stringType", Value: "StringValue", Native: "string", As: "asString"} diff --git a/src/pkg/exp/eval/stmt.go b/src/pkg/exp/eval/stmt.go index b9ffa94fa..77ff066d0 100644 --- a/src/pkg/exp/eval/stmt.go +++ b/src/pkg/exp/eval/stmt.go @@ -602,7 +602,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, case ac.rmt.Elems[i].isInteger(): lt = IntType case ac.rmt.Elems[i].isFloat(): - lt = FloatType + lt = Float64Type default: log.Panicf("unexpected ideal type %v", rs[i].t) } diff --git a/src/pkg/exp/eval/type.go b/src/pkg/exp/eval/type.go index db77ab198..3f272ce4b 100644 --- a/src/pkg/exp/eval/type.go +++ b/src/pkg/exp/eval/type.go @@ -372,7 +372,6 @@ type floatType struct { var ( Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"}) Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"}) - FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"}) ) func (t *floatType) compat(o Type, conv bool) bool { @@ -394,9 +393,6 @@ func (t *floatType) Zero() Value { case 64: res := float64V(0) return &res - case 0: - res := floatV(0) - return &res } panic("unexpected float bit count") } @@ -408,9 +404,6 @@ var minFloat64Val *big.Rat func (t *floatType) minVal() *big.Rat { bits := t.Bits - if bits == 0 { - bits = uint(8 * unsafe.Sizeof(float(0))) - } switch bits { case 32: return minFloat32Val @@ -423,9 +416,6 @@ func (t *floatType) minVal() *big.Rat { func (t *floatType) maxVal() *big.Rat { bits := t.Bits - if bits == 0 { - bits = uint(8 * unsafe.Sizeof(float(0))) - } switch bits { case 32: return maxFloat32Val diff --git a/src/pkg/exp/eval/value.go b/src/pkg/exp/eval/value.go index cace2fd37..daa691897 100644 --- a/src/pkg/exp/eval/value.go +++ b/src/pkg/exp/eval/value.go @@ -307,16 +307,6 @@ func (v *float64V) Get(*Thread) float64 { return float64(*v) } func (v *float64V) Set(t *Thread, x float64) { *v = float64V(x) } -type floatV float - -func (v *floatV) String() string { return fmt.Sprint(*v) } - -func (v *floatV) Assign(t *Thread, o Value) { *v = floatV(o.(FloatValue).Get(t)) } - -func (v *floatV) Get(*Thread) float64 { return float64(*v) } - -func (v *floatV) Set(t *Thread, x float64) { *v = floatV(x) } - /* * Ideal float */ diff --git a/src/pkg/exp/ogle/cmd.go b/src/pkg/exp/ogle/cmd.go index ff137b0f8..4f67032d0 100644 --- a/src/pkg/exp/ogle/cmd.go +++ b/src/pkg/exp/ogle/cmd.go @@ -64,7 +64,8 @@ func Main() { func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) { sc := new(scanner.Scanner) ev := new(scanner.ErrorVector) - sc.Init(fset, "input", input, ev, 0) + file := fset.AddFile("input", fset.Base(), len(input)) + sc.Init(file, input, ev, 0) return sc, ev } diff --git a/src/pkg/exp/ogle/rtype.go b/src/pkg/exp/ogle/rtype.go index fd77f1bc2..b3c35575a 100644 --- a/src/pkg/exp/ogle/rtype.go +++ b/src/pkg/exp/ogle/rtype.go @@ -209,9 +209,6 @@ func parseRemoteType(a aborter, rs remoteStruct) *remoteType { case p.runtime.PFloat64Type: t = eval.Float64Type mk = mkFloat64 - case p.runtime.PFloatType: - t = eval.FloatType - mk = mkFloat case p.runtime.PStringType: t = eval.StringType mk = mkString diff --git a/src/pkg/exp/wingui/Makefile b/src/pkg/exp/wingui/Makefile new file mode 100644 index 000000000..e9d44d2bc --- /dev/null +++ b/src/pkg/exp/wingui/Makefile @@ -0,0 +1,26 @@ +# Copyright 2011 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. + +GOOS=windows + +include ../../../Make.inc + +TARG=wingui + +GOFILES=\ + gui.go\ + winapi.go\ + zwinapi.go\ + +include ../../../Make.cmd + +zwinapi.go: winapi.go + $(GOROOT)/src/pkg/syscall/mksyscall_windows.sh $< \ + | sed 's/^package.*syscall$$/package main/' \ + | sed '/^import/a \ + import "syscall"' \ + | sed 's/Syscall/syscall.Syscall/' \ + | sed 's/EINVAL/syscall.EINVAL/' \ + | gofmt \ + > $@ diff --git a/src/pkg/exp/wingui/gui.go b/src/pkg/exp/wingui/gui.go new file mode 100644 index 000000000..41ee5b789 --- /dev/null +++ b/src/pkg/exp/wingui/gui.go @@ -0,0 +1,152 @@ +// Copyright 2011 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. + +package main + +import ( + "fmt" + "syscall" + "os" + "unsafe" +) + +// some help functions + +func abortf(format string, a ...interface{}) { + fmt.Fprintf(os.Stdout, format, a...) + os.Exit(1) +} + +func abortErrNo(funcname string, err int) { + abortf("%s failed: %d %s\n", funcname, err, syscall.Errstr(err)) +} + +// global vars + +var ( + mh uint32 + bh uint32 +) + +// WinProc called by windows to notify us of all windows events we might be interested in. +func WndProc(hwnd, msg uint32, wparam, lparam int32) uintptr { + var rc int32 + switch msg { + case WM_CREATE: + var e int + // CreateWindowEx + bh, e = CreateWindowEx( + 0, + syscall.StringToUTF16Ptr("button"), + syscall.StringToUTF16Ptr("Quit"), + WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON, + 75, 70, 140, 25, + hwnd, 1, mh, 0) + if e != 0 { + abortErrNo("CreateWindowEx", e) + } + fmt.Printf("button handle is %x\n", bh) + rc = DefWindowProc(hwnd, msg, wparam, lparam) + case WM_COMMAND: + switch uint32(lparam) { + case bh: + if ok, e := PostMessage(hwnd, WM_CLOSE, 0, 0); !ok { + abortErrNo("PostMessage", e) + } + default: + rc = DefWindowProc(hwnd, msg, wparam, lparam) + } + case WM_CLOSE: + DestroyWindow(hwnd) + case WM_DESTROY: + PostQuitMessage(0) + default: + rc = DefWindowProc(hwnd, msg, wparam, lparam) + } + //fmt.Printf("WndProc(0x%08x, %d, 0x%08x, 0x%08x) (%d)\n", hwnd, msg, wparam, lparam, rc) + return uintptr(rc) +} + +func rungui() int { + var e int + + // GetModuleHandle + mh, e = GetModuleHandle(nil) + if e != 0 { + abortErrNo("GetModuleHandle", e) + } + + // Get icon we're going to use. + myicon, e := LoadIcon(0, IDI_APPLICATION) + if e != 0 { + abortErrNo("LoadIcon", e) + } + + // Get cursor we're going to use. + mycursor, e := LoadCursor(0, IDC_ARROW) + if e != 0 { + abortErrNo("LoadCursor", e) + } + + // Create callback + wproc := syscall.NewCallback(WndProc) + + // RegisterClassEx + wcname := syscall.StringToUTF16Ptr("myWindowClass") + var wc Wndclassex + wc.Size = uint32(unsafe.Sizeof(wc)) + wc.WndProc = wproc + wc.Instance = mh + wc.Icon = myicon + wc.Cursor = mycursor + wc.Background = COLOR_BTNFACE + 1 + wc.MenuName = nil + wc.ClassName = wcname + wc.IconSm = myicon + if _, e := RegisterClassEx(&wc); e != 0 { + abortErrNo("RegisterClassEx", e) + } + + // CreateWindowEx + wh, e := CreateWindowEx( + WS_EX_CLIENTEDGE, + wcname, + syscall.StringToUTF16Ptr("My window"), + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, + 0, 0, mh, 0) + if e != 0 { + abortErrNo("CreateWindowEx", e) + } + fmt.Printf("main window handle is %x\n", wh) + + // ShowWindow + ShowWindow(wh, SW_SHOWDEFAULT) + + // UpdateWindow + if _, e := UpdateWindow(wh); e != 0 { + abortErrNo("UpdateWindow", e) + } + + // Process all windows messages until WM_QUIT. + var m Msg + for { + r, e := GetMessage(&m, 0, 0, 0) + if e != 0 { + abortErrNo("GetMessage", e) + } + if r == 0 { + // WM_QUIT received -> get out + break + } + TranslateMessage(&m) + DispatchMessage(&m) + } + return int(m.Wparam) +} + +func main() { + rc := rungui() + os.Exit(rc) +} diff --git a/src/pkg/exp/wingui/winapi.go b/src/pkg/exp/wingui/winapi.go new file mode 100644 index 000000000..2f480ec9e --- /dev/null +++ b/src/pkg/exp/wingui/winapi.go @@ -0,0 +1,148 @@ +// Copyright 2011 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. + +package main + +import ( + "syscall" + "unsafe" +) + +func loadDll(fname string) uint32 { + h, e := syscall.LoadLibrary(fname) + if e != 0 { + abortf("LoadLibrary(%s) failed with err=%d.\n", fname, e) + } + return h +} + +func getSysProcAddr(m uint32, pname string) uintptr { + p, e := syscall.GetProcAddress(m, pname) + if e != 0 { + abortf("GetProcAddress(%s) failed with err=%d.\n", pname, e) + } + return uintptr(p) +} + +type Wndclassex struct { + Size uint32 + Style uint32 + WndProc uintptr + ClsExtra int32 + WndExtra int32 + Instance uint32 + Icon uint32 + Cursor uint32 + Background uint32 + MenuName *uint16 + ClassName *uint16 + IconSm uint32 +} + +type Point struct { + X int32 + Y int32 +} + +type Msg struct { + Hwnd uint32 + Message uint32 + Wparam int32 + Lparam int32 + Time uint32 + Pt Point +} + +const ( + // Window styles + WS_OVERLAPPED = 0 + WS_POPUP = 0x80000000 + WS_CHILD = 0x40000000 + WS_MINIMIZE = 0x20000000 + WS_VISIBLE = 0x10000000 + WS_DISABLED = 0x8000000 + WS_CLIPSIBLINGS = 0x4000000 + WS_CLIPCHILDREN = 0x2000000 + WS_MAXIMIZE = 0x1000000 + WS_CAPTION = WS_BORDER | WS_DLGFRAME + WS_BORDER = 0x800000 + WS_DLGFRAME = 0x400000 + WS_VSCROLL = 0x200000 + WS_HSCROLL = 0x100000 + WS_SYSMENU = 0x80000 + WS_THICKFRAME = 0x40000 + WS_GROUP = 0x20000 + WS_TABSTOP = 0x10000 + WS_MINIMIZEBOX = 0x20000 + WS_MAXIMIZEBOX = 0x10000 + WS_TILED = WS_OVERLAPPED + WS_ICONIC = WS_MINIMIZE + WS_SIZEBOX = WS_THICKFRAME + // Common Window Styles + WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX + WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW + WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU + WS_CHILDWINDOW = WS_CHILD + + WS_EX_CLIENTEDGE = 0x200 + + // Some windows messages + WM_CREATE = 1 + WM_DESTROY = 2 + WM_CLOSE = 16 + WM_COMMAND = 273 + + // Some button control styles + BS_DEFPUSHBUTTON = 1 + + // Some colour constants + COLOR_WINDOW = 5 + COLOR_BTNFACE = 15 + + // Default window position + CW_USEDEFAULT = 0x80000000 - 0x100000000 + + // Show window default style + SW_SHOWDEFAULT = 10 +) + +var ( + // Some globaly known cusrors + IDC_ARROW = MakeIntResource(32512) + IDC_IBEAM = MakeIntResource(32513) + IDC_WAIT = MakeIntResource(32514) + IDC_CROSS = MakeIntResource(32515) + + // Some globaly known icons + IDI_APPLICATION = MakeIntResource(32512) + IDI_HAND = MakeIntResource(32513) + IDI_QUESTION = MakeIntResource(32514) + IDI_EXCLAMATION = MakeIntResource(32515) + IDI_ASTERISK = MakeIntResource(32516) + IDI_WINLOGO = MakeIntResource(32517) + IDI_WARNING = IDI_EXCLAMATION + IDI_ERROR = IDI_HAND + IDI_INFORMATION = IDI_ASTERISK +) + +//sys GetModuleHandle(modname *uint16) (handle uint32, errno int) = GetModuleHandleW +//sys RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) = user32.RegisterClassExW +//sys CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) = user32.CreateWindowExW +//sys DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.DefWindowProcW +//sys DestroyWindow(hwnd uint32) (ok bool, errno int) = user32.DestroyWindow +//sys PostQuitMessage(exitcode int32) = user32.PostQuitMessage +//sys ShowWindow(hwnd uint32, cmdshow int32) (ok bool) = user32.ShowWindow +//sys UpdateWindow(hwnd uint32) (ok bool, errno int) = user32.UpdateWindow +//sys GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) [failretval==-1] = user32.GetMessageW +//sys TranslateMessage(msg *Msg) (ok bool) = user32.TranslateMessage +//sys DispatchMessage(msg *Msg) (ret int32) = user32.DispatchMessageW +//sys LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) = user32.LoadIconW +//sys LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) = user32.LoadCursorW +//sys SetCursor(cursor uint32) (precursor uint32, errno int) = user32.SetCursor +//sys SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) = user32.SendMessageW +//sys PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (ok bool, errno int) = user32.PostMessageW + +func MakeIntResource(id uint16) *uint16 { + return (*uint16)(unsafe.Pointer(uintptr(id))) +} diff --git a/src/pkg/exp/wingui/zwinapi.go b/src/pkg/exp/wingui/zwinapi.go new file mode 100644 index 000000000..324bf1773 --- /dev/null +++ b/src/pkg/exp/wingui/zwinapi.go @@ -0,0 +1,214 @@ +// mksyscall_windows.sh winapi.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package main + +import "unsafe" +import "syscall" + +var ( + modkernel32 = loadDll("kernel32.dll") + moduser32 = loadDll("user32.dll") + + procGetModuleHandleW = getSysProcAddr(modkernel32, "GetModuleHandleW") + procRegisterClassExW = getSysProcAddr(moduser32, "RegisterClassExW") + procCreateWindowExW = getSysProcAddr(moduser32, "CreateWindowExW") + procDefWindowProcW = getSysProcAddr(moduser32, "DefWindowProcW") + procDestroyWindow = getSysProcAddr(moduser32, "DestroyWindow") + procPostQuitMessage = getSysProcAddr(moduser32, "PostQuitMessage") + procShowWindow = getSysProcAddr(moduser32, "ShowWindow") + procUpdateWindow = getSysProcAddr(moduser32, "UpdateWindow") + procGetMessageW = getSysProcAddr(moduser32, "GetMessageW") + procTranslateMessage = getSysProcAddr(moduser32, "TranslateMessage") + procDispatchMessageW = getSysProcAddr(moduser32, "DispatchMessageW") + procLoadIconW = getSysProcAddr(moduser32, "LoadIconW") + procLoadCursorW = getSysProcAddr(moduser32, "LoadCursorW") + procSetCursor = getSysProcAddr(moduser32, "SetCursor") + procSendMessageW = getSysProcAddr(moduser32, "SendMessageW") + procPostMessageW = getSysProcAddr(moduser32, "PostMessageW") +) + +func GetModuleHandle(modname *uint16) (handle uint32, errno int) { + r0, _, e1 := syscall.Syscall(procGetModuleHandleW, 1, uintptr(unsafe.Pointer(modname)), 0, 0) + handle = uint32(r0) + if handle == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) { + r0, _, e1 := syscall.Syscall(procRegisterClassExW, 1, uintptr(unsafe.Pointer(wndclass)), 0, 0) + atom = uint16(r0) + if atom == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) { + r0, _, e1 := syscall.Syscall12(procCreateWindowExW, 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param)) + hwnd = uint32(r0) + if hwnd == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) { + r0, _, _ := syscall.Syscall6(procDefWindowProcW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + lresult = int32(r0) + return +} + +func DestroyWindow(hwnd uint32) (ok bool, errno int) { + r0, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0) + ok = bool(r0 != 0) + if !ok { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func PostQuitMessage(exitcode int32) { + syscall.Syscall(procPostQuitMessage, 1, uintptr(exitcode), 0, 0) + return +} + +func ShowWindow(hwnd uint32, cmdshow int32) (ok bool) { + r0, _, _ := syscall.Syscall(procShowWindow, 2, uintptr(hwnd), uintptr(cmdshow), 0) + ok = bool(r0 != 0) + return +} + +func UpdateWindow(hwnd uint32) (ok bool, errno int) { + r0, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0) + ok = bool(r0 != 0) + if !ok { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) { + r0, _, e1 := syscall.Syscall6(procGetMessageW, 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0) + ret = int32(r0) + if ret == -1 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func TranslateMessage(msg *Msg) (ok bool) { + r0, _, _ := syscall.Syscall(procTranslateMessage, 1, uintptr(unsafe.Pointer(msg)), 0, 0) + ok = bool(r0 != 0) + return +} + +func DispatchMessage(msg *Msg) (ret int32) { + r0, _, _ := syscall.Syscall(procDispatchMessageW, 1, uintptr(unsafe.Pointer(msg)), 0, 0) + ret = int32(r0) + return +} + +func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) { + r0, _, e1 := syscall.Syscall(procLoadIconW, 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0) + icon = uint32(r0) + if icon == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) { + r0, _, e1 := syscall.Syscall(procLoadCursorW, 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0) + cursor = uint32(r0) + if cursor == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func SetCursor(cursor uint32) (precursor uint32, errno int) { + r0, _, e1 := syscall.Syscall(procSetCursor, 1, uintptr(cursor), 0, 0) + precursor = uint32(r0) + if precursor == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} + +func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) { + r0, _, _ := syscall.Syscall6(procSendMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + lresult = int32(r0) + return +} + +func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (ok bool, errno int) { + r0, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + ok = bool(r0 != 0) + if !ok { + if e1 != 0 { + errno = int(e1) + } else { + errno = syscall.EINVAL + } + } else { + errno = 0 + } + return +} diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go index fb20b25b2..b1f0f6c1b 100644 --- a/src/pkg/expvar/expvar.go +++ b/src/pkg/expvar/expvar.go @@ -38,7 +38,7 @@ type Var interface { String() string } -// Int is a 64-bit integer variable, and satisfies the Var interface. +// Int is a 64-bit integer variable that satisfies the Var interface. type Int struct { i int64 mu sync.Mutex @@ -58,7 +58,29 @@ func (v *Int) Set(value int64) { v.i = value } -// Map is a string-to-Var map variable, and satisfies the Var interface. +// Float is a 64-bit float variable that satisfies the Var interface. +type Float struct { + f float64 + mu sync.Mutex +} + +func (v *Float) String() string { return strconv.Ftoa64(v.f, 'g', -1) } + +// Add adds delta to v. +func (v *Float) Add(delta float64) { + v.mu.Lock() + defer v.mu.Unlock() + v.f += delta +} + +// Set sets v to value. +func (v *Float) Set(value float64) { + v.mu.Lock() + defer v.mu.Unlock() + v.f = value +} + +// Map is a string-to-Var map variable that satisfies the Var interface. type Map struct { m map[string]Var mu sync.Mutex @@ -119,6 +141,22 @@ func (v *Map) Add(key string, delta int64) { } } +// AddFloat adds delta to the *Float value stored under the given map key. +func (v *Map) AddFloat(key string, delta float64) { + v.mu.Lock() + defer v.mu.Unlock() + av, ok := v.m[key] + if !ok { + av = new(Float) + v.m[key] = av + } + + // Add to Float; ignore otherwise. + if iv, ok := av.(*Float); ok { + iv.Add(delta) + } +} + // TODO(rsc): Make sure map access in separate thread is safe. func (v *Map) iterate(c chan<- KeyValue) { for k, v := range v.m { @@ -148,6 +186,12 @@ type IntFunc func() int64 func (v IntFunc) String() string { return strconv.Itoa64(v()) } +// FloatFunc wraps a func() float64 to create a value that satisfies the Var interface. +// The function will be called each time the Var is evaluated. +type FloatFunc func() float64 + +func (v FloatFunc) String() string { return strconv.Ftoa64(v(), 'g', -1) } + // StringFunc wraps a func() string to create value that satisfies the Var interface. // The function will be called each time the Var is evaluated. type StringFunc func() string @@ -192,6 +236,12 @@ func NewInt(name string) *Int { return v } +func NewFloat(name string) *Float { + v := new(Float) + Publish(name, v) + return v +} + func NewMap(name string) *Map { v := new(Map).Init() Publish(name, v) diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go index 009f24d1a..a8b1a96a9 100644 --- a/src/pkg/expvar/expvar_test.go +++ b/src/pkg/expvar/expvar_test.go @@ -34,6 +34,31 @@ func TestInt(t *testing.T) { } } +func TestFloat(t *testing.T) { + reqs := NewFloat("requests-float") + if reqs.f != 0.0 { + t.Errorf("reqs.f = %v, want 0", reqs.f) + } + if reqs != Get("requests-float").(*Float) { + t.Errorf("Get() failed.") + } + + reqs.Add(1.5) + reqs.Add(1.25) + if reqs.f != 2.75 { + t.Errorf("reqs.f = %v, want 2.75", reqs.f) + } + + if s := reqs.String(); s != "2.75" { + t.Errorf("reqs.String() = %q, want \"4.64\"", s) + } + + reqs.Add(-2) + if reqs.f != 0.75 { + t.Errorf("reqs.f = %v, want 0.75", reqs.f) + } +} + func TestString(t *testing.T) { name := NewString("my-name") if name.s != "" { @@ -56,12 +81,16 @@ func TestMapCounter(t *testing.T) { colours.Add("red", 1) colours.Add("red", 2) colours.Add("blue", 4) + colours.AddFloat("green", 4.125) if x := colours.m["red"].(*Int).i; x != 3 { t.Errorf("colours.m[\"red\"] = %v, want 3", x) } if x := colours.m["blue"].(*Int).i; x != 4 { t.Errorf("colours.m[\"blue\"] = %v, want 4", x) } + if x := colours.m["green"].(*Float).f; x != 4.125 { + t.Errorf("colours.m[\"green\"] = %v, want 3.14", x) + } // colours.String() should be '{"red":3, "blue":4}', // though the order of red and blue could vary. @@ -98,6 +127,19 @@ func TestIntFunc(t *testing.T) { } } +func TestFloatFunc(t *testing.T) { + x := 8.5 + ix := FloatFunc(func() float64 { return x }) + if s := ix.String(); s != "8.5" { + t.Errorf("ix.String() = %v, want 3.14", s) + } + + x -= 1.25 + if s := ix.String(); s != "7.25" { + t.Errorf("ix.String() = %v, want 4.34", s) + } +} + func TestStringFunc(t *testing.T) { x := "hello" sx := StringFunc(func() string { return x }) diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go index 04fe2fa05..143a10611 100644 --- a/src/pkg/flag/flag.go +++ b/src/pkg/flag/flag.go @@ -166,22 +166,6 @@ func (s *stringValue) Set(val string) bool { func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } -// -- Float Value -type floatValue float - -func newFloatValue(val float, p *float) *floatValue { - *p = val - return (*floatValue)(p) -} - -func (f *floatValue) Set(s string) bool { - v, err := strconv.Atof(s) - *f = floatValue(v) - return err == nil -} - -func (f *floatValue) String() string { return fmt.Sprintf("%v", *f) } - // -- Float64 Value type float64Value float64 @@ -385,20 +369,6 @@ func String(name, value string, usage string) *string { return p } -// FloatVar defines a float flag with specified name, default value, and usage string. -// The argument p points to a float variable in which to store the value of the flag. -func FloatVar(p *float, name string, value float, usage string) { - Var(newFloatValue(value, p), name, usage) -} - -// Float defines a float flag with specified name, default value, and usage string. -// The return value is the address of a float variable that stores the value of the flag. -func Float(name string, value float, usage string) *float { - p := new(float) - FloatVar(p, name, value, usage) - return p -} - // Float64Var defines a float64 flag with specified name, default value, and usage string. // The argument p points to a float64 variable in which to store the value of the flag. func Float64Var(p *float64, name string, value float64, usage string) { diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go index 4ebb73805..b91a8b567 100644 --- a/src/pkg/flag/flag_test.go +++ b/src/pkg/flag/flag_test.go @@ -18,8 +18,7 @@ var ( test_uint = Uint("test_uint", 0, "uint value") test_uint64 = Uint64("test_uint64", 0, "uint64 value") test_string = String("test_string", "0", "string value") - test_float = Float("test_float", 0, "float value") - test_float64 = Float("test_float64", 0, "float64 value") + test_float64 = Float64("test_float64", 0, "float64 value") ) func boolString(s string) string { @@ -48,7 +47,7 @@ func TestEverything(t *testing.T) { } } VisitAll(visitor) - if len(m) != 8 { + if len(m) != 7 { t.Error("VisitAll misses some flags") for k, v := range m { t.Log(k, *v) @@ -69,11 +68,10 @@ func TestEverything(t *testing.T) { Set("test_uint", "1") Set("test_uint64", "1") Set("test_string", "1") - Set("test_float", "1") Set("test_float64", "1") desired = "1" Visit(visitor) - if len(m) != 8 { + if len(m) != 7 { t.Error("Visit fails after set") for k, v := range m { t.Log(k, *v) @@ -101,8 +99,7 @@ func TestParse(t *testing.T) { uintFlag := Uint("uint", 0, "uint value") uint64Flag := Uint64("uint64", 0, "uint64 value") stringFlag := String("string", "0", "string value") - floatFlag := Float("float", 0, "float value") - float64Flag := Float("float64", 0, "float64 value") + float64Flag := Float64("float64", 0, "float64 value") extra := "one-extra-argument" args := []string{ "a.out", @@ -113,7 +110,6 @@ func TestParse(t *testing.T) { "-uint", "24", "--uint64", "25", "-string", "hello", - "--float", "3141.5", "-float64", "2718e28", extra, } @@ -141,9 +137,6 @@ func TestParse(t *testing.T) { if *stringFlag != "hello" { t.Error("string flag should be `hello`, is ", *stringFlag) } - if *floatFlag != 3141.5 { - t.Error("float flag should be 3141.5, is ", *floatFlag) - } if *float64Flag != 2718e28 { t.Error("float64 flag should be 2718e28, is ", *float64Flag) } diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go index f3067eac9..02c29389d 100644 --- a/src/pkg/fmt/doc.go +++ b/src/pkg/fmt/doc.go @@ -26,7 +26,7 @@ %o base 8 %x base 16, with lower-case letters for a-f %X base 16, with upper-case letters for A-F - %U unicode format: U+1234; same as "U+%x" with 4 digits default + %U Unicode format: U+1234; same as "U+%x" with 4 digits default Floating-point and complex constituents: %e scientific notation, e.g. -1234.456e+78 %E scientific notation, e.g. -1234.456E+78 @@ -36,21 +36,27 @@ String and slice of bytes: %s the uninterpreted bytes of the string or slice %q a double-quoted string safely escaped with Go syntax - %x base 16 notation with two characters per byte + %x base 16, lower-case, two characters per byte + %X base 16, upper-case, two characters per byte Pointer: %p base 16 notation, with leading 0x There is no 'u' flag. Integers are printed unsigned if they have unsigned type. Similarly, there is no need to specify the size of the operand (int8, int64). - For numeric values, the width and precision flags control - formatting; width sets the width of the field, precision the - number of places after the decimal, if appropriate. The - format %6.2f prints 123.45. The width of a field is the number - of Unicode code points in the string. This differs from C's printf where - the field width is the number of bytes. Either or both of the - flags may be replaced with the character '*', causing their values - to be obtained from the next operand, which must be of type int. + The width and precision control formatting and are in units of Unicode + code points. (This differs from C's printf where the units are numbers + of bytes.) Either or both of the flags may be replaced with the + character '*', causing their values to be obtained from the next + operand, which must be of type int. + + For numeric values, width sets the width of the field and precision + sets the number of places after the decimal, if appropriate. For + example, the format %6.2f prints 123.45. + + For strings, width is the minimum number of characters to output, + padding with spaces if necessary, and precision is the maximum + number of characters to output, truncating if necessary. Other flags: + always print a sign for numeric values diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go index 0aafe6d99..3f085b722 100644 --- a/src/pkg/fmt/fmt_test.go +++ b/src/pkg/fmt/fmt_test.go @@ -28,10 +28,8 @@ type ( renamedUintptr uintptr renamedString string renamedBytes []byte - renamedFloat float renamedFloat32 float32 renamedFloat64 float64 - renamedComplex complex renamedComplex64 complex64 renamedComplex128 complex128 ) @@ -224,31 +222,31 @@ var fmttests = []struct { {"%b", 7, "111"}, {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"}, {"%b", -6, "-110"}, - {"%e", float64(1), "1.000000e+00"}, - {"%e", float64(1234.5678e3), "1.234568e+06"}, - {"%e", float64(1234.5678e-8), "1.234568e-05"}, - {"%e", float64(-7), "-7.000000e+00"}, - {"%e", float64(-1e-9), "-1.000000e-09"}, - {"%f", float64(1234.5678e3), "1234567.800000"}, - {"%f", float64(1234.5678e-8), "0.000012"}, - {"%f", float64(-7), "-7.000000"}, - {"%f", float64(-1e-9), "-0.000000"}, - {"%g", float64(1234.5678e3), "1.2345678e+06"}, + {"%e", 1.0, "1.000000e+00"}, + {"%e", 1234.5678e3, "1.234568e+06"}, + {"%e", 1234.5678e-8, "1.234568e-05"}, + {"%e", -7.0, "-7.000000e+00"}, + {"%e", -1e-9, "-1.000000e-09"}, + {"%f", 1234.5678e3, "1234567.800000"}, + {"%f", 1234.5678e-8, "0.000012"}, + {"%f", -7.0, "-7.000000"}, + {"%f", -1e-9, "-0.000000"}, + {"%g", 1234.5678e3, "1.2345678e+06"}, {"%g", float32(1234.5678e3), "1.2345678e+06"}, - {"%g", float64(1234.5678e-8), "1.2345678e-05"}, - {"%g", float64(-7), "-7"}, - {"%g", float64(-1e-9), "-1e-09"}, + {"%g", 1234.5678e-8, "1.2345678e-05"}, + {"%g", -7.0, "-7"}, + {"%g", -1e-9, "-1e-09"}, {"%g", float32(-1e-9), "-1e-09"}, - {"%E", float64(1), "1.000000E+00"}, - {"%E", float64(1234.5678e3), "1.234568E+06"}, - {"%E", float64(1234.5678e-8), "1.234568E-05"}, - {"%E", float64(-7), "-7.000000E+00"}, - {"%E", float64(-1e-9), "-1.000000E-09"}, - {"%G", float64(1234.5678e3), "1.2345678E+06"}, + {"%E", 1.0, "1.000000E+00"}, + {"%E", 1234.5678e3, "1.234568E+06"}, + {"%E", 1234.5678e-8, "1.234568E-05"}, + {"%E", -7.0, "-7.000000E+00"}, + {"%E", -1e-9, "-1.000000E-09"}, + {"%G", 1234.5678e3, "1.2345678E+06"}, {"%G", float32(1234.5678e3), "1.2345678E+06"}, - {"%G", float64(1234.5678e-8), "1.2345678E-05"}, - {"%G", float64(-7), "-7"}, - {"%G", float64(-1e-9), "-1E-09"}, + {"%G", 1234.5678e-8, "1.2345678E-05"}, + {"%G", -7.0, "-7"}, + {"%G", -1e-9, "-1E-09"}, {"%G", float32(-1e-9), "-1E-09"}, {"%c", 'x', "x"}, {"%c", 0xe4, "ä"}, @@ -273,15 +271,15 @@ var fmttests = []struct { {"%20e", 1.2345e3, " 1.234500e+03"}, {"%20e", 1.2345e-3, " 1.234500e-03"}, {"%20.8e", 1.2345e3, " 1.23450000e+03"}, - {"%20f", float64(1.23456789e3), " 1234.567890"}, - {"%20f", float64(1.23456789e-3), " 0.001235"}, - {"%20f", float64(12345678901.23456789), " 12345678901.234568"}, - {"%-20f", float64(1.23456789e3), "1234.567890 "}, - {"%20.8f", float64(1.23456789e3), " 1234.56789000"}, - {"%20.8f", float64(1.23456789e-3), " 0.00123457"}, - {"%g", float64(1.23456789e3), "1234.56789"}, - {"%g", float64(1.23456789e-3), "0.00123456789"}, - {"%g", float64(1.23456789e20), "1.23456789e+20"}, + {"%20f", 1.23456789e3, " 1234.567890"}, + {"%20f", 1.23456789e-3, " 0.001235"}, + {"%20f", 12345678901.23456789, " 12345678901.234568"}, + {"%-20f", 1.23456789e3, "1234.567890 "}, + {"%20.8f", 1.23456789e3, " 1234.56789000"}, + {"%20.8f", 1.23456789e-3, " 0.00123457"}, + {"%g", 1.23456789e3, "1234.56789"}, + {"%g", 1.23456789e-3, "0.00123456789"}, + {"%g", 1.23456789e20, "1.23456789e+20"}, {"%20e", math.Inf(1), " +Inf"}, {"%-20f", math.Inf(-1), "-Inf "}, {"%20g", math.NaN(), " NaN"}, @@ -346,10 +344,8 @@ var fmttests = []struct { {"%x", renamedString("thing"), "7468696e67"}, {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`}, {"%q", renamedBytes([]byte("hello")), `"hello"`}, - {"%v", renamedFloat(11), "11"}, {"%v", renamedFloat32(22), "22"}, {"%v", renamedFloat64(33), "33"}, - {"%v", renamedComplex(7 + .2i), "(7+0.2i)"}, {"%v", renamedComplex64(3 + 4i), "(3+4i)"}, {"%v", renamedComplex128(4 - 3i), "(4-3i)"}, @@ -363,7 +359,7 @@ var fmttests = []struct { {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"}, // %T - {"%T", (4 - 3i), "complex"}, + {"%T", (4 - 3i), "complex128"}, {"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"}, {"%T", intVal, "int"}, {"%6T", &intVal, " *int"}, diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go index 0121dda31..86057bf69 100644 --- a/src/pkg/fmt/format.go +++ b/src/pkg/fmt/format.go @@ -396,36 +396,3 @@ func (f *fmt) fmt_c128(v complex128, verb int) { } f.buf.Write(irparenBytes) } - -// float -func (x *fmt) f(a float) { - if strconv.FloatSize == 32 { - x.fmt_f32(float32(a)) - } else { - x.fmt_f64(float64(a)) - } -} - -func (x *fmt) e(a float) { - if strconv.FloatSize == 32 { - x.fmt_e32(float32(a)) - } else { - x.fmt_e64(float64(a)) - } -} - -func (x *fmt) g(a float) { - if strconv.FloatSize == 32 { - x.fmt_g32(float32(a)) - } else { - x.fmt_g64(float64(a)) - } -} - -func (x *fmt) fb(a float) { - if strconv.FloatSize == 32 { - x.fmt_fb32(float32(a)) - } else { - x.fmt_fb64(float64(a)) - } -} diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go index 412260441..d6dc8eb3d 100644 --- a/src/pkg/fmt/print.go +++ b/src/pkg/fmt/print.go @@ -74,15 +74,42 @@ type pp struct { fmt fmt } -// A leaky bucket of reusable pp structures. -var ppFree = make(chan *pp, 100) +// A cache holds a set of reusable objects. +// The buffered channel holds the currently available objects. +// If more are needed, the cache creates them by calling new. +type cache struct { + saved chan interface{} + new func() interface{} +} + +func (c *cache) put(x interface{}) { + select { + case c.saved <- x: + // saved in cache + default: + // discard + } +} -// Allocate a new pp struct. Probably can grab the previous one from ppFree. -func newPrinter() *pp { - p, ok := <-ppFree - if !ok { - p = new(pp) +func (c *cache) get() interface{} { + select { + case x := <-c.saved: + return x // reused from cache + default: + return c.new() } + panic("not reached") +} + +func newCache(f func() interface{}) *cache { + return &cache{make(chan interface{}, 100), f} +} + +var ppFree = newCache(func() interface{} { return new(pp) }) + +// Allocate a new pp struct or grab a cached one. +func newPrinter() *pp { + p := ppFree.get().(*pp) p.fmt.init(&p.buf) return p } @@ -94,7 +121,7 @@ func (p *pp) free() { return } p.buf.Reset() - _ = ppFree <- p + ppFree.put(p) } func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent } @@ -573,26 +600,12 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth case bool: p.fmtBool(f, verb, field) return false - case float: - if floatBits == 32 { - p.fmtFloat32(float32(f), verb, field) - } else { - p.fmtFloat64(float64(f), verb, field) - } - return false case float32: p.fmtFloat32(f, verb, field) return false case float64: p.fmtFloat64(f, verb, field) return false - case complex: - if complexBits == 64 { - p.fmtComplex64(complex64(f), verb, field) - } else { - p.fmtComplex128(complex128(f), verb, field) - } - return false case complex64: p.fmtComplex64(complex64(f), verb, field) return false diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go index dcc42bc92..a408c42aa 100644 --- a/src/pkg/fmt/scan.go +++ b/src/pkg/fmt/scan.go @@ -303,15 +303,11 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) { } -// A leaky bucket of reusable ss structures. -var ssFree = make(chan *ss, 100) +var ssFree = newCache(func() interface{} { return new(ss) }) -// Allocate a new ss struct. Probably can grab the previous one from ssFree. +// Allocate a new ss struct or grab a cached one. func newScanState(r io.Reader, nlIsSpace bool) *ss { - s, ok := <-ssFree - if !ok { - s = new(ss) - } + s := ssFree.get().(*ss) if rr, ok := r.(readRuner); ok { s.rr = rr } else { @@ -333,7 +329,7 @@ func (s *ss) free() { } s.buf.Reset() s.rr = nil - _ = ssFree <- s + ssFree.put(s) } // skipSpace skips spaces and maybe newlines. @@ -640,7 +636,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 { sreal, simag := s.complexTokens() real := s.convertFloat(sreal, n/2) imag := s.convertFloat(simag, n/2) - return cmplx(real, imag) + return complex(real, imag) } // convertString returns the string represented by the next input characters. @@ -772,8 +768,6 @@ func (s *ss) scanOne(verb int, field interface{}) { switch v := field.(type) { case *bool: *v = s.scanBool(verb) - case *complex: - *v = complex(s.scanComplex(verb, int(complexBits))) case *complex64: *v = complex64(s.scanComplex(verb, 64)) case *complex128: @@ -802,11 +796,6 @@ func (s *ss) scanOne(verb int, field interface{}) { *v = uintptr(s.scanUint(verb, uintptrBits)) // Floats are tricky because you want to scan in the precision of the result, not // scan in high precision and convert, in order to preserve the correct error condition. - case *float: - if s.okVerb(verb, floatVerbs, "float") { - s.skipSpace(false) - *v = float(s.convertFloat(s.floatToken(), int(floatBits))) - } case *float32: if s.okVerb(verb, floatVerbs, "float32") { s.skipSpace(false) diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go index fe5ee1d61..78b9fbb4a 100644 --- a/src/pkg/fmt/scan_test.go +++ b/src/pkg/fmt/scan_test.go @@ -50,13 +50,11 @@ var ( uint16Val uint16 uint32Val uint32 uint64Val uint64 - floatVal float float32Val float32 float64Val float64 stringVal string stringVal1 string bytesVal []byte - complexVal complex complex64Val complex64 complex128Val complex128 renamedBoolVal renamedBool @@ -73,10 +71,8 @@ var ( renamedUintptrVal renamedUintptr renamedStringVal renamedString renamedBytesVal renamedBytes - renamedFloatVal renamedFloat renamedFloat32Val renamedFloat32 renamedFloat64Val renamedFloat64 - renamedComplexVal renamedComplex renamedComplex64Val renamedComplex64 renamedComplex128Val renamedComplex128 ) @@ -161,12 +157,12 @@ var scanTests = []ScanTest{ {"30\n", &uint64Val, uint64(30)}, {"255\n", &uint8Val, uint8(255)}, {"32767\n", &int16Val, int16(32767)}, - {"2.3\n", &floatVal, 2.3}, + {"2.3\n", &float64Val, 2.3}, {"2.3e1\n", &float32Val, float32(2.3e1)}, - {"2.3e2\n", &float64Val, float64(2.3e2)}, + {"2.3e2\n", &float64Val, 2.3e2}, {"2.35\n", &stringVal, "2.35"}, {"2345678\n", &bytesVal, []byte("2345678")}, - {"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i}, + {"(3.4e1-2i)\n", &complex128Val, 3.4e1 - 2i}, {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)}, {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)}, {"hello\n", &stringVal, "hello"}, @@ -256,10 +252,8 @@ var scanfTests = []ScanfTest{ {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)}, {"%s", "114\n", &renamedStringVal, renamedString("114")}, {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))}, - {"%g", "115.1\n", &renamedFloatVal, renamedFloat(115.1)}, {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)}, {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)}, - {"%g", "11+5.1i\n", &renamedComplexVal, renamedComplex(11 + 5.1i)}, {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)}, {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)}, @@ -288,15 +282,15 @@ var overflowTests = []ScanTest{ {"65536", &uint16Val, 0}, {"1e100", &float32Val, 0}, {"1e500", &float64Val, 0}, - {"(1e100+0i)", &complexVal, 0}, + {"(1e100+0i)", &complex64Val, 0}, {"(1+1e100i)", &complex64Val, 0}, {"(1-1e500i)", &complex128Val, 0}, } var i, j, k int -var f float +var f float64 var s, t string -var c complex +var c complex128 var x, y Xs var multiTests = []ScanfMultiTest{ @@ -307,7 +301,7 @@ var multiTests = []ScanfMultiTest{ {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""}, {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""}, {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""}, - {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), float(2.5)), ""}, + {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""}, {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""}, {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""}, @@ -409,7 +403,7 @@ func TestScanOverflow(t *testing.T) { } func verifyNaN(str string, t *testing.T) { - var f float + var f float64 var f32 float32 var f64 float64 text := str + " " + str + " " + str @@ -432,7 +426,7 @@ func TestNaN(t *testing.T) { } func verifyInf(str string, t *testing.T) { - var f float + var f float64 var f32 float32 var f64 float64 text := str + " " + str + " " + str diff --git a/src/pkg/fmt/stringer_test.go b/src/pkg/fmt/stringer_test.go index 815147e1a..0ca3f522d 100644 --- a/src/pkg/fmt/stringer_test.go +++ b/src/pkg/fmt/stringer_test.go @@ -20,7 +20,7 @@ type TU16 uint16 type TU32 uint32 type TU64 uint64 type TUI uintptr -type TF float +type TF float64 type TF32 float32 type TF64 float64 type TB bool @@ -37,7 +37,7 @@ func (v TU16) String() string { return Sprintf("U16: %d", uint16(v)) } func (v TU32) String() string { return Sprintf("U32: %d", uint32(v)) } func (v TU64) String() string { return Sprintf("U64: %d", uint64(v)) } func (v TUI) String() string { return Sprintf("UI: %d", uintptr(v)) } -func (v TF) String() string { return Sprintf("F: %f", float(v)) } +func (v TF) String() string { return Sprintf("F: %f", float64(v)) } func (v TF32) String() string { return Sprintf("F32: %f", float32(v)) } func (v TF64) String() string { return Sprintf("F64: %f", float64(v)) } func (v TB) String() string { return Sprintf("B: %t", bool(v)) } diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go index cf2ce36df..2e8f0973f 100644 --- a/src/pkg/go/ast/ast.go +++ b/src/pkg/go/ast/ast.go @@ -535,6 +535,13 @@ type ( X Expr // expression } + // A SendStmt node represents a send statement. + SendStmt struct { + Chan Expr + Arrow token.Pos // position of "<-" + Value Expr + } + // An IncDecStmt node represents an increment or decrement statement. IncDecStmt struct { X Expr @@ -629,11 +636,10 @@ type ( // A CommClause node represents a case of a select statement. CommClause struct { - Case token.Pos // position of "case" or "default" keyword - Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil) - Lhs, Rhs Expr // Rhs == nil means default case - Colon token.Pos // position of ":" - Body []Stmt // statement list; or nil + Case token.Pos // position of "case" or "default" keyword + Comm Stmt // send or receive statement; nil means default case + Colon token.Pos // position of ":" + Body []Stmt // statement list; or nil } // An SelectStmt node represents a select statement. @@ -670,6 +676,7 @@ func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() } func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon } func (s *LabeledStmt) Pos() token.Pos { return s.Label.Pos() } func (s *ExprStmt) Pos() token.Pos { return s.X.Pos() } +func (s *SendStmt) Pos() token.Pos { return s.Chan.Pos() } func (s *IncDecStmt) Pos() token.Pos { return s.X.Pos() } func (s *AssignStmt) Pos() token.Pos { return s.Lhs[0].Pos() } func (s *GoStmt) Pos() token.Pos { return s.Go } @@ -695,6 +702,7 @@ func (s *EmptyStmt) End() token.Pos { } func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() } func (s *ExprStmt) End() token.Pos { return s.X.End() } +func (s *SendStmt) End() token.Pos { return s.Value.End() } func (s *IncDecStmt) End() token.Pos { return s.TokPos + 2 /* len("++") */ } @@ -753,6 +761,7 @@ func (s *DeclStmt) stmtNode() {} func (s *EmptyStmt) stmtNode() {} func (s *LabeledStmt) stmtNode() {} func (s *ExprStmt) stmtNode() {} +func (s *SendStmt) stmtNode() {} func (s *IncDecStmt) stmtNode() {} func (s *AssignStmt) stmtNode() {} func (s *GoStmt) stmtNode() {} diff --git a/src/pkg/go/ast/walk.go b/src/pkg/go/ast/walk.go index 875a92f3f..a77f8ee5e 100644 --- a/src/pkg/go/ast/walk.go +++ b/src/pkg/go/ast/walk.go @@ -195,6 +195,10 @@ func Walk(v Visitor, node Node) { case *ExprStmt: Walk(v, n.X) + case *SendStmt: + Walk(v, n.Chan) + Walk(v, n.Value) + case *IncDecStmt: Walk(v, n.X) @@ -258,11 +262,8 @@ func Walk(v Visitor, node Node) { Walk(v, n.Body) case *CommClause: - if n.Lhs != nil { - Walk(v, n.Lhs) - } - if n.Rhs != nil { - Walk(v, n.Rhs) + if n.Comm != nil { + Walk(v, n.Comm) } walkStmtList(v, n.Body) diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go index fb1c4e03d..e46857cb8 100644 --- a/src/pkg/go/doc/doc.go +++ b/src/pkg/go/doc/doc.go @@ -154,7 +154,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) { // determine values list const threshold = 0.75 values := &doc.values - if domName != "" && domFreq >= int(float(len(decl.Specs))*threshold) { + if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) { // typed entries are sufficiently frequent typ := doc.lookupTypeDoc(domName) if typ != nil { diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index 3b2fe4577..2395b8158 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -70,7 +70,8 @@ func scannerMode(mode uint) uint { func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) { - p.file = p.scanner.Init(fset, filename, src, p, scannerMode(mode)) + p.file = fset.AddFile(filename, fset.Base(), len(src)) + p.scanner.Init(p.file, src, p, scannerMode(mode)) p.mode = mode p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently) p.next() @@ -1192,18 +1193,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { x := p.parseExprList() switch p.tok { - case token.COLON: - // labeled statement - colon := p.pos - p.next() - if labelOk && len(x) == 1 { - if label, isIdent := x[0].(*ast.Ident); isIdent { - return &ast.LabeledStmt{label, colon, p.parseStmt()} - } - } - p.error(x[0].Pos(), "illegal label declaration") - return &ast.BadStmt{x[0].Pos(), colon + 1} - case token.DEFINE, token.ASSIGN, token.ADD_ASSIGN, token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN, @@ -1217,11 +1206,29 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { } if len(x) > 1 { - p.error(x[0].Pos(), "only one expression allowed") + p.errorExpected(x[0].Pos(), "1 expression") // continue with first expression } - if p.tok == token.INC || p.tok == token.DEC { + switch p.tok { + case token.COLON: + // labeled statement + colon := p.pos + p.next() + if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent { + return &ast.LabeledStmt{label, colon, p.parseStmt()} + } + p.error(x[0].Pos(), "illegal label declaration") + return &ast.BadStmt{x[0].Pos(), colon + 1} + + case token.ARROW: + // send statement + arrow := p.pos + p.next() // consume "<-" + y := p.parseExpr() + return &ast.SendStmt{x[0], arrow, y} + + case token.INC, token.DEC: // increment or decrement s := &ast.IncDecStmt{x[0], p.pos, p.tok} p.next() // consume "++" or "--" @@ -1485,28 +1492,52 @@ func (p *parser) parseCommClause() *ast.CommClause { // CommCase pos := p.pos - var tok token.Token - var lhs, rhs ast.Expr + var comm ast.Stmt if p.tok == token.CASE { p.next() + lhs := p.parseExprList() if p.tok == token.ARROW { - // RecvExpr without assignment - rhs = p.parseExpr() + // SendStmt + if len(lhs) > 1 { + p.errorExpected(lhs[0].Pos(), "1 expression") + // continue with first expression + } + arrow := p.pos + p.next() + rhs := p.parseExpr() + comm = &ast.SendStmt{lhs[0], arrow, rhs} } else { - // SendExpr or RecvExpr - rhs = p.parseExpr() + // RecvStmt + pos := p.pos + tok := p.tok + var rhs ast.Expr if p.tok == token.ASSIGN || p.tok == token.DEFINE { - // RecvExpr with assignment - tok = p.tok + // RecvStmt with assignment + if len(lhs) > 2 { + p.errorExpected(lhs[0].Pos(), "1 or 2 expressions") + // continue with first two expressions + lhs = lhs[0:2] + } p.next() - lhs = rhs - if p.tok == token.ARROW { - rhs = p.parseExpr() - } else { - p.expect(token.ARROW) // use expect() error handling + rhs = p.parseExpr() + } else { + // rhs must be single receive operation + if len(lhs) > 1 { + p.errorExpected(lhs[0].Pos(), "1 expression") + // continue with first expression } + rhs = lhs[0] + lhs = nil // there is no lhs + } + if x, isUnary := rhs.(*ast.UnaryExpr); !isUnary || x.Op != token.ARROW { + p.errorExpected(rhs.Pos(), "send or receive operation") + rhs = &ast.BadExpr{rhs.Pos(), rhs.End()} + } + if lhs != nil { + comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}} + } else { + comm = &ast.ExprStmt{rhs} } - // else SendExpr } } else { p.expect(token.DEFAULT) @@ -1515,7 +1546,7 @@ func (p *parser) parseCommClause() *ast.CommClause { colon := p.expect(token.COLON) body := p.parseStmtList() - return &ast.CommClause{pos, tok, lhs, rhs, colon, body} + return &ast.CommClause{pos, comm, colon, body} } @@ -1567,7 +1598,7 @@ func (p *parser) parseForStmt() ast.Stmt { } // check rhs if len(as.Rhs) != 1 { - p.errorExpected(as.Rhs[0].Pos(), "1 expressions") + p.errorExpected(as.Rhs[0].Pos(), "1 expression") return &ast.BadStmt{pos, body.End()} } if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE { diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go index 56bd80ef1..5a7f05ca8 100644 --- a/src/pkg/go/parser/parser_test.go +++ b/src/pkg/go/parser/parser_test.go @@ -46,6 +46,7 @@ var validPrograms = []interface{}{ `package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`, `package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`, `package main; var a = T{{1, 2}, {3, 4}}`, + `package main; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`, } diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go index 1ee0846f6..7933c2f18 100644 --- a/src/pkg/go/printer/nodes.go +++ b/src/pkg/go/printer/nodes.go @@ -228,7 +228,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp useFF = false } else { const r = 4 // threshold - ratio := float(size) / float(prevSize) + ratio := float64(size) / float64(prevSize) useFF = ratio <= 1/r || r <= ratio } } @@ -506,12 +506,12 @@ const ( ) -func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) { +func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { switch e.Op.Precedence() { + case 4: + has4 = true case 5: has5 = true - case 6: - has6 = true } switch l := e.X.(type) { @@ -521,9 +521,9 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) { // pretend this is an *ast.ParenExpr and do nothing. break } - h5, h6, mp := walkBinary(l) + h4, h5, mp := walkBinary(l) + has4 = has4 || h4 has5 = has5 || h5 - has6 = has6 || h6 if maxProblem < mp { maxProblem = mp } @@ -536,25 +536,25 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) { // pretend this is an *ast.ParenExpr and do nothing. break } - h5, h6, mp := walkBinary(r) + h4, h5, mp := walkBinary(r) + has4 = has4 || h4 has5 = has5 || h5 - has6 = has6 || h6 if maxProblem < mp { maxProblem = mp } case *ast.StarExpr: if e.Op.String() == "/" { - maxProblem = 6 + maxProblem = 5 } case *ast.UnaryExpr: switch e.Op.String() + r.Op.String() { case "/*", "&&", "&^": - maxProblem = 6 + maxProblem = 5 case "++", "--": - if maxProblem < 5 { - maxProblem = 5 + if maxProblem < 4 { + maxProblem = 4 } } } @@ -563,20 +563,20 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) { func cutoff(e *ast.BinaryExpr, depth int) int { - has5, has6, maxProblem := walkBinary(e) + has4, has5, maxProblem := walkBinary(e) if maxProblem > 0 { return maxProblem + 1 } - if has5 && has6 { + if has4 && has5 { if depth == 1 { - return 6 + return 5 } - return 5 + return 4 } if depth == 1 { - return 7 + return 6 } - return 5 + return 4 } @@ -603,15 +603,14 @@ func reduceDepth(depth int) int { // (Algorithm suggestion by Russ Cox.) // // The precedences are: -// 6 * / % << >> & &^ -// 5 + - | ^ -// 4 == != < <= > >= -// 3 <- +// 5 * / % << >> & &^ +// 4 + - | ^ +// 3 == != < <= > >= // 2 && // 1 || // -// The only decision is whether there will be spaces around levels 5 and 6. -// There are never spaces at level 7 (unary), and always spaces at levels 4 and below. +// The only decision is whether there will be spaces around levels 4 and 5. +// There are never spaces at level 6 (unary), and always spaces at levels 3 and below. // // To choose the cutoff, look at the whole expression but excluding primary // expressions (function calls, parenthesized exprs), and apply these rules: @@ -619,21 +618,21 @@ func reduceDepth(depth int) int { // 1) If there is a binary operator with a right side unary operand // that would clash without a space, the cutoff must be (in order): // -// /* 7 -// && 7 -// &^ 7 -// ++ 6 -// -- 6 +// /* 6 +// && 6 +// &^ 6 +// ++ 5 +// -- 5 // // (Comparison operators always have spaces around them.) // -// 2) If there is a mix of level 6 and level 5 operators, then the cutoff -// is 6 (use spaces to distinguish precedence) in Normal mode -// and 5 (never use spaces) in Compact mode. +// 2) If there is a mix of level 5 and level 4 operators, then the cutoff +// is 5 (use spaces to distinguish precedence) in Normal mode +// and 4 (never use spaces) in Compact mode. // -// 3) If there are no level 5 operators or no level 6 operators, then the -// cutoff is 7 (always use spaces) in Normal mode -// and 5 (never use spaces) in Compact mode. +// 3) If there are no level 4 operators or no level 5 operators, then the +// cutoff is 6 (always use spaces) in Normal mode +// and 4 (never use spaces) in Compact mode. // // Sets multiLine to true if the binary expression spans multiple lines. func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) { @@ -872,7 +871,10 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi } p.print(x.Lbrace, token.LBRACE) p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace) - p.print(x.Rbrace, token.RBRACE) + // do not insert extra line breaks because of comments before + // the closing '}' as it might break the code if there is no + // trailing ',' + p.print(noExtraLinebreak, x.Rbrace, token.RBRACE, noExtraLinebreak) case *ast.Ellipsis: p.print(token.ELLIPSIS) @@ -1080,6 +1082,12 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { const depth = 1 p.expr0(s.X, depth, multiLine) + case *ast.SendStmt: + const depth = 1 + p.expr0(s.Chan, depth, multiLine) + p.print(blank, s.Arrow, token.ARROW, blank) + p.expr0(s.Value, depth, multiLine) + case *ast.IncDecStmt: const depth = 1 p.expr0(s.X, depth+1, multiLine) @@ -1176,13 +1184,9 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { *multiLine = true case *ast.CommClause: - if s.Rhs != nil { + if s.Comm != nil { p.print(token.CASE, blank) - if s.Lhs != nil { - p.expr(s.Lhs, multiLine) - p.print(blank, s.Tok, blank) - } - p.expr(s.Rhs, multiLine) + p.stmt(s.Comm, false, ignoreMultiLine) } else { p.print(token.DEFAULT) } @@ -1388,7 +1392,7 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi if isLit { sep = blank } - p.print(sep, b.Pos(), token.LBRACE) + p.print(sep, b.Lbrace, token.LBRACE) if len(b.List) > 0 { p.print(blank) for i, s := range b.List { diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go index a4ddad50e..34b0c4e2d 100644 --- a/src/pkg/go/printer/printer.go +++ b/src/pkg/go/printer/printer.go @@ -58,6 +58,15 @@ var infinity = 1 << 30 var ignoreMultiLine = new(bool) +// A pmode value represents the current printer mode. +type pmode int + +const ( + inLiteral pmode = 1 << iota + noExtraLinebreak +) + + type printer struct { // Configuration (does not change after initialization) output io.Writer @@ -69,7 +78,7 @@ type printer struct { nesting int // nesting level (0: top-level (package scope), >0: functions/decls.) written int // number of bytes written indent int // current indentation - escape bool // true if in escape sequence + mode pmode // current printer mode lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) // Buffered whitespace @@ -162,7 +171,7 @@ func (p *printer) write(data []byte) { p.pos.Line++ p.pos.Column = 1 - if !p.escape { + if p.mode&inLiteral == 0 { // write indentation // use "hard" htabs - indentation columns // must not be discarded by the tabwriter @@ -211,7 +220,7 @@ func (p *printer) write(data []byte) { } case tabwriter.Escape: - p.escape = !p.escape + p.mode ^= inLiteral // ignore escape chars introduced by printer - they are // invisible and must not affect p.pos (was issue #1089) @@ -272,7 +281,7 @@ func (p *printer) writeItem(pos token.Position, data []byte, tag HTMLTag) { // (used when printing merged ASTs of different files // e.g., the result of ast.MergePackageFiles) p.indent = 0 - p.escape = false + p.mode = 0 p.buffer = p.buffer[0:0] fileChanged = true } @@ -683,9 +692,13 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro // follows on the same line: separate with an extra blank p.write([]byte{' '}) } - // ensure that there is a newline after a //-style comment - // or if we are before a closing '}' or at the end of a file - return p.writeCommentSuffix(last.Text[1] == '/' || tok == token.RBRACE || tok == token.EOF) + // ensure that there is a line break after a //-style comment, + // before a closing '}' unless explicitly disabled, or at eof + needsLinebreak := + last.Text[1] == '/' || + tok == token.RBRACE && p.mode&noExtraLinebreak == 0 || + tok == token.EOF + return p.writeCommentSuffix(needsLinebreak) } // no comment was written - we should never reach here since @@ -787,6 +800,9 @@ func (p *printer) print(args ...interface{}) { var tok token.Token switch x := f.(type) { + case pmode: + // toggle printer mode + p.mode ^= x case whiteSpace: if x == ignore { // don't add ignore's to the buffer; they @@ -818,10 +834,14 @@ func (p *printer) print(args ...interface{}) { data = x.Value } // escape all literals so they pass through unchanged - // (note that valid Go programs cannot contain esc ('\xff') - // bytes since they do not appear in legal UTF-8 sequences) - // TODO(gri): do this more efficiently. - data = []byte("\xff" + string(data) + "\xff") + // (note that valid Go programs cannot contain + // tabwriter.Escape bytes since they do not appear in + // legal UTF-8 sequences) + escData := make([]byte, 0, len(data)+2) + escData = append(escData, tabwriter.Escape) + escData = append(escData, data...) + escData = append(escData, tabwriter.Escape) + data = escData tok = x.Kind case token.Token: s := x.String() diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden index 200ea332f..a86d66174 100644 --- a/src/pkg/go/printer/testdata/comments.golden +++ b/src/pkg/go/printer/testdata/comments.golden @@ -422,7 +422,7 @@ func _() { func ( /* comment1 */ T /* comment2 */ ) _() {} -func _() { /* one-liner */ +func _() { /* one-line functions with comments are formatted as multi-line functions */ } func _() { @@ -430,6 +430,10 @@ func _() { /* closing curly brace should be on new line */ } +func _() { + _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ } +} + // Comments immediately adjacent to punctuation (for which the go/printer // may obly have estimated position information) must remain after the punctuation. diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input index 4a9ea4742..14cd4cf7a 100644 --- a/src/pkg/go/printer/testdata/comments.input +++ b/src/pkg/go/printer/testdata/comments.input @@ -422,12 +422,16 @@ func _() { func (/* comment1 */ T /* comment2 */) _() {} -func _() { /* one-liner */ } +func _() { /* one-line functions with comments are formatted as multi-line functions */ } func _() { _ = 0 /* closing curly brace should be on new line */ } +func _() { + _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */} +} + // Comments immediately adjacent to punctuation (for which the go/printer // may obly have estimated position information) must remain after the punctuation. diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go index 6ce846cd8..8c3205230 100644 --- a/src/pkg/go/scanner/scanner.go +++ b/src/pkg/go/scanner/scanner.go @@ -96,24 +96,28 @@ const ( InsertSemis // automatically insert semicolons ) -// TODO(gri) Would it be better to simply provide *token.File to Init -// instead of fset, and filename, and then return the file? -// It could cause an error/panic if the provided file.Size() -// doesn't match len(src). - -// Init prepares the scanner S to tokenize the text src. It sets the -// scanner at the beginning of the source text, adds a new file with -// the given filename to the file set fset, and returns that file. +// Init prepares the scanner S to tokenize the text src by setting the +// scanner at the beginning of src. The scanner uses the file set file +// for position information and it adds line information for each line. +// It is ok to re-use the same file when re-scanning the same file as +// line information which is already present is ignored. Init causes a +// panic if the file size does not match the src size. // // Calls to Scan will use the error handler err if they encounter a // syntax error and err is not nil. Also, for each error encountered, // the Scanner field ErrorCount is incremented by one. The mode parameter // determines how comments, illegal characters, and semicolons are handled. // -func (S *Scanner) Init(fset *token.FileSet, filename string, src []byte, err ErrorHandler, mode uint) *token.File { +// Note that Init may call err if there is an error in the first character +// of the file. +// +func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint) { // Explicitly initialize all fields since a scanner may be reused. - S.file = fset.AddFile(filename, fset.Base(), len(src)) - S.dir, _ = path.Split(filename) + if file.Size() != len(src) { + panic("file size does not match src len") + } + S.file = file + S.dir, _ = path.Split(file.Name()) S.src = src S.err = err S.mode = mode @@ -126,8 +130,6 @@ func (S *Scanner) Init(fset *token.FileSet, filename string, src []byte, err Err S.ErrorCount = 0 S.next() - - return S.file } diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go index b1004f89d..c622ff482 100644 --- a/src/pkg/go/scanner/scanner_test.go +++ b/src/pkg/go/scanner/scanner_test.go @@ -223,12 +223,12 @@ func TestScan(t *testing.T) { for _, e := range tokens { src += e.lit + whitespace } - src_linecount := newlineCount(src) + 1 + src_linecount := newlineCount(src) whitespace_linecount := newlineCount(whitespace) // verify scan var s Scanner - s.Init(fset, "", []byte(src), &testErrorHandler{t}, ScanComments) + s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &testErrorHandler{t}, ScanComments) index := 0 epos := token.Position{"", 0, 1, 1} // expected position for { @@ -241,7 +241,7 @@ func TestScan(t *testing.T) { if tok == token.EOF { lit = "<EOF>" epos.Line = src_linecount - epos.Column = 1 + epos.Column = 2 } checkPos(t, lit, pos, epos) if tok != e.tok { @@ -273,7 +273,8 @@ func TestScan(t *testing.T) { func checkSemi(t *testing.T, line string, mode uint) { var S Scanner - file := S.Init(fset, "TestSemis", []byte(line), nil, mode) + file := fset.AddFile("TestSemis", fset.Base(), len(line)) + S.Init(file, []byte(line), nil, mode) pos, tok, lit := S.Scan() for tok != token.EOF { if tok == token.ILLEGAL { @@ -476,7 +477,8 @@ func TestLineComments(t *testing.T) { // verify scan var S Scanner - file := S.Init(fset, "dir/TestLineComments", []byte(src), nil, 0) + file := fset.AddFile("dir/TestLineComments", fset.Base(), len(src)) + S.Init(file, []byte(src), nil, 0) for _, s := range segments { p, _, lit := S.Scan() pos := file.Position(p) @@ -495,7 +497,8 @@ func TestInit(t *testing.T) { // 1st init src1 := "if true { }" - f1 := s.Init(fset, "", []byte(src1), nil, 0) + f1 := fset.AddFile("src1", fset.Base(), len(src1)) + s.Init(f1, []byte(src1), nil, 0) if f1.Size() != len(src1) { t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1)) } @@ -508,7 +511,8 @@ func TestInit(t *testing.T) { // 2nd init src2 := "go true { ]" - f2 := s.Init(fset, "", []byte(src2), nil, 0) + f2 := fset.AddFile("src2", fset.Base(), len(src2)) + s.Init(f2, []byte(src2), nil, 0) if f2.Size() != len(src2) { t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2)) } @@ -527,7 +531,8 @@ func TestIllegalChars(t *testing.T) { var s Scanner const src = "*?*$*@*" - file := s.Init(fset, "", []byte(src), &testErrorHandler{t}, AllowIllegalChars) + file := fset.AddFile("", fset.Base(), len(src)) + s.Init(file, []byte(src), &testErrorHandler{t}, AllowIllegalChars) for offs, ch := range src { pos, tok, lit := s.Scan() if poffs := file.Offset(pos); poffs != offs { @@ -556,7 +561,7 @@ func TestStdErrorHander(t *testing.T) { v := new(ErrorVector) var s Scanner - s.Init(fset, "File1", []byte(src), v, 0) + s.Init(fset.AddFile("File1", fset.Base(), len(src)), []byte(src), v, 0) for { if _, tok, _ := s.Scan(); tok == token.EOF { break @@ -604,7 +609,7 @@ func (h *errorCollector) Error(pos token.Position, msg string) { func checkError(t *testing.T, src string, tok token.Token, pos int, err string) { var s Scanner var h errorCollector - s.Init(fset, "", []byte(src), &h, ScanComments) + s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), &h, ScanComments) _, tok0, _ := s.Scan() _, tok1, _ := s.Scan() if tok0 != tok { diff --git a/src/pkg/go/token/position.go b/src/pkg/go/token/position.go index 0044a0ed7..809e53f0a 100644 --- a/src/pkg/go/token/position.go +++ b/src/pkg/go/token/position.go @@ -153,7 +153,7 @@ type lineInfo struct { // AddLineInfo adds alternative file and line number information for // a given file offset. The offset must be larger than the offset for -// the previously added alternative line info and not larger than the +// the previously added alternative line info and smaller than the // file size; otherwise the information is ignored. // // AddLineInfo is typically used to register alternative position @@ -161,7 +161,7 @@ type lineInfo struct { // func (f *File) AddLineInfo(offset int, filename string, line int) { f.set.mutex.Lock() - if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset <= f.size { + if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset < f.size { f.infos = append(f.infos, lineInfo{offset, filename, line}) } f.set.mutex.Unlock() @@ -212,27 +212,30 @@ func (f *File) LineCount() int { // AddLine adds the line offset for a new line. // The line offset must be larger than the offset for the previous line -// and not larger than the file size; otherwise the line offset is ignored. +// and smaller than the file size; otherwise the line offset is ignored. // func (f *File) AddLine(offset int) { f.set.mutex.Lock() - if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset <= f.size { + if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset < f.size { f.lines = append(f.lines, offset) } f.set.mutex.Unlock() } -// SetLines sets all line offsets for a file and returns true if successful. +// SetLines sets the line offsets for a file and returns true if successful. +// The line offsets are the offsets of the first character of each line; +// for instance for the content "ab\nc\n" the line offsets are {0, 3}. +// An empty file has an empty line offset table. // Each line offset must be larger than the offset for the previous line -// and not larger than the file size; otherwise the SetLines fails and returns +// and smaller than the file size; otherwise SetLines fails and returns // false. // func (f *File) SetLines(lines []int) bool { // verify validity of lines table size := f.size for i, offset := range lines { - if i > 0 && offset <= lines[i-1] || size < offset { + if i > 0 && offset <= lines[i-1] || size <= offset { return false } } @@ -245,6 +248,27 @@ func (f *File) SetLines(lines []int) bool { } +// SetLinesForContent sets the line offsets for the given file content. +func (f *File) SetLinesForContent(content []byte) { + var lines []int + line := 0 + for offset, b := range content { + if line >= 0 { + lines = append(lines, line) + } + line = -1 + if b == '\n' { + line = offset + 1 + } + } + + // set lines table + f.set.mutex.Lock() + f.lines = lines + f.set.mutex.Unlock() +} + + // Pos returns the Pos value for the given file offset; // the offset must be <= f.Size(). // f.Pos(f.Offset(p)) == p. diff --git a/src/pkg/go/token/position_test.go b/src/pkg/go/token/position_test.go index 1cffcc3c2..979c9b1e8 100644 --- a/src/pkg/go/token/position_test.go +++ b/src/pkg/go/token/position_test.go @@ -39,14 +39,18 @@ func TestNoPos(t *testing.T) { var tests = []struct { filename string + source []byte // may be nil size int lines []int }{ - {"a", 0, []int{}}, - {"b", 5, []int{0}}, - {"c", 10, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}, - {"d", 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}}, - {"e", 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}}, + {"a", []byte{}, 0, []int{}}, + {"b", []byte("01234"), 5, []int{0}}, + {"c", []byte("\n\n\n\n\n\n\n\n\n"), 9, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}}, + {"d", nil, 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}}, + {"e", nil, 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}}, + {"f", []byte("package p\n\nimport \"fmt\""), 23, []int{0, 10, 11}}, + {"g", []byte("package p\n\nimport \"fmt\"\n"), 24, []int{0, 10, 11}}, + {"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}}, } @@ -77,10 +81,26 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) { } +func makeTestSource(size int, lines []int) []byte { + src := make([]byte, size) + for _, offs := range lines { + if offs > 0 { + src[offs-1] = '\n' + } + } + return src +} + + func TestPositions(t *testing.T) { const delta = 7 // a non-zero base offset increment fset := NewFileSet() for _, test := range tests { + // verify consistency of test case + if test.source != nil && len(test.source) != test.size { + t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source)) + } + // add file and verify name and size f := fset.AddFile(test.filename, fset.Base()+delta, test.size) if f.Name() != test.filename { @@ -107,15 +127,26 @@ func TestPositions(t *testing.T) { verifyPositions(t, fset, f, test.lines[0:i+1]) } - // add lines at once and verify all positions - ok := f.SetLines(test.lines) - if !ok { + // add lines with SetLines and verify all positions + if ok := f.SetLines(test.lines); !ok { t.Errorf("%s: SetLines failed", f.Name()) } if f.LineCount() != len(test.lines) { t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount()) } verifyPositions(t, fset, f, test.lines) + + // add lines with SetLinesForContent and verify all positions + src := test.source + if src == nil { + // no test source available - create one from scratch + src = makeTestSource(test.size, test.lines) + } + f.SetLinesForContent(src) + if f.LineCount() != len(test.lines) { + t.Errorf("%s, SetLinesForContent: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount()) + } + verifyPositions(t, fset, f, test.lines) } } diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go index 1bd81c1b1..2a2d3ecc4 100644 --- a/src/pkg/go/token/token.go +++ b/src/pkg/go/token/token.go @@ -252,8 +252,8 @@ func (tok Token) String() string { // const ( LowestPrec = 0 // non-operators - UnaryPrec = 7 - HighestPrec = 8 + UnaryPrec = 6 + HighestPrec = 7 ) @@ -267,14 +267,12 @@ func (op Token) Precedence() int { return 1 case LAND: return 2 - case ARROW: - return 3 case EQL, NEQ, LSS, LEQ, GTR, GEQ: - return 4 + return 3 case ADD, SUB, OR, XOR: - return 5 + return 4 case MUL, QUO, REM, SHL, SHR, AND, AND_NOT: - return 6 + return 5 } return LowestPrec } diff --git a/src/pkg/go/typechecker/typechecker_test.go b/src/pkg/go/typechecker/typechecker_test.go index 9c5b52e41..33f4a6223 100644 --- a/src/pkg/go/typechecker/typechecker_test.go +++ b/src/pkg/go/typechecker/typechecker_test.go @@ -68,7 +68,8 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) { } var s scanner.Scanner - s.Init(fset, filename, src, nil, scanner.ScanComments) + file := fset.AddFile(filename, fset.Base(), len(src)) + s.Init(file, src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment token loop: for { diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go index d150dbe9a..fe1f60ba7 100644 --- a/src/pkg/gob/codec_test.go +++ b/src/pkg/gob/codec_test.go @@ -58,7 +58,7 @@ func TestUintCodec(t *testing.T) { t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes()) } } - decState := newDecodeState(nil, &b) + decState := newDecodeState(nil, b) for u := uint64(0); ; u = (u + 1) * 7 { b.Reset() encState.encodeUint(u) @@ -77,7 +77,7 @@ func verifyInt(i int64, t *testing.T) { var b = new(bytes.Buffer) encState := newEncoderState(nil, b) encState.encodeInt(i) - decState := newDecodeState(nil, &b) + decState := newDecodeState(nil, b) decState.buf = make([]byte, 8) j := decState.decodeInt() if i != j { @@ -254,18 +254,6 @@ func TestScalarEncInstructions(t *testing.T) { } } - // float - { - b.Reset() - data := struct{ a float }{17} - instr := &encInstr{encFloat, 6, 0, 0} - state := newencoderState(b) - instr.op(instr, state, unsafe.Pointer(&data)) - if !bytes.Equal(floatResult, b.Bytes()) { - t.Errorf("float enc instructions: expected % x got % x", floatResult, b.Bytes()) - } - } - // float32 { b.Reset() @@ -327,7 +315,7 @@ func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p un func newDecodeStateFromData(data []byte) *decodeState { b := bytes.NewBuffer(data) - state := newDecodeState(nil, &b) + state := newDecodeState(nil, b) state.fieldnum = -1 return state } @@ -492,19 +480,6 @@ func TestScalarDecInstructions(t *testing.T) { } } - // float - { - var data struct { - a float - } - instr := &decInstr{decOpMap[reflect.Float], 6, 0, 0, ovfl} - state := newDecodeStateFromData(floatResult) - execDec("float", instr, state, t, unsafe.Pointer(&data)) - if data.a != 17 { - t.Errorf("float a = %v not 17", data.a) - } - } - // float32 { var data struct { @@ -531,19 +506,6 @@ func TestScalarDecInstructions(t *testing.T) { } } - // complex - { - var data struct { - a complex - } - instr := &decInstr{decOpMap[reflect.Complex], 6, 0, 0, ovfl} - state := newDecodeStateFromData(complexResult) - execDec("complex", instr, state, t, unsafe.Pointer(&data)) - if data.a != 17+19i { - t.Errorf("complex a = %v not 17+19i", data.a) - } - } - // complex64 { var data struct { @@ -605,8 +567,8 @@ func TestEndToEnd(t *testing.T) { s2 := "string2" type T1 struct { A, B, C int - M map[string]*float - N *[3]float + M map[string]*float64 + N *[3]float64 Strs *[2]string Int64s *[]int64 RI complex64 @@ -620,8 +582,8 @@ func TestEndToEnd(t *testing.T) { A: 17, B: 18, C: -5, - M: map[string]*float{"pi": &pi, "e": &e}, - N: &[3]float{1.5, 2.5, 3.5}, + M: map[string]*float64{"pi": &pi, "e": &e}, + N: &[3]float64{1.5, 2.5, 3.5}, Strs: &[2]string{s1, s2}, Int64s: &[]int64{77, 89, 123412342134}, RI: 17 - 23i, @@ -799,7 +761,7 @@ func TestOverflow(t *testing.T) { // complex64 b.Reset() it = inputT{ - Maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2), + Maxc: complex(math.MaxFloat32*2, math.MaxFloat32*2), } type outc64 struct { Maxc complex64 @@ -940,10 +902,10 @@ func TestAutoIndirection(t *testing.T) { type RT0 struct { A int B string - C float + C float64 } type RT1 struct { - C float + C float64 B string A int NotSet string @@ -973,13 +935,13 @@ type IT0 struct { A int64 B string Ignore_d []int - Ignore_e [3]float + Ignore_e [3]float64 Ignore_f bool Ignore_g string Ignore_h []byte Ignore_i *RT1 Ignore_m map[string]int - C float + C float64 } func TestIgnoredFields(t *testing.T) { @@ -1013,7 +975,7 @@ func TestIgnoredFields(t *testing.T) { type Bad0 struct { ch chan int - c float + c float64 } var nilEncoder *Encoder @@ -1109,7 +1071,7 @@ func (i Int) Square() int { return int(i * i) } -type Float float +type Float float64 func (f Float) Square() int { return int(f * f) @@ -1126,25 +1088,25 @@ func (v Vector) Square() int { } type Point struct { - a, b int + X, Y int } func (p Point) Square() int { - return p.a*p.a + p.b*p.b + return p.X*p.X + p.Y*p.Y } // A struct with interfaces in it. type InterfaceItem struct { I int Sq1, Sq2, Sq3 Squarer - F float + F float64 Sq []Squarer } // The same struct without interfaces type NoInterfaceItem struct { I int - F float + F float64 } func TestInterface(t *testing.T) { @@ -1200,15 +1162,14 @@ func TestInterface(t *testing.T) { } } } - } // A struct with all basic types, stored in interfaces. type BasicInterfaceItem struct { Int, Int8, Int16, Int32, Int64 interface{} Uint, Uint8, Uint16, Uint32, Uint64 interface{} - Float, Float32, Float64 interface{} - Complex, Complex64, Complex128 interface{} + Float32, Float64 interface{} + Complex64, Complex128 interface{} Bool interface{} String interface{} Bytes interface{} @@ -1219,8 +1180,8 @@ func TestInterfaceBasic(t *testing.T) { item1 := &BasicInterfaceItem{ int(1), int8(1), int16(1), int32(1), int64(1), uint(1), uint8(1), uint16(1), uint32(1), uint64(1), - float(1), float32(1), float64(1), - complex(0i), complex64(0i), complex128(0i), + float32(1), 1.0, + complex64(1i), complex128(1i), true, "hello", []byte("sailor"), @@ -1318,7 +1279,7 @@ func TestIgnoreInterface(t *testing.T) { type U struct { A int B string - c float + c float64 D uint } @@ -1345,6 +1306,31 @@ func TestUnexportedFields(t *testing.T) { } } +var singletons = []interface{}{ + true, + 7, + 3.2, + "hello", + [3]int{11, 22, 33}, + []float32{0.5, 0.25, 0.125}, + map[string]int{"one": 1, "two": 2}, +} + +func TestDebugSingleton(t *testing.T) { + if debugFunc == nil { + return + } + b := new(bytes.Buffer) + // Accumulate a number of values and print them out all at once. + for _, x := range singletons { + err := NewEncoder(b).Encode(x) + if err != nil { + t.Fatal("encode:", err) + } + } + debugFunc(b) +} + // A type that won't be defined in the gob until we send it in an interface value. type OnTheFly struct { A int @@ -1354,7 +1340,7 @@ type DT struct { // X OnTheFly A int B string - C float + C float64 I interface{} J interface{} I_nil interface{} @@ -1363,7 +1349,7 @@ type DT struct { S []string } -func TestDebug(t *testing.T) { +func TestDebugStruct(t *testing.T) { if debugFunc == nil { return } diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go index f3632a080..e4583901e 100644 --- a/src/pkg/gob/debug.go +++ b/src/pkg/gob/debug.go @@ -2,309 +2,655 @@ package gob // This file is not normally included in the gob package. Used only for debugging the package itself. // Add debug.go to the files listed in the Makefile to add Debug to the gob package. +// Except for reading uints, it is an implementation of a reader that is independent of +// the one implemented by Decoder. import ( "bytes" "fmt" "io" "os" - "reflect" - "runtime" + "strings" + "sync" ) -var dump = false // If true, print the remaining bytes in the input buffer at each item. +var dumpBytes = false // If true, print the remaining bytes in the input buffer at each item. // Init installs the debugging facility. If this file is not compiled in the -// package, the test in codec_test.go is a no-op. +// package, the tests in codec_test.go are no-ops. func init() { debugFunc = Debug } -// Debug prints a human-readable representation of the gob data read from r. -func Debug(r io.Reader) { - defer func() { - if e := recover(); e != nil { - if _, ok := e.(runtime.Error); ok { - panic(e) - } - fmt.Printf("error during debugging: %v\n", e) +var ( + blanks = bytes.Repeat([]byte{' '}, 3*10) + empty = []byte(": <empty>\n") + tabs = strings.Repeat("\t", 100) +) + +// tab indents itself when printed. +type tab int + +func (t tab) String() string { + n := int(t) + if n > len(tabs) { + n = len(tabs) + } + return tabs[0:n] +} + +func (t tab) print() { + fmt.Fprint(os.Stderr, t) +} + +// A peekReader wraps an io.Reader, allowing one to peek ahead to see +// what's coming without stealing the data from the client of the Reader. +type peekReader struct { + r io.Reader + data []byte // read-ahead data +} + +// newPeekReader returns a peekReader that wraps r. +func newPeekReader(r io.Reader) *peekReader { + return &peekReader{r: r} +} + +// Read is the usual method. It will first take data that has been read ahead. +func (p *peekReader) Read(b []byte) (n int, err os.Error) { + if len(p.data) == 0 { + return p.r.Read(b) + } + // Satisfy what's possible from the read-ahead data. + n = copy(b, p.data) + // Move data down to beginning of slice, to avoid endless growth + copy(p.data, p.data[n:]) + p.data = p.data[:len(p.data)-n] + return +} + +// peek returns as many bytes as possible from the unread +// portion of the stream, up to the length of b. +func (p *peekReader) peek(b []byte) (n int, err os.Error) { + if len(p.data) > 0 { + n = copy(b, p.data) + if n == len(b) { + return } - }() - NewDecoder(r).debug() + b = b[n:] + } + if len(b) == 0 { + return + } + m, e := io.ReadFull(p.r, b) + if m > 0 { + p.data = append(p.data, b[:m]...) + } + n += m + if e == io.ErrUnexpectedEOF { + // That means m > 0 but we reached EOF. If we got data + // we won't complain about not being able to peek enough. + if n > 0 { + e = nil + } else { + e = os.EOF + } + } + return n, e } -// debugRecv is like recv but prints what it sees. -func (dec *Decoder) debugRecv() { - if dec.byteBuffer != nil && dec.byteBuffer.Len() != 0 { - fmt.Printf("error in recv: %d bytes left in input buffer\n", dec.byteBuffer.Len()) +type debugger struct { + mutex sync.Mutex + remain int // the number of bytes known to remain in the input + remainingKnown bool // the value of 'remain' is valid + r *peekReader + wireType map[typeId]*wireType + tmp []byte // scratch space for decoding uints. +} + +// dump prints the next nBytes of the input. +// It arranges to print the output aligned from call to +// call, to make it easy to see what has been consumed. +func (deb *debugger) dump(format string, args ...interface{}) { + if !dumpBytes { return } - // Read a count. - var nbytes uint64 - nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:]) - if dec.err != nil { - fmt.Printf("receiver error on count: %s\n", dec.err) + fmt.Fprintf(os.Stderr, format+" ", args...) + if !deb.remainingKnown { return } - // Allocate the buffer. - if nbytes > uint64(len(dec.buf)) { - dec.buf = make([]byte, nbytes+1000) + if deb.remain < 0 { + fmt.Fprintf(os.Stderr, "remaining byte count is negative! %d\n", deb.remain) + return } - dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes]) - - // Read the data - _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes]) - if dec.err != nil { - fmt.Printf("receiver error on data: %s\n", dec.err) - if dec.err == os.EOF { - dec.err = io.ErrUnexpectedEOF - } + data := make([]byte, deb.remain) + n, _ := deb.r.peek(data) + if n == 0 { + os.Stderr.Write(empty) return } - if dump { - fmt.Printf("received %d bytes:\n\t% x\n", nbytes, dec.byteBuffer.Bytes()) + b := new(bytes.Buffer) + fmt.Fprintf(b, "[%d]{\n", deb.remain) + // Blanks until first byte + lineLength := 0 + if n := len(data); n%10 != 0 { + lineLength = 10 - n%10 + fmt.Fprintf(b, "\t%s", blanks[:lineLength*3]) + } + // 10 bytes per line + for len(data) > 0 { + if lineLength == 0 { + fmt.Fprint(b, "\t") + } + m := 10 - lineLength + lineLength = 0 + if m > len(data) { + m = len(data) + } + fmt.Fprintf(b, "% x\n", data[:m]) + data = data[m:] + } + fmt.Fprint(b, "}\n") + os.Stderr.Write(b.Bytes()) +} + +// Debug prints a human-readable representation of the gob data read from r. +func Debug(r io.Reader) { + fmt.Fprintln(os.Stderr, "Start of debugging") + deb := &debugger{ + r: newPeekReader(r), + wireType: make(map[typeId]*wireType), + tmp: make([]byte, 16), + } + if b, ok := r.(*bytes.Buffer); ok { + deb.remain = b.Len() + deb.remainingKnown = true } + deb.gobStream() +} + +// note that we've consumed some bytes +func (deb *debugger) consumed(n int) { + if deb.remainingKnown { + deb.remain -= n + } +} + +// int64 decodes and returns the next integer, which must be present. +// Don't call this if you could be at EOF. +func (deb *debugger) int64() int64 { + return toInt(deb.uint64()) } +// uint64 returns and decodes the next unsigned integer, which must be present. +// Don't call this if you could be at EOF. +// TODO: handle errors better. +func (deb *debugger) uint64() uint64 { + n, w, err := decodeUintReader(deb.r, deb.tmp) + if err != nil { + errorf("debug: read error: %s", err) + } + deb.consumed(w) + return n +} -// debug is like Decode but just prints what it finds. It should be safe even for corrupted data. -func (dec *Decoder) debug() { +// GobStream: +// DelimitedMessage* (until EOF) +func (deb *debugger) gobStream() { // Make sure we're single-threaded through here. - dec.mutex.Lock() - defer dec.mutex.Unlock() + deb.mutex.Lock() + defer deb.mutex.Unlock() - dec.err = nil - dec.debugRecv() - if dec.err != nil { - return + for deb.delimitedMessage(0) { } - dec.debugFromBuffer(0, false) } -// printFromBuffer prints the next value. The buffer contains data, but it may -// be a type descriptor and we may need to load more data to see the value; -// printType takes care of that. -func (dec *Decoder) debugFromBuffer(indent int, countPresent bool) { - for dec.state.b.Len() > 0 { - // Receive a type id. - id := typeId(dec.state.decodeInt()) +// DelimitedMessage: +// uint(lengthOfMessage) Message +func (deb *debugger) delimitedMessage(indent tab) bool { + for { + n := deb.loadBlock(true) + if n < 0 { + return false + } + deb.dump("Delimited message of length %d", n) + deb.message(indent) + } + return true +} - // Is it a new type? - if id < 0 { // 0 is the error state, handled above - // If the id is negative, we have a type. - dec.debugRecvType(-id) - if dec.err != nil { - break - } +// loadBlock preps us to read a message +// of the length specified next in the input. It returns +// the length of the block. The argument tells whether +// an EOF is acceptable now. If it is and one is found, +// the return value is negative. +func (deb *debugger) loadBlock(eofOK bool) int { + n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF + if err != nil { + if eofOK && err == os.EOF { + return -1 + } + errorf("debug: unexpected error: %s", err) + } + deb.consumed(w) + n := int(n64) + if n < 0 { + errorf("huge value for message length: %d", n64) + } + return int(n) +} + +// Message: +// TypeSequence TypedValue +// TypeSequence +// (TypeDefinition DelimitedTypeDefinition*)? +// DelimitedTypeDefinition: +// uint(lengthOfTypeDefinition) TypeDefinition +// TypedValue: +// int(typeId) Value +func (deb *debugger) message(indent tab) bool { + for { + // Convert the uint64 to a signed integer typeId + uid := deb.int64() + id := typeId(uid) + deb.dump("type id=%d", id) + if id < 0 { + deb.typeDefinition(indent, -id) + n := deb.loadBlock(false) + deb.dump("Message of length %d", n) continue + } else { + deb.value(indent, id) + break } + } + return true +} + +// Helper methods to make it easy to scan a type descriptor. - // No, it's a value. - // Make sure the type has been defined already or is a builtin type (for - // top-level singleton values). - if dec.wireType[id] == nil && builtinIdToType[id] == nil { - dec.err = errBadType +// common returns the CommonType at the input point. +func (deb *debugger) common() CommonType { + fieldNum := -1 + name := "" + id := typeId(0) + for { + delta := deb.delta(-1) + if delta == 0 { break } - if countPresent { - dec.state.decodeUint() + fieldNum += delta + switch fieldNum { + case 0: + name = deb.string() + case 1: + // Id typeId + id = deb.typeId() + default: + errorf("corrupted CommonType") } - dec.debugPrint(indent, id) - break } + return CommonType{name, id} } -func (dec *Decoder) debugRecvType(id typeId) { - // Have we already seen this type? That's an error - if _, alreadySeen := dec.wireType[id]; alreadySeen { - dec.err = os.ErrorString("gob: duplicate type received") - return - } +// uint returns the unsigned int at the input point, as a uint (not uint64). +func (deb *debugger) uint() uint { + return uint(deb.uint64()) +} - // Type: - wire := new(wireType) - dec.err = dec.decode(tWireType, reflect.NewValue(wire)) - if dec.err == nil { - printWireType(wire) +// int returns the signed int at the input point, as an int (not int64). +func (deb *debugger) int() int { + return int(deb.int64()) +} + +// typeId returns the type id at the input point. +func (deb *debugger) typeId() typeId { + return typeId(deb.int64()) +} + +// string returns the string at the input point. +func (deb *debugger) string() string { + x := int(deb.uint64()) + b := make([]byte, x) + nb, _ := deb.r.Read(b) + if nb != x { + errorf("corrupted type") } - // Remember we've seen this type. - dec.wireType[id] = wire + deb.consumed(nb) + return string(b) +} - // Load the next parcel. - dec.debugRecv() +// delta returns the field delta at the input point. The expect argument, +// if non-negative, identifies what the value should be. +func (deb *debugger) delta(expect int) int { + delta := int(deb.uint64()) + if delta < 0 || (expect >= 0 && delta != expect) { + errorf("gob decode: corrupted type: delta %d expected %d", delta, expect) + } + return delta } -func printWireType(wire *wireType) { - fmt.Printf("type definition {\n") - switch { - case wire.ArrayT != nil: - printCommonType("array", &wire.ArrayT.CommonType) - fmt.Printf("\tlen %d\n\telemid %d\n", wire.ArrayT.Len, wire.ArrayT.Elem) - case wire.MapT != nil: - printCommonType("map", &wire.MapT.CommonType) - fmt.Printf("\tkeyid %d\n", wire.MapT.Key) - fmt.Printf("\telemid %d\n", wire.MapT.Elem) - case wire.SliceT != nil: - printCommonType("slice", &wire.SliceT.CommonType) - fmt.Printf("\telemid %d\n", wire.SliceT.Elem) - case wire.StructT != nil: - printCommonType("struct", &wire.StructT.CommonType) - for i, field := range wire.StructT.Field { - fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.Name, field.Id) +// TypeDefinition: +// [int(-typeId) (already read)] encodingOfWireType +func (deb *debugger) typeDefinition(indent tab, id typeId) { + deb.dump("type definition for id %d", id) + // Encoding is of a wireType. Decode the structure as usual + fieldNum := -1 + wire := new(wireType) + // A wireType defines a single field. + delta := deb.delta(-1) + fieldNum += delta + switch fieldNum { + case 0: // array type, one field of {{Common}, elem, length} + // Field number 0 is CommonType + deb.delta(1) + com := deb.common() + // Field number 1 is type Id of elem + deb.delta(1) + id := deb.typeId() + // Field number 3 is length + deb.delta(1) + length := deb.int() + wire.ArrayT = &arrayType{com, id, length} + + case 1: // slice type, one field of {{Common}, elem} + // Field number 0 is CommonType + deb.delta(1) + com := deb.common() + // Field number 1 is type Id of elem + deb.delta(1) + id := deb.typeId() + wire.SliceT = &sliceType{com, id} + + case 2: // struct type, one field of {{Common}, []fieldType} + // Field number 0 is CommonType + deb.delta(1) + com := deb.common() + // Field number 1 is slice of FieldType + deb.delta(1) + numField := int(deb.uint()) + field := make([]*fieldType, numField) + for i := 0; i < numField; i++ { + field[i] = new(fieldType) + deb.delta(1) // field 0 of fieldType: name + field[i].Name = deb.string() + deb.delta(1) // field 1 of fieldType: id + field[i].Id = deb.typeId() + deb.delta(0) // end of fieldType } + wire.StructT = &structType{com, field} + + case 3: // map type, one field of {{Common}, key, elem} + // Field number 0 is CommonType + deb.delta(1) + com := deb.common() + // Field number 1 is type Id of key + deb.delta(1) + keyId := deb.typeId() + wire.SliceT = &sliceType{com, id} + // Field number 2 is type Id of elem + deb.delta(1) + elemId := deb.typeId() + wire.MapT = &mapType{com, keyId, elemId} + default: + errorf("bad field in type %d", fieldNum) } - fmt.Printf("}\n") + deb.printWireType(indent, wire) + deb.delta(0) // end inner type (arrayType, etc.) + deb.delta(0) // end wireType + // Remember we've seen this type. + deb.wireType[id] = wire } -func printCommonType(kind string, common *CommonType) { - fmt.Printf("\t%s %q\n\tid: %d\n", kind, common.Name, common.Id) -} -func (dec *Decoder) debugPrint(indent int, id typeId) { - wire, ok := dec.wireType[id] +// Value: +// SingletonValue | StructValue +func (deb *debugger) value(indent tab, id typeId) { + wire, ok := deb.wireType[id] if ok && wire.StructT != nil { - dec.debugStruct(indent+1, id, wire) + deb.structValue(indent, id) } else { - dec.debugSingle(indent+1, id, wire) + deb.singletonValue(indent, id) } } -func (dec *Decoder) debugSingle(indent int, id typeId, wire *wireType) { +// SingletonValue: +// uint(0) FieldValue +func (deb *debugger) singletonValue(indent tab, id typeId) { + deb.dump("Singleton value") // is it a builtin type? + wire := deb.wireType[id] _, ok := builtinIdToType[id] if !ok && wire == nil { - errorf("type id %d not defined\n", id) + errorf("type id %d not defined", id) + } + m := deb.uint64() + if m != 0 { + errorf("expected zero; got %d", m) } - dec.state.decodeUint() - dec.printItem(indent, id) + deb.fieldValue(indent, id) } -func (dec *Decoder) printItem(indent int, id typeId) { - if dump { - fmt.Printf("print item %d bytes: % x\n", dec.state.b.Len(), dec.state.b.Bytes()) +// InterfaceValue: +// NilInterfaceValue | NonNilInterfaceValue +func (deb *debugger) interfaceValue(indent tab) { + deb.dump("Start of interface value") + if nameLen := deb.uint64(); nameLen == 0 { + deb.nilInterfaceValue(indent) + } else { + deb.nonNilInterfaceValue(indent, int(nameLen)) } +} + +// NilInterfaceValue: +// uint(0) [already read] +func (deb *debugger) nilInterfaceValue(indent tab) int { + fmt.Fprintf(os.Stderr, "%snil interface\n", indent) + return 0 +} + + +// NonNilInterfaceValue: +// ConcreteTypeName TypeSequence InterfaceContents +// ConcreteTypeName: +// uint(lengthOfName) [already read=n] name +// InterfaceContents: +// int(concreteTypeId) DelimitedValue +// DelimitedValue: +// uint(length) Value +func (deb *debugger) nonNilInterfaceValue(indent tab, nameLen int) { + // ConcreteTypeName + b := make([]byte, nameLen) + deb.r.Read(b) // TODO: CHECK THESE READS!! + deb.consumed(nameLen) + name := string(b) + + for { + id := deb.typeId() + if id < 0 { + deb.typeDefinition(indent, -id) + n := deb.loadBlock(false) + deb.dump("Nested message of length %d", n) + } else { + // DelimitedValue + x := deb.uint64() // in case we want to ignore the value; we don't. + fmt.Fprintf(os.Stderr, "%sinterface value, type %q id=%d; valueLength %d\n", indent, name, id, x) + deb.value(indent, id) + break + } + } +} + +// printCommonType prints a common type; used by printWireType. +func (deb *debugger) printCommonType(indent tab, kind string, common *CommonType) { + indent.print() + fmt.Fprintf(os.Stderr, "%s %q id=%d\n", kind, common.Name, common.Id) +} + +// printWireType prints the contents of a wireType. +func (deb *debugger) printWireType(indent tab, wire *wireType) { + fmt.Fprintf(os.Stderr, "%stype definition {\n", indent) + indent++ + switch { + case wire.ArrayT != nil: + deb.printCommonType(indent, "array", &wire.ArrayT.CommonType) + fmt.Fprintf(os.Stderr, "%slen %d\n", indent+1, wire.ArrayT.Len) + fmt.Fprintf(os.Stderr, "%selemid %d\n", indent+1, wire.ArrayT.Elem) + case wire.MapT != nil: + deb.printCommonType(indent, "map", &wire.MapT.CommonType) + fmt.Fprintf(os.Stderr, "%skey id=%d\n", indent+1, wire.MapT.Key) + fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.MapT.Elem) + case wire.SliceT != nil: + deb.printCommonType(indent, "slice", &wire.SliceT.CommonType) + fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.SliceT.Elem) + case wire.StructT != nil: + deb.printCommonType(indent, "struct", &wire.StructT.CommonType) + for i, field := range wire.StructT.Field { + fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\tid=%d\n", indent+1, i, field.Name, field.Id) + } + } + indent-- + fmt.Fprintf(os.Stderr, "%s}\n", indent) +} + +// fieldValue prints a value of any type, such as a struct field. +// FieldValue: +// builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue +func (deb *debugger) fieldValue(indent tab, id typeId) { _, ok := builtinIdToType[id] if ok { - dec.printBuiltin(indent, id) + if id == tInterface { + deb.interfaceValue(indent) + } else { + deb.printBuiltin(indent, id) + } return } - wire, ok := dec.wireType[id] + wire, ok := deb.wireType[id] if !ok { - errorf("type id %d not defined\n", id) + errorf("type id %d not defined", id) } switch { case wire.ArrayT != nil: - dec.printArray(indent, wire) + deb.arrayValue(indent, wire) case wire.MapT != nil: - dec.printMap(indent, wire) + deb.mapValue(indent, wire) case wire.SliceT != nil: - dec.printSlice(indent, wire) + deb.sliceValue(indent, wire) case wire.StructT != nil: - dec.debugStruct(indent, id, wire) + deb.structValue(indent, id) + default: + panic("bad wire type for field") + } +} + +// printBuiltin prints a value not of a fundamental type, that is, +// one whose type is known to gobs at bootstrap time. +func (deb *debugger) printBuiltin(indent tab, id typeId) { + switch id { + case tBool: + x := deb.int64() + if x == 0 { + fmt.Fprintf(os.Stderr, "%sfalse\n", indent) + } else { + fmt.Fprintf(os.Stderr, "%strue\n", indent) + } + case tInt: + x := deb.int64() + fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) + case tUint: + x := deb.int64() + fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) + case tFloat: + x := deb.uint64() + fmt.Fprintf(os.Stderr, "%s%g\n", indent, floatFromBits(x)) + case tComplex: + r := deb.uint64() + i := deb.uint64() + fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, floatFromBits(r), floatFromBits(i)) + case tBytes: + x := int(deb.uint64()) + b := make([]byte, x) + deb.r.Read(b) + deb.consumed(x) + fmt.Fprintf(os.Stderr, "%s{% x}=%q\n", indent, b, b) + case tString: + x := int(deb.uint64()) + b := make([]byte, x) + deb.r.Read(b) + deb.consumed(x) + fmt.Fprintf(os.Stderr, "%s%q\n", indent, b) + default: + panic("unknown builtin") } } -func (dec *Decoder) printArray(indent int, wire *wireType) { + +// ArrayValue: +// uint(n) FieldValue*n +func (deb *debugger) arrayValue(indent tab, wire *wireType) { elemId := wire.ArrayT.Elem - n := int(dec.state.decodeUint()) - for i := 0; i < n && dec.err == nil; i++ { - dec.printItem(indent, elemId) + u := deb.uint64() + length := int(u) + for i := 0; i < length; i++ { + deb.fieldValue(indent, elemId) } - if n != wire.ArrayT.Len { - tab(indent) - fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.ArrayT.Len) + if length != wire.ArrayT.Len { + fmt.Fprintf(os.Stderr, "%s(wrong length for array: %d should be %d)\n", indent, length, wire.ArrayT.Len) } } -func (dec *Decoder) printMap(indent int, wire *wireType) { +// MapValue: +// uint(n) (FieldValue FieldValue)*n [n (key, value) pairs] +func (deb *debugger) mapValue(indent tab, wire *wireType) { keyId := wire.MapT.Key elemId := wire.MapT.Elem - n := int(dec.state.decodeUint()) - for i := 0; i < n && dec.err == nil; i++ { - dec.printItem(indent, keyId) - dec.printItem(indent+1, elemId) + u := deb.uint64() + length := int(u) + for i := 0; i < length; i++ { + deb.fieldValue(indent+1, keyId) + deb.fieldValue(indent+1, elemId) } } -func (dec *Decoder) printSlice(indent int, wire *wireType) { +// SliceValue: +// uint(n) (n FieldValue) +func (deb *debugger) sliceValue(indent tab, wire *wireType) { elemId := wire.SliceT.Elem - n := int(dec.state.decodeUint()) - for i := 0; i < n && dec.err == nil; i++ { - dec.printItem(indent, elemId) - } -} + u := deb.uint64() + length := int(u) + deb.dump("Start of slice of length %d", length) -func (dec *Decoder) printBuiltin(indent int, id typeId) { - tab(indent) - switch id { - case tBool: - if dec.state.decodeInt() == 0 { - fmt.Printf("false\n") - } else { - fmt.Printf("true\n") - } - case tInt: - fmt.Printf("%d\n", dec.state.decodeInt()) - case tUint: - fmt.Printf("%d\n", dec.state.decodeUint()) - case tFloat: - fmt.Printf("%g\n", floatFromBits(dec.state.decodeUint())) - case tBytes: - b := make([]byte, dec.state.decodeUint()) - dec.state.b.Read(b) - fmt.Printf("% x\n", b) - case tString: - b := make([]byte, dec.state.decodeUint()) - dec.state.b.Read(b) - fmt.Printf("%q\n", b) - case tInterface: - b := make([]byte, dec.state.decodeUint()) - dec.state.b.Read(b) - if len(b) == 0 { - fmt.Printf("nil interface") - } else { - fmt.Printf("interface value; type %q\n", b) - dec.debugFromBuffer(indent, true) - } - default: - fmt.Print("unknown\n") + for i := 0; i < length; i++ { + deb.fieldValue(indent, elemId) } } -func (dec *Decoder) debugStruct(indent int, id typeId, wire *wireType) { - tab(indent) - fmt.Printf("%s struct {\n", id.name()) +// StructValue: +// (uint(fieldDelta) FieldValue)* +func (deb *debugger) structValue(indent tab, id typeId) { + deb.dump("Start of struct value of %q id=%d\n<<\n", id.name(), id) + fmt.Fprintf(os.Stderr, "%s%s struct {\n", indent, id.name()) + wire, ok := deb.wireType[id] + if !ok { + errorf("type id %d not defined", id) + } strct := wire.StructT - state := newDecodeState(dec, dec.state.b) - state.fieldnum = -1 - for dec.err == nil { - delta := int(state.decodeUint()) - if delta < 0 { - errorf("gob decode: corrupted data: negative delta") - } + fieldNum := -1 + indent++ + for { + delta := deb.uint64() if delta == 0 { // struct terminator is zero delta fieldnum break } - fieldNum := state.fieldnum + delta + fieldNum += int(delta) if fieldNum < 0 || fieldNum >= len(strct.Field) { - errorf("field number out of range") + deb.dump("field number out of range: prevField=%d delta=%d", fieldNum-int(delta), delta) break } - tab(indent) - fmt.Printf("%s(%d):\n", wire.StructT.Field[fieldNum].Name, fieldNum) - dec.printItem(indent+1, strct.Field[fieldNum].Id) - state.fieldnum = fieldNum - } - tab(indent) - fmt.Printf(" } // end %s struct\n", id.name()) -} - -func tab(indent int) { - for i, w := 0, 0; i < indent; i += w { - w = 10 - if i+w > indent { - w = indent - i - } - fmt.Print("\t\t\t\t\t\t\t\t\t\t"[:w]) + fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\n", indent, fieldNum, wire.StructT.Field[fieldNum].Name) + deb.fieldValue(indent+1, strct.Field[fieldNum].Id) } + indent-- + fmt.Fprintf(os.Stderr, "%s} // end %s struct\n", indent, id.name()) + deb.dump(">> End of struct value of type %d %q", id, id.name()) } diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go index f88ca72da..db8b96870 100644 --- a/src/pkg/gob/decode.go +++ b/src/pkg/gob/decode.go @@ -30,15 +30,17 @@ type decodeState struct { dec *Decoder // The buffer is stored with an extra indirection because it may be replaced // if we load a type during decode (when reading an interface value). - b **bytes.Buffer + b *bytes.Buffer fieldnum int // the last field number read. buf []byte } -func newDecodeState(dec *Decoder, b **bytes.Buffer) *decodeState { +// We pass the bytes.Buffer separately for easier testing of the infrastructure +// without requiring a full Decoder. +func newDecodeState(dec *Decoder, buf *bytes.Buffer) *decodeState { d := new(decodeState) d.dec = dec - d.b = b + d.b = buf d.buf = make([]byte, uint64Size) return d } @@ -49,14 +51,15 @@ func overflow(name string) os.ErrorString { // decodeUintReader reads an encoded unsigned integer from an io.Reader. // Used only by the Decoder to read the message length. -func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) { - _, err = r.Read(buf[0:1]) +func decodeUintReader(r io.Reader, buf []byte) (x uint64, width int, err os.Error) { + width = 1 + _, err = r.Read(buf[0:width]) if err != nil { return } b := buf[0] if b <= 0x7f { - return uint64(b), nil + return uint64(b), width, nil } nb := -int(int8(b)) if nb > uint64Size { @@ -75,6 +78,7 @@ func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) { for i := 0; i < n; i++ { x <<= 8 x |= uint64(buf[i]) + width++ } return } @@ -333,7 +337,7 @@ func decComplex64(i *decInstr, state *decodeState, p unsafe.Pointer) { p = *(*unsafe.Pointer)(p) } storeFloat32(i, state, p) - storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float(0))))) + storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float32(0))))) } func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) { @@ -345,7 +349,7 @@ func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) { } real := floatFromBits(uint64(state.decodeUint())) imag := floatFromBits(uint64(state.decodeUint())) - *(*complex128)(p) = cmplx(real, imag) + *(*complex128)(p) = complex(real, imag) } // uint8 arrays are encoded as an unsigned count followed by the raw bytes. @@ -405,10 +409,10 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr { return *(*uintptr)(up) } -func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes.Buffer, p uintptr, indir int) (err os.Error) { +func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, p uintptr, indir int) (err os.Error) { defer catchError(&err) p = allocate(rtyp, p, indir) - state := newDecodeState(dec, b) + state := newDecodeState(dec, &dec.buf) state.fieldnum = singletonField basep := p delta := int(state.decodeUint()) @@ -424,10 +428,10 @@ func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes return nil } -func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b **bytes.Buffer, p uintptr, indir int) (err os.Error) { +func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, p uintptr, indir int) (err os.Error) { defer catchError(&err) p = allocate(rtyp, p, indir) - state := newDecodeState(dec, b) + state := newDecodeState(dec, &dec.buf) state.fieldnum = -1 basep := p for state.b.Len() > 0 { @@ -454,9 +458,9 @@ func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b return nil } -func (dec *Decoder) ignoreStruct(engine *decEngine, b **bytes.Buffer) (err os.Error) { +func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) { defer catchError(&err) - state := newDecodeState(dec, b) + state := newDecodeState(dec, &dec.buf) state.fieldnum = -1 for state.b.Len() > 0 { delta := int(state.decodeUint()) @@ -612,9 +616,17 @@ func (dec *Decoder) decodeInterface(ityp *reflect.InterfaceType, state *decodeSt if !ok { errorf("gob: name not registered for interface: %q", name) } + // Read the type id of the concrete value. + concreteId := dec.decodeTypeSequence(true) + if concreteId < 0 { + error(dec.err) + } + // Byte count of value is next; we don't care what it is (it's there + // in case we want to ignore the value by skipping it completely). + state.decodeUint() // Read the concrete value. value := reflect.MakeZero(typ) - dec.decodeValueFromBuffer(value, false, true) + dec.decodeValue(concreteId, value) if dec.err != nil { error(dec.err) } @@ -637,10 +649,12 @@ func (dec *Decoder) ignoreInterface(state *decodeState) { if err != nil { error(err) } - dec.decodeValueFromBuffer(nil, true, true) - if dec.err != nil { - error(err) + id := dec.decodeTypeSequence(true) + if id < 0 { + error(dec.err) } + // At this point, the decoder buffer contains the value. Just toss it. + state.b.Reset() } // Index by Go types. @@ -731,7 +745,7 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp } op = func(i *decInstr, state *decodeState, p unsafe.Pointer) { // indirect through enginePtr to delay evaluation for recursive structs - err = dec.decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir) + err = dec.decodeStruct(*enginePtr, t, uintptr(p), i.indir) if err != nil { error(err) } @@ -796,7 +810,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { } op = func(i *decInstr, state *decodeState, p unsafe.Pointer) { // indirect through enginePtr to delay evaluation for recursive structs - state.dec.ignoreStruct(*enginePtr, state.b) + state.dec.ignoreStruct(*enginePtr) } } } @@ -905,7 +919,11 @@ func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEng if t, ok := builtinIdToType[remoteId]; ok { wireStruct, _ = t.(*structType) } else { - wireStruct = dec.wireType[remoteId].StructT + wire := dec.wireType[remoteId] + if wire == nil { + error(errBadType) + } + wireStruct = wire.StructT } if wireStruct == nil { errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String()) @@ -974,7 +992,7 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er return } -func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error { +func (dec *Decoder) decodeValue(wireId typeId, val reflect.Value) os.Error { // Dereference down to the underlying struct type. rt, indir := indirect(val.Type()) enginePtr, err := dec.getDecEnginePtr(wireId, rt) @@ -987,26 +1005,12 @@ func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error { name := rt.Name() return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name) } - return dec.decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir) + return dec.decodeStruct(engine, st, uintptr(val.Addr()), indir) } - return dec.decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir) + return dec.decodeSingle(engine, rt, uintptr(val.Addr()), indir) } func init() { - var fop, cop decOp - switch reflect.Typeof(float(0)).Bits() { - case 32: - fop = decFloat32 - cop = decComplex64 - case 64: - fop = decFloat64 - cop = decComplex128 - default: - panic("gob: unknown size of float") - } - decOpMap[reflect.Float] = fop - decOpMap[reflect.Complex] = cop - var iop, uop decOp switch reflect.Typeof(int(0)).Bits() { case 32: diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go index 664001a4b..7527c5f1f 100644 --- a/src/pkg/gob/decoder.go +++ b/src/pkg/gob/decoder.go @@ -17,14 +17,13 @@ import ( type Decoder struct { mutex sync.Mutex // each item must be received atomically r io.Reader // source of the data + buf bytes.Buffer // buffer for more efficient i/o from r wireType map[typeId]*wireType // map from remote ID to local description decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines ignorerCache map[typeId]**decEngine // ditto for ignored objects - state *decodeState // reads data from in-memory buffer countState *decodeState // reads counts from wire - buf []byte - countBuf [9]byte // counts may be uint64s (unlikely!), require 9 bytes - byteBuffer *bytes.Buffer + countBuf []byte // used for decoding integers while parsing messages + tmp []byte // temporary storage for i/o; saves reallocating err os.Error } @@ -33,111 +32,138 @@ func NewDecoder(r io.Reader) *Decoder { dec := new(Decoder) dec.r = r dec.wireType = make(map[typeId]*wireType) - dec.state = newDecodeState(dec, &dec.byteBuffer) // buffer set in Decode() dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine) dec.ignorerCache = make(map[typeId]**decEngine) + dec.countBuf = make([]byte, 9) // counts may be uint64s (unlikely!), require 9 bytes return dec } -// recvType loads the definition of a type and reloads the Decoder's buffer. +// recvType loads the definition of a type. func (dec *Decoder) recvType(id typeId) { // Have we already seen this type? That's an error - if dec.wireType[id] != nil { + if id < firstUserId || dec.wireType[id] != nil { dec.err = os.ErrorString("gob: duplicate type received") return } // Type: wire := new(wireType) - dec.err = dec.decode(tWireType, reflect.NewValue(wire)) + dec.err = dec.decodeValue(tWireType, reflect.NewValue(wire)) if dec.err != nil { return } // Remember we've seen this type. dec.wireType[id] = wire - - // Load the next parcel. - dec.recv() } -// Decode reads the next value from the connection and stores -// it in the data represented by the empty interface value. -// The value underlying e must be the correct type for the next -// data item received, and must be a pointer. -func (dec *Decoder) Decode(e interface{}) os.Error { - value := reflect.NewValue(e) - // If e represents a value as opposed to a pointer, the answer won't - // get back to the caller. Make sure it's a pointer. - if value.Type().Kind() != reflect.Ptr { - dec.err = os.ErrorString("gob: attempt to decode into a non-pointer") - return dec.err +// recvMessage reads the next count-delimited item from the input. It is the converse +// of Encoder.writeMessage. It returns false on EOF or other error reading the message. +func (dec *Decoder) recvMessage() bool { + // Read a count. + nbytes, _, err := decodeUintReader(dec.r, dec.countBuf) + if err != nil { + dec.err = err + return false } - return dec.DecodeValue(value) + dec.readMessage(int(nbytes)) + return dec.err == nil } -// recv reads the next count-delimited item from the input. It is the converse -// of Encoder.send. -func (dec *Decoder) recv() { - // Read a count. - var nbytes uint64 - nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:]) - if dec.err != nil { - return - } +// readMessage reads the next nbytes bytes from the input. +func (dec *Decoder) readMessage(nbytes int) { // Allocate the buffer. - if nbytes > uint64(len(dec.buf)) { - dec.buf = make([]byte, nbytes+1000) + if cap(dec.tmp) < nbytes { + dec.tmp = make([]byte, nbytes+100) // room to grow } - dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes]) + dec.tmp = dec.tmp[:nbytes] // Read the data - _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes]) + _, dec.err = io.ReadFull(dec.r, dec.tmp) if dec.err != nil { if dec.err == os.EOF { dec.err = io.ErrUnexpectedEOF } return } + dec.buf.Write(dec.tmp) } -// decodeValueFromBuffer grabs the next value from the input. The Decoder's -// buffer already contains data. If the next item in the buffer is a type -// descriptor, it may be necessary to reload the buffer, but recvType does that. -func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignoreInterfaceValue, countPresent bool) { - for dec.state.b.Len() > 0 { - // Receive a type id. - id := typeId(dec.state.decodeInt()) +// toInt turns an encoded uint64 into an int, according to the marshaling rules. +func toInt(x uint64) int64 { + i := int64(x >> 1) + if x&1 != 0 { + i = ^i + } + return i +} + +func (dec *Decoder) nextInt() int64 { + n, _, err := decodeUintReader(&dec.buf, dec.countBuf) + if err != nil { + dec.err = err + } + return toInt(n) +} + +func (dec *Decoder) nextUint() uint64 { + n, _, err := decodeUintReader(&dec.buf, dec.countBuf) + if err != nil { + dec.err = err + } + return n +} - // Is it a new type? - if id < 0 { // 0 is the error state, handled above - // If the id is negative, we have a type. - dec.recvType(-id) - if dec.err != nil { +// decodeTypeSequence parses: +// TypeSequence +// (TypeDefinition DelimitedTypeDefinition*)? +// and returns the type id of the next value. It returns -1 at +// EOF. Upon return, the remainder of dec.buf is the value to be +// decoded. If this is an interface value, it can be ignored by +// simply resetting that buffer. +func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { + for dec.err == nil { + if dec.buf.Len() == 0 { + if !dec.recvMessage() { break } - continue } - - // Make sure the type has been defined already or is a builtin type (for - // top-level singleton values). - if dec.wireType[id] == nil && builtinIdToType[id] == nil { - dec.err = errBadType - break + // Receive a type id. + id := typeId(dec.nextInt()) + if id >= 0 { + // Value follows. + return id } - // An interface value is preceded by a byte count. - if countPresent { - count := int(dec.state.decodeUint()) - if ignoreInterfaceValue { - // An interface value is preceded by a byte count. Just skip that many bytes. - dec.state.b.Next(int(count)) + // Type definition for (-id) follows. + dec.recvType(-id) + // When decoding an interface, after a type there may be a + // DelimitedValue still in the buffer. Skip its count. + // (Alternatively, the buffer is empty and the byte count + // will be absorbed by recvMessage.) + if dec.buf.Len() > 0 { + if !isInterface { + dec.err = os.ErrorString("extra data in buffer") break } - // Otherwise fall through and decode it. + dec.nextUint() } - dec.err = dec.decode(id, value) - break } + return -1 +} + +// Decode reads the next value from the connection and stores +// it in the data represented by the empty interface value. +// The value underlying e must be the correct type for the next +// data item received, and must be a pointer. +func (dec *Decoder) Decode(e interface{}) os.Error { + value := reflect.NewValue(e) + // If e represents a value as opposed to a pointer, the answer won't + // get back to the caller. Make sure it's a pointer. + if value.Type().Kind() != reflect.Ptr { + dec.err = os.ErrorString("gob: attempt to decode into a non-pointer") + return dec.err + } + return dec.DecodeValue(value) } // DecodeValue reads the next value from the connection and stores @@ -149,12 +175,12 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error { dec.mutex.Lock() defer dec.mutex.Unlock() + dec.buf.Reset() // In case data lingers from previous invocation. dec.err = nil - dec.recv() - if dec.err != nil { - return dec.err + id := dec.decodeTypeSequence(false) + if id >= 0 { + dec.err = dec.decodeValue(id, value) } - dec.decodeValueFromBuffer(value, false, false) return dec.err } diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go index 31253f16d..613974a00 100644 --- a/src/pkg/gob/doc.go +++ b/src/pkg/gob/doc.go @@ -220,6 +220,54 @@ be predefined or be defined before the value in the stream. package gob /* +Grammar: + +Tokens starting with a lower case letter are terminals; int(n) +and uint(n) represent the signed/unsigned encodings of the value n. + +GobStream: + DelimitedMessage* +DelimitedMessage: + uint(lengthOfMessage) Message +Message: + TypeSequence TypedValue +TypeSequence + (TypeDefinition DelimitedTypeDefinition*)? +DelimitedTypeDefinition: + uint(lengthOfTypeDefinition) TypeDefinition +TypedValue: + int(typeId) Value +TypeDefinition: + int(-typeId) encodingOfWireType +Value: + SingletonValue | StructValue +SingletonValue: + uint(0) FieldValue +FieldValue: + builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue +InterfaceValue: + NilInterfaceValue | NonNilInterfaceValue +NilInterfaceValue: + uint(0) +NonNilInterfaceValue: + ConcreteTypeName TypeSequence InterfaceContents +ConcreteTypeName: + uint(lengthOfName) [already read=n] name +InterfaceContents: + int(concreteTypeId) DelimitedValue +DelimitedValue: + uint(length) Value +ArrayValue: + uint(n) FieldValue*n [n elements] +MapValue: + uint(n) (FieldValue FieldValue)*n [n (key, value) pairs] +SliceValue: + uint(n) FieldValue*n [n elements] +StructValue: + (uint(fieldDelta) FieldValue)* +*/ + +/* For implementers and the curious, here is an encoded example. Given type Point struct {x, y int} and the value diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index 3431eafa7..2e5ba2487 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -223,15 +223,6 @@ func floatBits(f float64) uint64 { return v } -func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) { - f := *(*float)(p) - if f != 0 || state.sendZero { - v := floatBits(float64(f)) - state.update(i) - state.encodeUint(v) - } -} - func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) { f := *(*float32)(p) if f != 0 || state.sendZero { @@ -251,17 +242,6 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) { } // Complex numbers are just a pair of floating-point numbers, real part first. -func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) { - c := *(*complex)(p) - if c != 0+0i || state.sendZero { - rpart := floatBits(float64(real(c))) - ipart := floatBits(float64(imag(c))) - state.update(i) - state.encodeUint(rpart) - state.encodeUint(ipart) - } -} - func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) { c := *(*complex64)(p) if c != 0+0i || state.sendZero { @@ -284,9 +264,6 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) { } } -func encNoOp(i *encInstr, state *encoderState, p unsafe.Pointer) { -} - // Byte arrays are encoded as an unsigned count followed by the raw bytes. func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) { b := *(*[]byte)(p) @@ -418,17 +395,21 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) if err != nil { error(err) } - // Send (and maybe first define) the type id. - enc.sendTypeDescriptor(typ) - // Encode the value into a new buffer. + // Define the type id if necessary. + enc.sendTypeDescriptor(enc.writer(), state, typ) + // Send the type id. + enc.sendTypeId(state, typ) + // Encode the value into a new buffer. Any nested type definitions + // should be written to b, before the encoded value. + enc.pushWriter(b) data := new(bytes.Buffer) err = enc.encode(data, iv.Elem()) if err != nil { error(err) } - state.encodeUint(uint64(data.Len())) - _, err = state.b.Write(data.Bytes()) - if err != nil { + enc.popWriter() + enc.writeMessage(b, data) + if enc.err != nil { error(err) } } @@ -446,10 +427,8 @@ var encOpMap = []encOp{ reflect.Uint32: encUint32, reflect.Uint64: encUint64, reflect.Uintptr: encUintptr, - reflect.Float: encFloat, reflect.Float32: encFloat32, reflect.Float64: encFloat64, - reflect.Complex: encComplex, reflect.Complex64: encComplex64, reflect.Complex128: encComplex128, reflect.String: encString, @@ -538,16 +517,18 @@ func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine { srt, isStruct := rt.(*reflect.StructType) engine := new(encEngine) if isStruct { - engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator - for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ { - f := srt.Field(fieldnum) - op, indir := enc.encOpFor(f.Type) + for fieldNum := 0; fieldNum < srt.NumField(); fieldNum++ { + f := srt.Field(fieldNum) if !isExported(f.Name) { - op = encNoOp + continue } - engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)} + op, indir := enc.encOpFor(f.Type) + engine.instr = append(engine.instr, encInstr{op, fieldNum, indir, uintptr(f.Offset)}) + } + if srt.NumField() > 0 && len(engine.instr) == 0 { + errorf("type %s has no exported fields", rt) } - engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0} + engine.instr = append(engine.instr, encInstr{encStructTerminator, 0, 0, 0}) } else { engine.instr = make([]encInstr, 1) op, indir := enc.encOpFor(rt) diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go index 8869b2629..29ba44057 100644 --- a/src/pkg/gob/encoder.go +++ b/src/pkg/gob/encoder.go @@ -16,9 +16,8 @@ import ( // other side of a connection. type Encoder struct { mutex sync.Mutex // each item must be sent atomically - w io.Writer // where to send the data + w []io.Writer // where to send the data sent map[reflect.Type]typeId // which types we've already sent - state *encoderState // so we can encode integers, strings directly countState *encoderState // stage for writing counts buf []byte // for collecting the output. err os.Error @@ -27,13 +26,27 @@ type Encoder struct { // NewEncoder returns a new encoder that will transmit on the io.Writer. func NewEncoder(w io.Writer) *Encoder { enc := new(Encoder) - enc.w = w + enc.w = []io.Writer{w} enc.sent = make(map[reflect.Type]typeId) - enc.state = newEncoderState(enc, new(bytes.Buffer)) enc.countState = newEncoderState(enc, new(bytes.Buffer)) return enc } +// writer() returns the innermost writer the encoder is using +func (enc *Encoder) writer() io.Writer { + return enc.w[len(enc.w)-1] +} + +// pushWriter adds a writer to the encoder. +func (enc *Encoder) pushWriter(w io.Writer) { + enc.w = append(enc.w, w) +} + +// popWriter pops the innermost writer. +func (enc *Encoder) popWriter() { + enc.w = enc.w[0 : len(enc.w)-1] +} + func (enc *Encoder) badType(rt reflect.Type) { enc.setError(os.ErrorString("gob: can't encode type " + rt.String())) } @@ -42,16 +55,14 @@ func (enc *Encoder) setError(err os.Error) { if enc.err == nil { // remember the first. enc.err = err } - enc.state.b.Reset() } -// Send the data item preceded by a unsigned count of its length. -func (enc *Encoder) send() { - // Encode the length. - enc.countState.encodeUint(uint64(enc.state.b.Len())) +// writeMessage sends the data item preceded by a unsigned count of its length. +func (enc *Encoder) writeMessage(w io.Writer, b *bytes.Buffer) { + enc.countState.encodeUint(uint64(b.Len())) // Build the buffer. countLen := enc.countState.b.Len() - total := countLen + enc.state.b.Len() + total := countLen + b.Len() if total > len(enc.buf) { enc.buf = make([]byte, total+1000) // extra for growth } @@ -59,15 +70,15 @@ func (enc *Encoder) send() { // TODO(r): avoid the extra copy here. enc.countState.b.Read(enc.buf[0:countLen]) // Now the data. - enc.state.b.Read(enc.buf[countLen:total]) + b.Read(enc.buf[countLen:total]) // Write the data. - _, err := enc.w.Write(enc.buf[0:total]) + _, err := w.Write(enc.buf[0:total]) if err != nil { enc.setError(err) } } -func (enc *Encoder) sendType(origt reflect.Type) (sent bool) { +func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Type) (sent bool) { // Drill down to the base type. rt, _ := indirect(origt) @@ -112,10 +123,10 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) { } // Send the pair (-id, type) // Id: - enc.state.encodeInt(-int64(info.id)) + state.encodeInt(-int64(info.id)) // Type: - enc.encode(enc.state.b, reflect.NewValue(info.wire)) - enc.send() + enc.encode(state.b, reflect.NewValue(info.wire)) + enc.writeMessage(w, state.b) if enc.err != nil { return } @@ -128,10 +139,10 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) { switch st := rt.(type) { case *reflect.StructType: for i := 0; i < st.NumField(); i++ { - enc.sendType(st.Field(i).Type) + enc.sendType(w, state, st.Field(i).Type) } case reflect.ArrayOrSliceType: - enc.sendType(st.Elem()) + enc.sendType(w, state, st.Elem()) } return true } @@ -144,13 +155,13 @@ func (enc *Encoder) Encode(e interface{}) os.Error { // sendTypeId makes sure the remote side knows about this type. // It will send a descriptor if this is the first time the type has been -// sent. Regardless, it sends the id. -func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) { +// sent. +func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, rt reflect.Type) { // Make sure the type is known to the other side. // First, have we already sent this type? if _, alreadySent := enc.sent[rt]; !alreadySent { // No, so send it. - sent := enc.sendType(rt) + sent := enc.sendType(w, state, rt) if enc.err != nil { return } @@ -168,9 +179,12 @@ func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) { enc.sent[rt] = info.id } } +} +// sendTypeId sends the id, which must have already been defined. +func (enc *Encoder) sendTypeId(state *encoderState, rt reflect.Type) { // Identify the type of this top-level value. - enc.state.encodeInt(int64(enc.sent[rt])) + state.encodeInt(int64(enc.sent[rt])) } // EncodeValue transmits the data item represented by the reflection value, @@ -181,26 +195,26 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error { enc.mutex.Lock() defer enc.mutex.Unlock() + // Remove any nested writers remaining due to previous errors. + enc.w = enc.w[0:1] + enc.err = nil rt, _ := indirect(value.Type()) - // Sanity check only: encoder should never come in with data present. - if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 { - enc.err = os.ErrorString("encoder: buffer not empty") - return enc.err - } + state := newEncoderState(enc, new(bytes.Buffer)) - enc.sendTypeDescriptor(rt) + enc.sendTypeDescriptor(enc.writer(), state, rt) + enc.sendTypeId(state, rt) if enc.err != nil { return enc.err } // Encode the object. - err := enc.encode(enc.state.b, value) + err := enc.encode(state.b, value) if err != nil { enc.setError(err) } else { - enc.send() + enc.writeMessage(enc.writer(), state.b) } return enc.err diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go index db0b7db66..1456ca00c 100644 --- a/src/pkg/gob/encoder_test.go +++ b/src/pkg/gob/encoder_test.go @@ -33,7 +33,7 @@ type ET3 struct { // Like ET1 but with a different type for a field type ET4 struct { A int - Et2 float + Et2 float64 Next int } @@ -189,13 +189,13 @@ func TestPtrTypeToType(t *testing.T) { func TestTypeToPtrPtrPtrPtrType(t *testing.T) { type Type2 struct { - A ****float + A ****float64 } t2 := Type2{} - t2.A = new(***float) - *t2.A = new(**float) - **t2.A = new(*float) - ***t2.A = new(float) + t2.A = new(***float64) + *t2.A = new(**float64) + **t2.A = new(*float64) + ***t2.A = new(float64) ****t2.A = 27.4 t2pppp := new(***Type2) if err := encAndDec(t2, t2pppp); err != nil { @@ -220,7 +220,7 @@ func TestSlice(t *testing.T) { func TestValueError(t *testing.T) { // Encode a *T, decode a T type Type4 struct { - a int + A int } t4p := &Type4{3} var t4 Type4 // note: not a pointer. @@ -254,13 +254,13 @@ func TestDefaultsInArray(t *testing.T) { B []bool I []int S []string - F []float + F []float64 } t7 := Type7{ []bool{false, false, true}, []int{0, 0, 1}, []string{"hi", "", "there"}, - []float{0, 0, 1}, + []float64{0, 0, 1}, } var t7p Type7 if err := encAndDec(t7, &t7p); err != nil { @@ -383,3 +383,46 @@ func TestInterfaceIndirect(t *testing.T) { t.Fatal("decode error:", err) } } + +// Another bug from golang-nuts, involving nested interfaces. +type Bug0Outer struct { + Bug0Field interface{} +} + +type Bug0Inner struct { + A int +} + +func TestNestedInterfaces(t *testing.T) { + var buf bytes.Buffer + e := NewEncoder(&buf) + d := NewDecoder(&buf) + Register(new(Bug0Outer)) + Register(new(Bug0Inner)) + f := &Bug0Outer{&Bug0Outer{&Bug0Inner{7}}} + var v interface{} = f + err := e.Encode(&v) + if err != nil { + t.Fatal("Encode:", err) + } + err = d.Decode(&v) + if err != nil { + t.Fatal("Decode:", err) + } + // Make sure it decoded correctly. + outer1, ok := v.(*Bug0Outer) + if !ok { + t.Fatalf("v not Bug0Outer: %T", v) + } + outer2, ok := outer1.Bug0Field.(*Bug0Outer) + if !ok { + t.Fatalf("v.Bug0Field not Bug0Outer: %T", outer1.Bug0Field) + } + inner, ok := outer2.Bug0Field.(*Bug0Inner) + if !ok { + t.Fatalf("v.Bug0Field.Bug0Field not Bug0Inner: %T", outer2.Bug0Field) + } + if inner.A != 7 { + t.Fatalf("final value %d; expected %d", inner.A, 7) + } +} diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go index c00af87bf..f613f6e8a 100644 --- a/src/pkg/gob/type.go +++ b/src/pkg/gob/type.go @@ -529,10 +529,8 @@ func registerBasics() { Register(uint16(0)) Register(uint32(0)) Register(uint64(0)) - Register(float(0)) Register(float32(0)) Register(float64(0)) - Register(complex(0i)) Register(complex64(0i)) Register(complex128(0i)) Register(false) diff --git a/src/pkg/gob/type_test.go b/src/pkg/gob/type_test.go index 106e4f10b..5aecde103 100644 --- a/src/pkg/gob/type_test.go +++ b/src/pkg/gob/type_test.go @@ -135,8 +135,8 @@ type Foo struct { b int32 // will become int c string d []byte - e *float // will become float - f ****float64 // will become float + e *float64 // will become float64 + f ****float64 // will become float64 g *Bar h *Bar // should not interpolate the definition of Bar again i *Foo // will not explode diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go index 29678ee32..022f4f124 100644 --- a/src/pkg/http/client.go +++ b/src/pkg/http/client.go @@ -120,6 +120,7 @@ func Get(url string) (r *Response, finalURL string, err os.Error) { // TODO: if/when we add cookie support, the redirected request shouldn't // necessarily supply the same cookies as the original. // TODO: set referrer header on redirects. + var base *URL for redirect := 0; ; redirect++ { if redirect >= 10 { err = os.ErrorString("stopped after 10 redirects") @@ -127,7 +128,12 @@ func Get(url string) (r *Response, finalURL string, err os.Error) { } var req Request - if req.URL, err = ParseURL(url); err != nil { + if base == nil { + req.URL, err = ParseURL(url) + } else { + req.URL, err = base.ParseURL(url) + } + if err != nil { break } url = req.URL.String() @@ -140,6 +146,7 @@ func Get(url string) (r *Response, finalURL string, err os.Error) { err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode)) break } + base = req.URL continue } finalURL = url diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go index 143a839a8..bbfa58d26 100644 --- a/src/pkg/http/fs.go +++ b/src/pkg/http/fs.go @@ -166,7 +166,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { } size = ra.length code = StatusPartialContent - w.SetHeader("Content-Range", fmt.Sprintf("%d-%d/%d", ra.start, ra.start+ra.length, d.Size)) + w.SetHeader("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size)) } w.SetHeader("Accept-Ranges", "bytes") @@ -174,7 +174,9 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) { w.WriteHeader(code) - io.Copyn(w, f, size) + if r.Method != "HEAD" { + io.Copyn(w, f, size) + } } // ServeFile replies to the request with the contents of the named file or directory. diff --git a/src/pkg/http/fs_test.go b/src/pkg/http/fs_test.go index 0f7135692..0a5636b88 100644 --- a/src/pkg/http/fs_test.go +++ b/src/pkg/http/fs_test.go @@ -134,7 +134,7 @@ func TestServeFile(t *testing.T) { if rt.code == StatusRequestedRangeNotSatisfiable { continue } - h := fmt.Sprintf("%d-%d/%d", rt.start, rt.end, testFileLength) + h := fmt.Sprintf("bytes %d-%d/%d", rt.start, rt.end-1, testFileLength) if rt.r == "" { h = "" } diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go index 067e17dda..5e1cbcbcb 100644 --- a/src/pkg/http/readrequest_test.go +++ b/src/pkg/http/readrequest_test.go @@ -69,6 +69,41 @@ var reqTests = []reqTest{ "abcdef\n", }, + + // Tests that we don't parse a path that looks like a + // scheme-relative URI as a scheme-relative URI. + { + "GET //user@host/is/actually/a/path/ HTTP/1.1\r\n" + + "Host: test\r\n\r\n", + + Request{ + Method: "GET", + RawURL: "//user@host/is/actually/a/path/", + URL: &URL{ + Raw: "//user@host/is/actually/a/path/", + Scheme: "", + RawPath: "//user@host/is/actually/a/path/", + RawAuthority: "", + RawUserinfo: "", + Host: "", + Path: "//user@host/is/actually/a/path/", + RawQuery: "", + Fragment: "", + }, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: map[string]string{}, + Close: false, + ContentLength: -1, + Host: "test", + Referer: "", + UserAgent: "", + Form: map[string][]string{}, + }, + + "", + }, } func TestReadRequest(t *testing.T) { diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go index b88689988..04bebaaf5 100644 --- a/src/pkg/http/request.go +++ b/src/pkg/http/request.go @@ -504,7 +504,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) { return nil, &badStringError{"malformed HTTP version", req.Proto} } - if req.URL, err = ParseURL(req.RawURL); err != nil { + if req.URL, err = ParseRequestURL(req.RawURL); err != nil { return nil, err } diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go index 43e1b93a5..7da3fc6f3 100644 --- a/src/pkg/http/serve_test.go +++ b/src/pkg/http/serve_test.go @@ -7,7 +7,9 @@ package http import ( + "bufio" "bytes" + "io" "os" "net" "testing" @@ -133,3 +135,151 @@ func TestConsumingBodyOnNextConn(t *testing.T) { t.Errorf("Serve returned %q; expected EOF", serveerr) } } + +type stringHandler string + +func (s stringHandler) ServeHTTP(w ResponseWriter, r *Request) { + w.SetHeader("Result", string(s)) +} + +var handlers = []struct { + pattern string + msg string +}{ + {"/", "Default"}, + {"/someDir/", "someDir"}, + {"someHost.com/someDir/", "someHost.com/someDir"}, +} + +var vtests = []struct { + url string + expected string +}{ + {"http://localhost/someDir/apage", "someDir"}, + {"http://localhost/otherDir/apage", "Default"}, + {"http://someHost.com/someDir/apage", "someHost.com/someDir"}, + {"http://otherHost.com/someDir/apage", "someDir"}, + {"http://otherHost.com/aDir/apage", "Default"}, +} + +func TestHostHandlers(t *testing.T) { + for _, h := range handlers { + Handle(h.pattern, stringHandler(h.msg)) + } + l, err := net.Listen("tcp", "127.0.0.1:0") // any port + if err != nil { + t.Fatal(err) + } + defer l.Close() + go Serve(l, nil) + conn, err := net.Dial("tcp", "", l.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + cc := NewClientConn(conn, nil) + for _, vt := range vtests { + var r *Response + var req Request + if req.URL, err = ParseURL(vt.url); err != nil { + t.Errorf("cannot parse url: %v", err) + continue + } + if err := cc.Write(&req); err != nil { + t.Errorf("writing request: %v", err) + continue + } + r, err := cc.Read() + if err != nil { + t.Errorf("reading response: %v", err) + continue + } + s := r.Header["Result"] + if s != vt.expected { + t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected) + } + } +} + +type responseWriterMethodCall struct { + method string + headerKey, headerValue string // if method == "SetHeader" + bytesWritten []byte // if method == "Write" + responseCode int // if method == "WriteHeader" +} + +type recordingResponseWriter struct { + log []*responseWriterMethodCall +} + +func (rw *recordingResponseWriter) RemoteAddr() string { + return "1.2.3.4" +} + +func (rw *recordingResponseWriter) UsingTLS() bool { + return false +} + +func (rw *recordingResponseWriter) SetHeader(k, v string) { + rw.log = append(rw.log, &responseWriterMethodCall{method: "SetHeader", headerKey: k, headerValue: v}) +} + +func (rw *recordingResponseWriter) Write(buf []byte) (int, os.Error) { + rw.log = append(rw.log, &responseWriterMethodCall{method: "Write", bytesWritten: buf}) + return len(buf), nil +} + +func (rw *recordingResponseWriter) WriteHeader(code int) { + rw.log = append(rw.log, &responseWriterMethodCall{method: "WriteHeader", responseCode: code}) +} + +func (rw *recordingResponseWriter) Flush() { + rw.log = append(rw.log, &responseWriterMethodCall{method: "Flush"}) +} + +func (rw *recordingResponseWriter) Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error) { + panic("Not supported") +} + +// Tests for http://code.google.com/p/go/issues/detail?id=900 +func TestMuxRedirectLeadingSlashes(t *testing.T) { + paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"} + for _, path := range paths { + req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n"))) + if err != nil { + t.Errorf("%s", err) + } + mux := NewServeMux() + resp := new(recordingResponseWriter) + resp.log = make([]*responseWriterMethodCall, 0) + + mux.ServeHTTP(resp, req) + + dumpLog := func() { + t.Logf("For path %q:", path) + for _, call := range resp.log { + t.Logf("Got call: %s, header=%s, value=%s, buf=%q, code=%d", call.method, + call.headerKey, call.headerValue, call.bytesWritten, call.responseCode) + } + } + + if len(resp.log) != 2 { + dumpLog() + t.Errorf("expected 2 calls to response writer; got %d", len(resp.log)) + return + } + + if resp.log[0].method != "SetHeader" || + resp.log[0].headerKey != "Location" || resp.log[0].headerValue != "/foo.txt" { + dumpLog() + t.Errorf("Expected SetHeader of Location to /foo.txt") + return + } + + if resp.log[1].method != "WriteHeader" || resp.log[1].responseCode != StatusMovedPermanently { + dumpLog() + t.Errorf("Expected WriteHeader of StatusMovedPermanently") + return + } + } +} diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go index b8783da28..6672c494b 100644 --- a/src/pkg/http/server.go +++ b/src/pkg/http/server.go @@ -181,7 +181,9 @@ func (c *conn) readRequest() (w *response, err os.Error) { w.SetHeader("Content-Type", "text/html; charset=utf-8") w.SetHeader("Date", time.UTC().Format(TimeFormat)) - if req.ProtoAtLeast(1, 1) { + if req.Method == "HEAD" { + // do nothing + } else if req.ProtoAtLeast(1, 1) { // HTTP/1.1 or greater: use chunked transfer encoding // to avoid closing the connection at EOF. w.chunking = true @@ -227,6 +229,10 @@ func (w *response) WriteHeader(code int) { w.header["Transfer-Encoding"] = "", false w.chunking = false } + // Cannot use Content-Length with non-identity Transfer-Encoding. + if w.chunking { + w.header["Content-Length"] = "", false + } if !w.req.ProtoAtLeast(1, 0) { return } @@ -268,7 +274,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) { return 0, nil } - if w.status == StatusNotModified { + if w.status == StatusNotModified || w.req.Method == "HEAD" { // Must not have body. return 0, ErrBodyNotAllowed } @@ -495,11 +501,11 @@ func Redirect(w ResponseWriter, r *Request, url string, code int) { // RFC2616 recommends that a short note "SHOULD" be included in the // response because older user agents may not understand 301/307. - note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n" - if r.Method == "POST" { - note = "" + // Shouldn't send the response for POST or HEAD; that leaves GET. + if r.Method == "GET" { + note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n" + fmt.Fprintln(w, note) } - fmt.Fprintln(w, note) } func htmlEscape(s string) string { @@ -533,9 +539,8 @@ func RedirectHandler(url string, code int) Handler { // patterns and calls the handler for the pattern that // most closely matches the URL. // -// Patterns named fixed paths, like "/favicon.ico", -// or subtrees, like "/images/" (note the trailing slash). -// Patterns must begin with /. +// Patterns named fixed, rooted paths, like "/favicon.ico", +// or rooted subtrees, like "/images/" (note the trailing slash). // Longer patterns take precedence over shorter ones, so that // if there are handlers registered for both "/images/" // and "/images/thumbnails/", the latter handler will be @@ -543,11 +548,11 @@ func RedirectHandler(url string, code int) Handler { // former will receiver requests for any other paths in the // "/images/" subtree. // -// In the future, the pattern syntax may be relaxed to allow -// an optional host-name at the beginning of the pattern, -// so that a handler might register for the two patterns -// "/codesearch" and "codesearch.google.com/" -// without taking over requests for http://www.google.com/. +// Patterns may optionally begin with a host name, restricting matches to +// URLs on that host only. Host-specific patterns take precedence over +// general patterns, so that a handler might register for the two patterns +// "/codesearch" and "codesearch.google.com/" without also taking over +// requests for "http://www.google.com/". // // ServeMux also takes care of sanitizing the URL request path, // redirecting any request containing . or .. elements to an @@ -592,21 +597,13 @@ func cleanPath(p string) string { return np } -// ServeHTTP dispatches the request to the handler whose -// pattern most closely matches the request URL. -func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { - // Clean path to canonical form and redirect. - if p := cleanPath(r.URL.Path); p != r.URL.Path { - w.SetHeader("Location", p) - w.WriteHeader(StatusMovedPermanently) - return - } - - // Most-specific (longest) pattern wins. +// Find a handler on a handler map given a path string +// Most-specific (longest) pattern wins +func (mux *ServeMux) match(path string) Handler { var h Handler var n = 0 for k, v := range mux.m { - if !pathMatch(k, r.URL.Path) { + if !pathMatch(k, path) { continue } if h == nil || len(k) > n { @@ -614,6 +611,23 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { h = v } } + return h +} + +// ServeHTTP dispatches the request to the handler whose +// pattern most closely matches the request URL. +func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { + // Clean path to canonical form and redirect. + if p := cleanPath(r.URL.Path); p != r.URL.Path { + w.SetHeader("Location", p) + w.WriteHeader(StatusMovedPermanently) + return + } + // Host-specific pattern takes precedence over generic ones + h := mux.match(r.Host + r.URL.Path) + if h == nil { + h = mux.match(r.URL.Path) + } if h == nil { h = NotFoundHandler() } @@ -622,7 +636,7 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { // Handle registers the handler for the given pattern. func (mux *ServeMux) Handle(pattern string, handler Handler) { - if pattern == "" || pattern[0] != '/' { + if pattern == "" { panic("http: invalid pattern " + pattern) } @@ -697,7 +711,7 @@ func Serve(l net.Listener, handler Handler) os.Error { // http.HandleFunc("/hello", HelloServer) // err := http.ListenAndServe(":12345", nil) // if err != nil { -// log.Exit("ListenAndServe: ", err.String()) +// log.Fatal("ListenAndServe: ", err.String()) // } // } func ListenAndServe(addr string, handler Handler) os.Error { @@ -731,7 +745,7 @@ func ListenAndServe(addr string, handler Handler) os.Error { // log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") // err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil) // if err != nil { -// log.Exit(err) +// log.Fatal(err) // } // } // diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go index f0ac4c1df..efd90d81e 100644 --- a/src/pkg/http/url.go +++ b/src/pkg/http/url.go @@ -114,62 +114,6 @@ func shouldEscape(c byte, mode encoding) bool { return true } -// CanonicalPath applies the algorithm specified in RFC 2396 to -// simplify the path, removing unnecessary . and .. elements. -func CanonicalPath(path string) string { - buf := []byte(path) - a := buf[0:0] - // state helps to find /.. ^.. ^. and /. patterns. - // state == 1 - prev char is '/' or beginning of the string. - // state > 1 - prev state > 0 and prev char was '.' - // state == 0 - otherwise - state := 1 - cnt := 0 - for _, v := range buf { - switch v { - case '/': - s := state - state = 1 - switch s { - case 2: - a = a[0 : len(a)-1] - continue - case 3: - if cnt > 0 { - i := len(a) - 4 - for ; i >= 0 && a[i] != '/'; i-- { - } - a = a[0 : i+1] - cnt-- - continue - } - default: - if len(a) > 0 { - cnt++ - } - } - case '.': - if state > 0 { - state++ - } - default: - state = 0 - } - l := len(a) - a = a[0 : l+1] - a[l] = v - } - switch { - case state == 2: - a = a[0 : len(a)-1] - case state == 3 && cnt > 0: - i := len(a) - 4 - for ; i >= 0 && a[i] != '/'; i-- { - } - a = a[0 : i+1] - } - return string(a) -} // URLUnescape unescapes a string in ``URL encoded'' form, // converting %AB into the byte 0xAB and '+' into ' ' (space). @@ -385,7 +329,25 @@ func split(s string, c byte, cutc bool) (string, string) { // ParseURL parses rawurl into a URL structure. // The string rawurl is assumed not to have a #fragment suffix. // (Web browsers strip #fragment before sending the URL to a web server.) +// The rawurl may be relative or absolute. func ParseURL(rawurl string) (url *URL, err os.Error) { + return parseURL(rawurl, false) +} + +// ParseRequestURL parses rawurl into a URL structure. It assumes that +// rawurl was received from an HTTP request, so the rawurl is interpreted +// only as an absolute URI or an absolute path. +// The string rawurl is assumed not to have a #fragment suffix. +// (Web browsers strip #fragment before sending the URL to a web server.) +func ParseRequestURL(rawurl string) (url *URL, err os.Error) { + return parseURL(rawurl, true) +} + +// parseURL parses a URL from a string in one of two contexts. If +// viaRequest is true, the URL is assumed to have arrived via an HTTP request, +// in which case only absolute URLs or path-absolute relative URLs are allowed. +// If viaRequest is false, all forms of relative URLs are allowed. +func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) { if rawurl == "" { err = os.ErrorString("empty url") goto Error @@ -400,7 +362,9 @@ func ParseURL(rawurl string) (url *URL, err os.Error) { goto Error } - if url.Scheme != "" && (len(path) == 0 || path[0] != '/') { + leadingSlash := strings.HasPrefix(path, "/") + + if url.Scheme != "" && !leadingSlash { // RFC 2396: // Absolute URI (has scheme) with non-rooted path // is uninterpreted. It doesn't even have a ?query. @@ -412,6 +376,11 @@ func ParseURL(rawurl string) (url *URL, err os.Error) { } url.OpaquePath = true } else { + if viaRequest && !leadingSlash { + err = os.ErrorString("invalid URI for request") + goto Error + } + // Split off query before parsing path further. url.RawPath = path path, query := split(path, '?', false) @@ -420,7 +389,8 @@ func ParseURL(rawurl string) (url *URL, err os.Error) { } // Maybe path is //authority/path - if url.Scheme != "" && len(path) > 2 && path[0:2] == "//" { + if (url.Scheme != "" || !viaRequest) && + strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///") { url.RawAuthority, path = split(path[2:], '/', false) url.RawPath = url.RawPath[2+len(url.RawAuthority):] } @@ -527,3 +497,99 @@ func EncodeQuery(m map[string][]string) string { } return strings.Join(parts, "&") } + +// resolvePath applies special path segments from refs and applies +// them to base, per RFC 2396. +func resolvePath(basepath string, refpath string) string { + base := strings.Split(basepath, "/", -1) + refs := strings.Split(refpath, "/", -1) + if len(base) == 0 { + base = []string{""} + } + for idx, ref := range refs { + switch { + case ref == ".": + base[len(base)-1] = "" + case ref == "..": + newLen := len(base) - 1 + if newLen < 1 { + newLen = 1 + } + base = base[0:newLen] + base[len(base)-1] = "" + default: + if idx == 0 || base[len(base)-1] == "" { + base[len(base)-1] = ref + } else { + base = append(base, ref) + } + } + } + return strings.Join(base, "/") +} + +// IsAbs returns true if the URL is absolute. +func (url *URL) IsAbs() bool { + return url.Scheme != "" +} + +// ParseURL parses a URL in the context of a base URL. The URL in ref +// may be relative or absolute. ParseURL returns nil, err on parse +// failure, otherwise its return value is the same as ResolveReference. +func (base *URL) ParseURL(ref string) (*URL, os.Error) { + refurl, err := ParseURL(ref) + if err != nil { + return nil, err + } + return base.ResolveReference(refurl), nil +} + +// ResolveReference resolves a URI reference to an absolute URI from +// an absolute base URI, per RFC 2396 Section 5.2. The URI reference +// may be relative or absolute. ResolveReference always returns a new +// URL instance, even if the returned URL is identical to either the +// base or reference. If ref is an absolute URL, then ResolveReference +// ignores base and returns a copy of ref. +func (base *URL) ResolveReference(ref *URL) *URL { + url := new(URL) + switch { + case ref.IsAbs(): + *url = *ref + default: + // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] + *url = *base + if ref.RawAuthority != "" { + // The "net_path" case. + url.RawAuthority = ref.RawAuthority + url.Host = ref.Host + url.RawUserinfo = ref.RawUserinfo + } + switch { + case url.OpaquePath: + url.Path = ref.Path + url.RawPath = ref.RawPath + url.RawQuery = ref.RawQuery + case strings.HasPrefix(ref.Path, "/"): + // The "abs_path" case. + url.Path = ref.Path + url.RawPath = ref.RawPath + url.RawQuery = ref.RawQuery + default: + // The "rel_path" case. + path := resolvePath(base.Path, ref.Path) + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + url.Path = path + url.RawPath = url.Path + url.RawQuery = ref.RawQuery + if ref.RawQuery != "" { + url.RawPath += "?" + url.RawQuery + } + } + + url.Fragment = ref.Fragment + } + url.Raw = url.String() + return url +} diff --git a/src/pkg/http/url_test.go b/src/pkg/http/url_test.go index 447d5390e..0801f7ff3 100644 --- a/src/pkg/http/url_test.go +++ b/src/pkg/http/url_test.go @@ -188,14 +188,48 @@ var urltests = []URLTest{ }, "", }, - // leading // without scheme shouldn't create an authority + // leading // without scheme should create an authority { "//foo", &URL{ - Raw: "//foo", - Scheme: "", - RawPath: "//foo", - Path: "//foo", + RawAuthority: "foo", + Raw: "//foo", + Host: "foo", + Scheme: "", + RawPath: "", + Path: "", + }, + "", + }, + // leading // without scheme, with userinfo, path, and query + { + "//user@foo/path?a=b", + &URL{ + Raw: "//user@foo/path?a=b", + RawAuthority: "user@foo", + RawUserinfo: "user", + Scheme: "", + RawPath: "/path?a=b", + Path: "/path", + RawQuery: "a=b", + Host: "foo", + }, + "", + }, + // Three leading slashes isn't an authority, but doesn't return an error. + // (We can't return an error, as this code is also used via + // ServeHTTP -> ReadRequest -> ParseURL, which is arguably a + // different URL parsing context, but currently shares the + // same codepath) + { + "///threeslashes", + &URL{ + RawAuthority: "", + Raw: "///threeslashes", + Host: "", + Scheme: "", + RawPath: "///threeslashes", + Path: "///threeslashes", }, "", }, @@ -272,7 +306,7 @@ var urlfragtests = []URLTest{ // more useful string for debugging than fmt's struct printer func ufmt(u *URL) string { - return fmt.Sprintf("%q, %q, %q, %q, %q, %q, %q, %q, %q", + return fmt.Sprintf("raw=%q, scheme=%q, rawpath=%q, auth=%q, userinfo=%q, host=%q, path=%q, rawq=%q, frag=%q", u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo, u.Host, u.Path, u.RawQuery, u.Fragment) } @@ -301,6 +335,40 @@ func TestParseURLReference(t *testing.T) { DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests) } +const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path" + +var parseRequestUrlTests = []struct { + url string + expectedValid bool +}{ + {"http://foo.com", true}, + {"http://foo.com/", true}, + {"http://foo.com/path", true}, + {"/", true}, + {pathThatLooksSchemeRelative, true}, + {"//not.a.user@%66%6f%6f.com/just/a/path/also", true}, + {"foo.html", false}, + {"../dir/", false}, +} + +func TestParseRequestURL(t *testing.T) { + for _, test := range parseRequestUrlTests { + _, err := ParseRequestURL(test.url) + valid := err == nil + if valid != test.expectedValid { + t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid) + } + } + + url, err := ParseRequestURL(pathThatLooksSchemeRelative) + if err != nil { + t.Fatalf("Unexpected error %v", err) + } + if url.Path != pathThatLooksSchemeRelative { + t.Errorf("Expected path %q; got %q", pathThatLooksSchemeRelative, url.Path) + } +} + func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string, tests []URLTest) { for _, tt := range tests { u, err := parse(tt.in) @@ -442,44 +510,6 @@ func TestURLEscape(t *testing.T) { } } -type CanonicalPathTest struct { - in string - out string -} - -var canonicalTests = []CanonicalPathTest{ - {"", ""}, - {"/", "/"}, - {".", ""}, - {"./", ""}, - {"/a/", "/a/"}, - {"a/", "a/"}, - {"a/./", "a/"}, - {"./a", "a"}, - {"/a/../b", "/b"}, - {"a/../b", "b"}, - {"a/../../b", "../b"}, - {"a/.", "a/"}, - {"../.././a", "../../a"}, - {"/../.././a", "/../../a"}, - {"a/b/g/../..", "a/"}, - {"a/b/..", "a/"}, - {"a/b/.", "a/b/"}, - {"a/b/../../../..", "../.."}, - {"a./", "a./"}, - {"/../a/b/../../../", "/../../"}, - {"../a/b/../../../", "../../"}, -} - -func TestCanonicalPath(t *testing.T) { - for _, tt := range canonicalTests { - actual := CanonicalPath(tt.in) - if tt.out != actual { - t.Errorf("CanonicalPath(%q) = %q, want %q", tt.in, actual, tt.out) - } - } -} - type UserinfoTest struct { User string Password string @@ -529,3 +559,117 @@ func TestEncodeQuery(t *testing.T) { } } } + +var resolvePathTests = []struct { + base, ref, expected string +}{ + {"a/b", ".", "a/"}, + {"a/b", "c", "a/c"}, + {"a/b", "..", ""}, + {"a/", "..", ""}, + {"a/", "../..", ""}, + {"a/b/c", "..", "a/"}, + {"a/b/c", "../d", "a/d"}, + {"a/b/c", ".././d", "a/d"}, + {"a/b", "./..", ""}, + {"a/./b", ".", "a/./"}, + {"a/../", ".", "a/../"}, + {"a/.././b", "c", "a/.././c"}, +} + +func TestResolvePath(t *testing.T) { + for _, test := range resolvePathTests { + got := resolvePath(test.base, test.ref) + if got != test.expected { + t.Errorf("For %q + %q got %q; expected %q", test.base, test.ref, got, test.expected) + } + } +} + +var resolveReferenceTests = []struct { + base, rel, expected string +}{ + // Absolute URL references + {"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"}, + {"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"}, + {"http://foo.com/bar", "mailto:foo@example.com", "mailto:foo@example.com"}, + + // Path-absolute references + {"http://foo.com/bar", "/baz", "http://foo.com/baz"}, + {"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"}, + {"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"}, + + // Scheme-relative + {"https://foo.com/bar?a=b", "//bar.com/quux", "https://bar.com/quux"}, + + // Path-relative references: + + // ... current directory + {"http://foo.com", ".", "http://foo.com/"}, + {"http://foo.com/bar", ".", "http://foo.com/"}, + {"http://foo.com/bar/", ".", "http://foo.com/bar/"}, + + // ... going down + {"http://foo.com", "bar", "http://foo.com/bar"}, + {"http://foo.com/", "bar", "http://foo.com/bar"}, + {"http://foo.com/bar/baz", "quux", "http://foo.com/bar/quux"}, + + // ... going up + {"http://foo.com/bar/baz", "../quux", "http://foo.com/quux"}, + {"http://foo.com/bar/baz", "../../../../../quux", "http://foo.com/quux"}, + {"http://foo.com/bar", "..", "http://foo.com/"}, + {"http://foo.com/bar/baz", "./..", "http://foo.com/"}, + + // "." and ".." in the base aren't special + {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/./dotdot/../baz"}, + + // Triple dot isn't special + {"http://foo.com/bar", "...", "http://foo.com/..."}, + + // Fragment + {"http://foo.com/bar", ".#frag", "http://foo.com/#frag"}, +} + +func TestResolveReference(t *testing.T) { + mustParseURL := func(url string) *URL { + u, err := ParseURLReference(url) + if err != nil { + t.Fatalf("Expected URL to parse: %q, got error: %v", url, err) + } + return u + } + for _, test := range resolveReferenceTests { + base := mustParseURL(test.base) + rel := mustParseURL(test.rel) + url := base.ResolveReference(rel) + urlStr := url.String() + if urlStr != test.expected { + t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr) + } + } + + // Test that new instances are returned. + base := mustParseURL("http://foo.com/") + abs := base.ResolveReference(mustParseURL(".")) + if base == abs { + t.Errorf("Expected no-op reference to return new URL instance.") + } + barRef := mustParseURL("http://bar.com/") + abs = base.ResolveReference(barRef) + if abs == barRef { + t.Errorf("Expected resolution of absolute reference to return new URL instance.") + } + + // Test the convenience wrapper too + base = mustParseURL("http://foo.com/path/one/") + abs, _ = base.ParseURL("../two") + expected := "http://foo.com/path/two" + if abs.String() != expected { + t.Errorf("ParseURL wrapper got %q; expected %q", abs.String(), expected) + } + _, err := base.ParseURL("") + if err == nil { + t.Errorf("Expected an error from ParseURL wrapper parsing an empty string.") + } + +} diff --git a/src/pkg/index/suffixarray/qsufsort.go b/src/pkg/index/suffixarray/qsufsort.go index 0e6894a8b..9751b5c76 100644 --- a/src/pkg/index/suffixarray/qsufsort.go +++ b/src/pkg/index/suffixarray/qsufsort.go @@ -146,19 +146,25 @@ func (x *suffixSortable) Swap(i, j int) { x.sa[i], x.sa[j] = x.sa[j], x.sa[ func (x *suffixSortable) updateGroups(offset int) { - prev := len(x.sa) - 1 - group := x.inv[x.sa[prev]+x.h] - for i := prev; i >= 0; i-- { - if g := x.inv[x.sa[i]+x.h]; g < group { - if prev == i+1 { // previous group had size 1 and is thus sorted - x.sa[i+1] = -1 - } + bounds := make([]int, 0, 4) + group := x.inv[x.sa[0]+x.h] + for i := 1; i < len(x.sa); i++ { + if g := x.inv[x.sa[i]+x.h]; g > group { + bounds = append(bounds, i) group = g - prev = i } - x.inv[x.sa[i]] = prev + offset - if prev == 0 { // first group has size 1 and is thus sorted - x.sa[0] = -1 + } + bounds = append(bounds, len(x.sa)) + + // update the group numberings after all new groups are determined + prev := 0 + for _, b := range bounds { + for i := prev; i < b; i++ { + x.inv[x.sa[i]] = offset + b - 1 + } + if b-prev == 1 { + x.sa[prev] = -1 } + prev = b } } diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go index 628e000e1..d8c6fc91b 100644 --- a/src/pkg/index/suffixarray/suffixarray.go +++ b/src/pkg/index/suffixarray/suffixarray.go @@ -50,27 +50,33 @@ func (x *Index) at(i int) []byte { } -func (x *Index) search(s []byte) int { - return sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 }) +// lookupAll returns a slice into the matching region of the index. +// The runtime is O(log(N)*len(s)). +func (x *Index) lookupAll(s []byte) []int { + // find matching suffix index range [i:j] + // find the first index where s would be the prefix + i := sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 }) + // starting at i, find the first index at which s is not a prefix + j := i + sort.Search(len(x.sa)-i, func(j int) bool { return !bytes.HasPrefix(x.at(j+i), s) }) + return x.sa[i:j] } // Lookup returns an unsorted list of at most n indices where the byte string s // occurs in the indexed data. If n < 0, all occurrences are returned. // The result is nil if s is empty, s is not found, or n == 0. -// Lookup time is O((log(N) + len(result))*len(s)) where N is the +// Lookup time is O(log(N)*len(s) + len(result)) where N is the // size of the indexed data. // func (x *Index) Lookup(s []byte, n int) (result []int) { if len(s) > 0 && n != 0 { - // find matching suffix index i - i := x.search(s) - // x.at(i-1) < s <= x.at(i) - - // collect the following suffixes with matching prefixes - for (n < 0 || len(result) < n) && i < len(x.sa) && bytes.HasPrefix(x.at(i), s) { - result = append(result, x.sa[i]) - i++ + matches := x.lookupAll(s) + if len(matches) < n || n < 0 { + n = len(matches) + } + if n > 0 { + result = make([]int, n) + copy(result, matches) } } return diff --git a/src/pkg/index/suffixarray/suffixarray_test.go b/src/pkg/index/suffixarray/suffixarray_test.go index b3486a96d..e85267f17 100644 --- a/src/pkg/index/suffixarray/suffixarray_test.go +++ b/src/pkg/index/suffixarray/suffixarray_test.go @@ -99,6 +99,12 @@ var testCases = []testCase{ "to (come|the)?", }, }, + + { + "godoc simulation", + "package main\n\nimport(\n \"rand\"\n ", + []string{}, + }, } diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go index c704cacbd..ff91dd83c 100644 --- a/src/pkg/json/decode.go +++ b/src/pkg/json/decode.go @@ -749,7 +749,7 @@ func (d *decodeState) literalInterface() interface{} { } n, err := strconv.Atof64(string(item)) if err != nil { - d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(float64(0))}) + d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.Typeof(0.0)}) } return n } diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go index 68cdea051..9cb27af41 100644 --- a/src/pkg/json/decode_test.go +++ b/src/pkg/json/decode_test.go @@ -52,7 +52,7 @@ var unmarshalTests = []unmarshalTest{ // basic types {`true`, new(bool), true, nil}, {`1`, new(int), 1, nil}, - {`1.2`, new(float), 1.2, nil}, + {`1.2`, new(float64), 1.2, nil}, {`-5`, new(int16), int16(-5), nil}, {`"a\u1234"`, new(string), "a\u1234", nil}, {`"http:\/\/"`, new(string), "http://", nil}, @@ -220,7 +220,6 @@ type All struct { Uint32 uint32 Uint64 uint64 Uintptr uintptr - Float float Float32 float32 Float64 float64 @@ -238,7 +237,6 @@ type All struct { PUint32 *uint32 PUint64 *uint64 PUintptr *uintptr - PFloat *float PFloat32 *float32 PFloat64 *float64 @@ -291,7 +289,6 @@ var allValue = All{ Uint32: 10, Uint64: 11, Uintptr: 12, - Float: 13.1, Float32: 14.1, Float64: 15.1, Foo: "foo", @@ -312,7 +309,7 @@ var allValue = All{ ByteSlice: []byte{27, 28, 29}, Small: Small{Tag: "tag30"}, PSmall: &Small{Tag: "tag31"}, - Interface: float64(5.2), + Interface: 5.2, } var pallValue = All{ @@ -328,7 +325,6 @@ var pallValue = All{ PUint32: &allValue.Uint32, PUint64: &allValue.Uint64, PUintptr: &allValue.Uintptr, - PFloat: &allValue.Float, PFloat32: &allValue.Float32, PFloat64: &allValue.Float64, PString: &allValue.String, @@ -353,7 +349,6 @@ var allValueIndent = `{ "Uint32": 10, "Uint64": 11, "Uintptr": 12, - "Float": 13.1, "Float32": 14.1, "Float64": 15.1, "bar": "foo", @@ -369,7 +364,6 @@ var allValueIndent = `{ "PUint32": null, "PUint64": null, "PUintptr": null, - "PFloat": null, "PFloat32": null, "PFloat64": null, "String": "16", @@ -449,7 +443,6 @@ var pallValueIndent = `{ "Uint32": 0, "Uint64": 0, "Uintptr": 0, - "Float": 0, "Float32": 0, "Float64": 0, "bar": "", @@ -465,7 +458,6 @@ var pallValueIndent = `{ "PUint32": 10, "PUint64": 11, "PUintptr": 12, - "PFloat": 13.1, "PFloat32": 14.1, "PFloat64": 15.1, "String": "", diff --git a/src/pkg/json/scanner.go b/src/pkg/json/scanner.go index 112c8f9c3..e98ddef5c 100644 --- a/src/pkg/json/scanner.go +++ b/src/pkg/json/scanner.go @@ -416,7 +416,7 @@ func state0(s *scanner, c int) int { s.step = stateDot return scanContinue } - if c == 'e' { + if c == 'e' || c == 'E' { s.step = stateE return scanContinue } @@ -440,7 +440,7 @@ func stateDot0(s *scanner, c int) int { s.step = stateDot0 return scanContinue } - if c == 'e' { + if c == 'e' || c == 'E' { s.step = stateE return scanContinue } diff --git a/src/pkg/json/stream_test.go b/src/pkg/json/stream_test.go index c83cfe3a9..6ddaed9fe 100644 --- a/src/pkg/json/stream_test.go +++ b/src/pkg/json/stream_test.go @@ -13,14 +13,14 @@ import ( // Test values for the stream test. // One of each JSON kind. var streamTest = []interface{}{ - float64(0.1), + 0.1, "hello", nil, true, false, []interface{}{"a", "b", "c"}, map[string]interface{}{"K": "Kelvin", "ß": "long s"}, - float64(3.14), // another value to make sure something can follow map + 3.14, // another value to make sure something can follow map } var streamEncoded = `0.1 diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go index d34af9e5e..658e3bd94 100644 --- a/src/pkg/log/log.go +++ b/src/pkg/log/log.go @@ -4,11 +4,11 @@ // Simple logging package. It defines a type, Logger, with methods // for formatting output. It also has a predefined 'standard' Logger -// accessible through helper functions Print[f|ln], Exit[f|ln], and +// accessible through helper functions Print[f|ln], Fatal[f|ln], and // Panic[f|ln], which are easier to use than creating a Logger manually. // That logger writes to standard error and prints the date and time // of each logged message. -// The Exit functions call os.Exit(1) after writing the log message. +// The Fatal functions call os.Exit(1) after writing the log message. // The Panic functions call panic after writing the log message. package log @@ -164,20 +164,20 @@ func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) } // Arguments are handled in the manner of fmt.Println. func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) } -// Exit is equivalent to l.Print() followed by a call to os.Exit(1). -func (l *Logger) Exit(v ...interface{}) { +// Fatal is equivalent to l.Print() followed by a call to os.Exit(1). +func (l *Logger) Fatal(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) os.Exit(1) } -// Exitf is equivalent to l.Printf() followed by a call to os.Exit(1). -func (l *Logger) Exitf(format string, v ...interface{}) { +// Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1). +func (l *Logger) Fatalf(format string, v ...interface{}) { l.Output(2, fmt.Sprintf(format, v...)) os.Exit(1) } -// Exitln is equivalent to l.Println() followed by a call to os.Exit(1). -func (l *Logger) Exitln(v ...interface{}) { +// Fatalln is equivalent to l.Println() followed by a call to os.Exit(1). +func (l *Logger) Fatalln(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) os.Exit(1) } @@ -238,20 +238,20 @@ func Println(v ...interface{}) { std.Output(2, fmt.Sprintln(v...)) } -// Exit is equivalent to Print() followed by a call to os.Exit(1). -func Exit(v ...interface{}) { +// Fatal is equivalent to Print() followed by a call to os.Exit(1). +func Fatal(v ...interface{}) { std.Output(2, fmt.Sprint(v...)) os.Exit(1) } -// Exitf is equivalent to Printf() followed by a call to os.Exit(1). -func Exitf(format string, v ...interface{}) { +// Fatalf is equivalent to Printf() followed by a call to os.Exit(1). +func Fatalf(format string, v ...interface{}) { std.Output(2, fmt.Sprintf(format, v...)) os.Exit(1) } -// Exitln is equivalent to Println() followed by a call to os.Exit(1). -func Exitln(v ...interface{}) { +// Fatalln is equivalent to Println() followed by a call to os.Exit(1). +func Fatalln(v ...interface{}) { std.Output(2, fmt.Sprintln(v...)) os.Exit(1) } diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go index 6033d37e3..d2a7d411e 100644 --- a/src/pkg/math/all_test.go +++ b/src/pkg/math/all_test.go @@ -1112,6 +1112,33 @@ var jM3SC = []float64{ NaN(), } +var vfldexpSC = []fi{ + {0, 0}, + {0, -1075}, + {0, 1024}, + {Copysign(0, -1), 0}, + {Copysign(0, -1), -1075}, + {Copysign(0, -1), 1024}, + {Inf(1), 0}, + {Inf(1), -1024}, + {Inf(-1), 0}, + {Inf(-1), -1024}, + {NaN(), -1024}, +} +var ldexpSC = []float64{ + 0, + 0, + 0, + Copysign(0, -1), + Copysign(0, -1), + Copysign(0, -1), + Inf(1), + Inf(1), + Inf(-1), + Inf(-1), + NaN(), +} + var vflgammaSC = []float64{ Inf(-1), -3, @@ -1440,6 +1467,65 @@ var yM3SC = []float64{ NaN(), } +// arguments and expected results for boundary cases +const ( + SmallestNormalFloat64 = 2.2250738585072014e-308 // 2**-1022 + LargestSubnormalFloat64 = SmallestNormalFloat64 - SmallestNonzeroFloat64 +) + +var vffrexpBC = []float64{ + SmallestNormalFloat64, + LargestSubnormalFloat64, + SmallestNonzeroFloat64, + MaxFloat64, + -SmallestNormalFloat64, + -LargestSubnormalFloat64, + -SmallestNonzeroFloat64, + -MaxFloat64, +} +var frexpBC = []fi{ + {0.5, -1021}, + {0.99999999999999978, -1022}, + {0.5, -1073}, + {0.99999999999999989, 1024}, + {-0.5, -1021}, + {-0.99999999999999978, -1022}, + {-0.5, -1073}, + {-0.99999999999999989, 1024}, +} + +var vfldexpBC = []fi{ + {SmallestNormalFloat64, -52}, + {LargestSubnormalFloat64, -51}, + {SmallestNonzeroFloat64, 1074}, + {MaxFloat64, -(1023 + 1074)}, + {1, -1075}, + {-1, -1075}, + {1, 1024}, + {-1, 1024}, +} +var ldexpBC = []float64{ + SmallestNonzeroFloat64, + 1e-323, // 2**-1073 + 1, + 1e-323, // 2**-1073 + 0, + Copysign(0, -1), + Inf(1), + Inf(-1), +} + +var logbBC = []float64{ + -1022, + -1023, + -1074, + 1023, + -1022, + -1023, + -1074, + 1023, +} + func tolerance(a, b, e float64) bool { d := a - b if d < 0 { @@ -1792,6 +1878,11 @@ func TestFrexp(t *testing.T) { t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i) } } + for i := 0; i < len(vffrexpBC); i++ { + if f, j := Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j { + t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i) + } + } } func TestGamma(t *testing.T) { @@ -1833,6 +1924,11 @@ func TestIlogb(t *testing.T) { t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i]) } } + for i := 0; i < len(vffrexpBC); i++ { + if e := Ilogb(vffrexpBC[i]); int(logbBC[i]) != e { + t.Errorf("Ilogb(%g) = %d, want %d", vffrexpBC[i], e, int(logbBC[i])) + } + } } func TestJ0(t *testing.T) { @@ -1891,6 +1987,21 @@ func TestLdexp(t *testing.T) { t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i]) } } + for i := 0; i < len(vfldexpSC); i++ { + if f := Ldexp(vfldexpSC[i].f, vfldexpSC[i].i); !alike(ldexpSC[i], f) { + t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpSC[i].f, vfldexpSC[i].i, f, ldexpSC[i]) + } + } + for i := 0; i < len(vffrexpBC); i++ { + if f := Ldexp(frexpBC[i].f, frexpBC[i].i); !alike(vffrexpBC[i], f) { + t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpBC[i].f, frexpBC[i].i, f, vffrexpBC[i]) + } + } + for i := 0; i < len(vfldexpBC); i++ { + if f := Ldexp(vfldexpBC[i].f, vfldexpBC[i].i); !alike(ldexpBC[i], f) { + t.Errorf("Ldexp(%g, %d) = %g, want %g", vfldexpBC[i].f, vfldexpBC[i].i, f, ldexpBC[i]) + } + } } func TestLgamma(t *testing.T) { @@ -1934,6 +2045,11 @@ func TestLogb(t *testing.T) { t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i]) } } + for i := 0; i < len(vffrexpBC); i++ { + if e := Logb(vffrexpBC[i]); !alike(logbBC[i], e) { + t.Errorf("Ilogb(%g) = %g, want %g", vffrexpBC[i], e, logbBC[i]) + } + } } func TestLog10(t *testing.T) { @@ -1960,7 +2076,7 @@ func TestLog1p(t *testing.T) { t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i]) } } - a := float64(9) + a := 9.0 if f := Log1p(a); f != Ln10 { t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10) } diff --git a/src/pkg/math/bits.go b/src/pkg/math/bits.go index 1a97e7679..a1dca3ed6 100644 --- a/src/pkg/math/bits.go +++ b/src/pkg/math/bits.go @@ -47,3 +47,13 @@ func IsInf(f float64, sign int) bool { // return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf; return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64 } + +// normalize returns a normal number y and exponent exp +// satisfying x == y × 2**exp. It assumes x is finite and non-zero. +func normalize(x float64) (y float64, exp int) { + const SmallestNormal = 2.2250738585072014e-308 // 2**-1022 + if Fabs(x) < SmallestNormal { + return x * (1 << 52), -52 + } + return x, 0 +} diff --git a/src/pkg/math/frexp.go b/src/pkg/math/frexp.go index 203219c0d..867b78f36 100644 --- a/src/pkg/math/frexp.go +++ b/src/pkg/math/frexp.go @@ -8,6 +8,11 @@ package math // and an integral power of two. // It returns frac and exp satisfying f == frac × 2**exp, // with the absolute value of frac in the interval [½, 1). +// +// Special cases are: +// Frexp(±0) = ±0, 0 +// Frexp(±Inf) = ±Inf, 0 +// Frexp(NaN) = NaN, 0 func Frexp(f float64) (frac float64, exp int) { // TODO(rsc): Remove manual inlining of IsNaN, IsInf // when compiler does it for us @@ -18,8 +23,9 @@ func Frexp(f float64) (frac float64, exp int) { case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f): return f, 0 } + f, exp = normalize(f) x := Float64bits(f) - exp = int((x>>shift)&mask) - bias + 1 + exp += int((x>>shift)&mask) - bias + 1 x &^= mask << shift x |= (-1 + bias) << shift frac = Float64frombits(x) diff --git a/src/pkg/math/gamma.go b/src/pkg/math/gamma.go index 4c5b17d05..73ca0e53a 100644 --- a/src/pkg/math/gamma.go +++ b/src/pkg/math/gamma.go @@ -151,7 +151,7 @@ func Gamma(x float64) float64 { } // Reduce argument - z := float64(1) + z := 1.0 for x >= 3 { x = x - 1 z = z * x diff --git a/src/pkg/math/jn.go b/src/pkg/math/jn.go index 7d3174310..9024af3c2 100644 --- a/src/pkg/math/jn.go +++ b/src/pkg/math/jn.go @@ -132,7 +132,7 @@ func Jn(n int, x float64) float64 { } else { temp := x * 0.5 b = temp - a := float64(1) + a := 1.0 for i := 2; i <= n; i++ { a *= float64(i) // a = n! b *= temp // b = (x/2)**n @@ -181,7 +181,7 @@ func Jn(n int, x float64) float64 { q0, q1 = q1, z*q1-q0 } m := n + n - t := float64(0) + t := 0.0 for i := 2 * (n + k); i >= m; i -= 2 { t = 1 / (float64(i)/x - t) } diff --git a/src/pkg/math/ldexp.go b/src/pkg/math/ldexp.go index d04bf1581..96c95cad4 100644 --- a/src/pkg/math/ldexp.go +++ b/src/pkg/math/ldexp.go @@ -6,6 +6,11 @@ package math // Ldexp is the inverse of Frexp. // It returns frac × 2**exp. +// +// Special cases are: +// Ldexp(±0, exp) = ±0 +// Ldexp(±Inf, exp) = ±Inf +// Ldexp(NaN, exp) = NaN func Ldexp(frac float64, exp int) float64 { // TODO(rsc): Remove manual inlining of IsNaN, IsInf // when compiler does it for us @@ -13,21 +18,28 @@ func Ldexp(frac float64, exp int) float64 { switch { case frac == 0: return frac // correctly return -0 - case frac != frac: // IsNaN(frac): - return NaN() + case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac): + return frac } + frac, e := normalize(frac) + exp += e x := Float64bits(frac) - exp += int(x>>shift) & mask - if exp <= 0 { - return 0 // underflow + exp += int(x>>shift)&mask - bias + if exp < -1074 { + return Copysign(0, frac) // underflow } - if exp >= mask { // overflow + if exp > 1023 { // overflow if frac < 0 { return Inf(-1) } return Inf(1) } + var m float64 = 1 + if exp < -1022 { // denormal + exp += 52 + m = 1.0 / (1 << 52) // 2**-52 + } x &^= mask << shift - x |= uint64(exp) << shift - return Float64frombits(x) + x |= uint64(exp+bias) << shift + return m * Float64frombits(x) } diff --git a/src/pkg/math/lgamma.go b/src/pkg/math/lgamma.go index dc31be929..dc30f468f 100644 --- a/src/pkg/math/lgamma.go +++ b/src/pkg/math/lgamma.go @@ -272,7 +272,7 @@ func Lgamma(x float64) (lgamma float64, sign int) { p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6)))))) q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6))))) lgamma = 0.5*y + p/q - z := float64(1) // Lgamma(1+s) = Log(s) + Lgamma(s) + z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s) switch i { case 7: z *= (y + 6) diff --git a/src/pkg/math/logb.go b/src/pkg/math/logb.go index 9e4651517..072281ddf 100644 --- a/src/pkg/math/logb.go +++ b/src/pkg/math/logb.go @@ -4,7 +4,7 @@ package math -// Logb(x) returns the binary exponent of non-zero x. +// Logb(x) returns the binary exponent of x. // // Special cases are: // Logb(±Inf) = +Inf @@ -22,10 +22,10 @@ func Logb(x float64) float64 { case x != x: // IsNaN(x): return x } - return float64(int((Float64bits(x)>>shift)&mask) - bias) + return float64(ilogb(x)) } -// Ilogb(x) returns the binary exponent of non-zero x as an integer. +// Ilogb(x) returns the binary exponent of x as an integer. // // Special cases are: // Ilogb(±Inf) = MaxInt32 @@ -43,5 +43,12 @@ func Ilogb(x float64) int { case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0): return MaxInt32 } - return int((Float64bits(x)>>shift)&mask) - bias + return ilogb(x) +} + +// logb returns the binary exponent of x. It assumes x is finite and +// non-zero. +func ilogb(x float64) int { + x, exp := normalize(x) + return int((Float64bits(x)>>shift)&mask) - bias + exp } diff --git a/src/pkg/math/pow.go b/src/pkg/math/pow.go index f0ad84af6..06b107401 100644 --- a/src/pkg/math/pow.go +++ b/src/pkg/math/pow.go @@ -98,7 +98,7 @@ func Pow(x, y float64) float64 { } // ans = a1 * 2**ae (= 1 for now). - a1 := float64(1) + a1 := 1.0 ae := 0 // ans *= x**yf diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go index 9a4c8f688..03b9d87be 100644 --- a/src/pkg/net/dial.go +++ b/src/pkg/net/dial.go @@ -59,7 +59,7 @@ func Dial(net, laddr, raddr string) (c Conn, err os.Error) { return nil, err } return c, nil - case "unix", "unixgram": + case "unix", "unixgram", "unixpacket": var la, ra *UnixAddr if raddr != "" { if ra, err = ResolveUnixAddr(net, raddr); err != nil { @@ -102,7 +102,7 @@ Error: // Listen announces on the local network address laddr. // The network string net must be a stream-oriented -// network: "tcp", "tcp4", "tcp6", or "unix". +// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket". func Listen(net, laddr string) (l Listener, err os.Error) { switch net { case "tcp", "tcp4", "tcp6": @@ -117,7 +117,7 @@ func Listen(net, laddr string) (l Listener, err os.Error) { return nil, err } return l, nil - case "unix": + case "unix", "unixpacket": var la *UnixAddr if laddr != "" { if la, err = ResolveUnixAddr(net, laddr); err != nil { diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go index 47a478a8f..a432800cf 100644 --- a/src/pkg/net/dialgoogle_test.go +++ b/src/pkg/net/dialgoogle_test.go @@ -6,12 +6,14 @@ package net import ( "flag" + "fmt" "io" + "strings" "syscall" "testing" ) -// If an IPv6 tunnel is running (see go/stubl), we can try dialing a real IPv6 address. +// If an IPv6 tunnel is running, we can try dialing a real IPv6 address. var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present") // fd is already connected to the destination, port 80. @@ -40,16 +42,16 @@ func doDial(t *testing.T, network, addr string) { } var googleaddrs = []string{ - "74.125.19.99:80", + "%d.%d.%d.%d:80", "www.google.com:80", - "74.125.19.99:http", + "%d.%d.%d.%d:http", "www.google.com:http", - "074.125.019.099:0080", - "[::ffff:74.125.19.99]:80", - "[::ffff:4a7d:1363]:80", - "[0:0:0:0:0000:ffff:74.125.19.99]:80", - "[0:0:0:0:000000:ffff:74.125.19.99]:80", - "[0:0:0:0:0:ffff::74.125.19.99]:80", + "%03d.%03d.%03d.%03d:0080", + "[::ffff:%d.%d.%d.%d]:80", + "[::ffff:%02x%02x:%02x%02x]:80", + "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80", + "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80", + "[0:0:0:0:0:ffff::%d.%d.%d.%d]:80", "[2001:4860:0:2001::68]:80", // ipv6.google.com; removed if ipv6 flag not set } @@ -59,6 +61,24 @@ func TestDialGoogle(t *testing.T) { googleaddrs[len(googleaddrs)-1] = "" } + // Insert an actual IP address for google.com + // into the table. + + _, addrs, err := LookupHost("www.google.com") + if err != nil { + t.Fatalf("lookup www.google.com: %v", err) + } + if len(addrs) == 0 { + t.Fatalf("no addresses for www.google.com") + } + ip := ParseIP(addrs[0]).To4() + + for i, s := range googleaddrs { + if strings.Contains(s, "%") { + googleaddrs[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3]) + } + } + for i := 0; i < len(googleaddrs); i++ { addr := googleaddrs[i] if addr == "" { diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go index f1cd47bb1..3252dd454 100644 --- a/src/pkg/net/dnsclient.go +++ b/src/pkg/net/dnsclient.go @@ -15,6 +15,8 @@ package net import ( + "bytes" + "fmt" "os" "rand" "sync" @@ -96,18 +98,18 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er // Find answer for name in dns message. // On return, if err == nil, addrs != nil. -func answer(name, server string, dns *dnsMsg, qtype uint16) (addrs []dnsRR, err os.Error) { +func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) { addrs = make([]dnsRR, 0, len(dns.answer)) if dns.rcode == dnsRcodeNameError && dns.recursion_available { - return nil, &DNSError{Error: noSuchHost, Name: name} + return "", nil, &DNSError{Error: noSuchHost, Name: name} } if dns.rcode != dnsRcodeSuccess { // None of the error codes make sense // for the query we sent. If we didn't get // a name error and we didn't get success, // the server is behaving incorrectly. - return nil, &DNSError{Error: "server misbehaving", Name: name, Server: server} + return "", nil, &DNSError{Error: "server misbehaving", Name: name, Server: server} } // Look for the name. @@ -135,19 +137,19 @@ Cname: } } if len(addrs) == 0 { - return nil, &DNSError{Error: noSuchHost, Name: name, Server: server} + return "", nil, &DNSError{Error: noSuchHost, Name: name, Server: server} } - return addrs, nil + return name, addrs, nil } - return nil, &DNSError{Error: "too many redirects", Name: name, Server: server} + return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server} } // Do a lookup for a single name, which must be rooted // (otherwise answer will not find the answers). -func tryOneName(cfg *dnsConfig, name string, qtype uint16) (addrs []dnsRR, err os.Error) { +func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) { if len(cfg.servers) == 0 { - return nil, &DNSError{Error: "no DNS servers", Name: name} + return "", nil, &DNSError{Error: "no DNS servers", Name: name} } for i := 0; i < len(cfg.servers); i++ { // Calling Dial here is scary -- we have to be sure @@ -168,7 +170,7 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (addrs []dnsRR, err o err = merr continue } - addrs, err = answer(name, server, msg, qtype) + cname, addrs, err = answer(name, server, msg, qtype) if err == nil || err.(*DNSError).Error == noSuchHost { break } @@ -259,9 +261,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro rname += "." } // Can try as ordinary name. - addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg, rname, qtype) if err == nil { - cname = rname return } } @@ -275,9 +276,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro if rname[len(rname)-1] != '.' { rname += "." } - addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg, rname, qtype) if err == nil { - cname = rname return } } @@ -287,9 +287,8 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro if !rooted { rname += "." } - addrs, err = tryOneName(cfg, rname, qtype) + cname, addrs, err = tryOneName(cfg, rname, qtype) if err == nil { - cname = rname return } return @@ -357,9 +356,59 @@ func LookupMX(name string) (entries []*MX, err os.Error) { return } entries = make([]*MX, len(records)) - for i := 0; i < len(records); i++ { + for i := range records { r := records[i].(*dnsRR_MX) entries[i] = &MX{r.Mx, r.Pref} } return } + +// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP +// address addr suitable for rDNS (PTR) record lookup or an error if it fails +// to parse the IP address. +func reverseaddr(addr string) (arpa string, err os.Error) { + ip := ParseIP(addr) + if ip == nil { + return "", &DNSError{Error: "unrecognized address", Name: addr} + } + if ip.To4() != nil { + return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil + } + // Must be IPv6 + var buf bytes.Buffer + // Add it, in reverse, to the buffer + for i := len(ip) - 1; i >= 0; i-- { + s := fmt.Sprintf("%02x", ip[i]) + buf.WriteByte(s[1]) + buf.WriteByte('.') + buf.WriteByte(s[0]) + buf.WriteByte('.') + } + // Append "ip6.arpa." and return (buf already has the final .) + return buf.String() + "ip6.arpa.", nil +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +func LookupAddr(addr string) (name []string, err os.Error) { + name = lookupStaticAddr(addr) + if len(name) > 0 { + return + } + var arpa string + arpa, err = reverseaddr(addr) + if err != nil { + return + } + var records []dnsRR + _, records, err = lookup(arpa, dnsTypePTR) + if err != nil { + return + } + name = make([]string, len(records)) + for i := range records { + r := records[i].(*dnsRR_PTR) + name[i] = r.Ptr + } + return +} diff --git a/src/pkg/net/dnsname_test.go b/src/pkg/net/dnsname_test.go index f4089c5db..0c1a62518 100644 --- a/src/pkg/net/dnsname_test.go +++ b/src/pkg/net/dnsname_test.go @@ -27,7 +27,7 @@ var tests = []testCase{ {"a.b..com", false}, } -func getTestCases(ch chan<- *testCase) { +func getTestCases(ch chan<- testCase) { defer close(ch) var char59 = "" var char63 = "" @@ -39,17 +39,17 @@ func getTestCases(ch chan<- *testCase) { char64 = char63 + "a" for _, tc := range tests { - ch <- &tc + ch <- tc } - ch <- &testCase{char63 + ".com", true} - ch <- &testCase{char64 + ".com", false} + ch <- testCase{char63 + ".com", true} + ch <- testCase{char64 + ".com", false} // 255 char name is fine: - ch <- &testCase{char59 + "." + char63 + "." + char63 + "." + + ch <- testCase{char59 + "." + char63 + "." + char63 + "." + char63 + ".com", true} // 256 char name is bad: - ch <- &testCase{char59 + "a." + char63 + "." + char63 + "." + + ch <- testCase{char59 + "a." + char63 + "." + char63 + "." + char63 + ".com", false} } @@ -58,7 +58,7 @@ func TestDNSNames(t *testing.T) { if runtime.GOOS == "windows" { return } - ch := make(chan *testCase) + ch := make(chan testCase) go getTestCases(ch) for tc := range ch { if isDomainName(tc.name) != tc.result { diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go index 5ec91845d..2ba9296f3 100644 --- a/src/pkg/net/fd.go +++ b/src/pkg/net/fd.go @@ -220,11 +220,16 @@ func (s *pollServer) Run() { nn, _ = s.pr.Read(scratch[0:]) } // Read from channels - for fd, ok := <-s.cr; ok; fd, ok = <-s.cr { - s.AddFD(fd, 'r') - } - for fd, ok := <-s.cw; ok; fd, ok = <-s.cw { - s.AddFD(fd, 'w') + Update: + for { + select { + case fd := <-s.cr: + s.AddFD(fd, 'r') + case fd := <-s.cw: + s.AddFD(fd, 'w') + default: + break Update + } } } else { netfd := s.LookupFD(fd, mode) @@ -417,7 +422,7 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S var oserr os.Error for { var errno int - n, oobn, flags, errno = syscall.Recvmsg(fd.sysfd, p, oob, sa, 0) + n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0) if errno == syscall.EAGAIN && fd.rdeadline >= 0 { pollserver.WaitRead(fd) continue diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index 72685d612..9b91eb398 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -6,14 +6,13 @@ package net import ( "os" + "runtime" "sync" "syscall" + "time" "unsafe" - "runtime" ) -// BUG(brainman): The Windows implementation does not implement SetTimeout. - // IO completion result parameters. type ioResult struct { key uint32 @@ -79,6 +78,8 @@ type ioPacket struct { // Link to the io owner. c chan *ioResult + + w *syscall.WSABuf } func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) { @@ -126,6 +127,8 @@ func startServer() { panic("Start pollServer: " + err.String() + "\n") } pollserver = p + + go timeoutIO() } var initErr os.Error @@ -143,8 +146,8 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err sysfd: fd, family: family, proto: proto, - cr: make(chan *ioResult), - cw: make(chan *ioResult), + cr: make(chan *ioResult, 1), + cw: make(chan *ioResult, 1), net: net, laddr: laddr, raddr: raddr, @@ -199,6 +202,80 @@ func newWSABuf(p []byte) *syscall.WSABuf { return &syscall.WSABuf{uint32(len(p)), p0} } +func waitPacket(fd *netFD, pckt *ioPacket, mode int) (r *ioResult) { + var delta int64 + if mode == 'r' { + delta = fd.rdeadline_delta + } + if mode == 'w' { + delta = fd.wdeadline_delta + } + if delta <= 0 { + return <-pckt.c + } + + select { + case r = <-pckt.c: + case <-time.After(delta): + a := &arg{f: cancel, fd: fd, pckt: pckt, c: make(chan int)} + ioChan <- a + <-a.c + r = <-pckt.c + if r.errno == 995 { // IO Canceled + r.errno = syscall.EWOULDBLOCK + } + } + return r +} + +const ( + read = iota + readfrom + write + writeto + cancel +) + +type arg struct { + f int + fd *netFD + pckt *ioPacket + done *uint32 + flags *uint32 + rsa *syscall.RawSockaddrAny + size *int32 + sa *syscall.Sockaddr + c chan int +} + +var ioChan chan *arg = make(chan *arg) + +func timeoutIO() { + // CancelIO only cancels all pending input and output (I/O) operations that are + // issued by the calling thread for the specified file, does not cancel I/O + // operations that other threads issue for a file handle. So we need do all timeout + // I/O in single OS thread. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + for { + o := <-ioChan + var e int + switch o.f { + case read: + e = syscall.WSARecv(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, &o.pckt.o, nil) + case readfrom: + e = syscall.WSARecvFrom(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, o.rsa, o.size, &o.pckt.o, nil) + case write: + e = syscall.WSASend(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, uint32(0), &o.pckt.o, nil) + case writeto: + e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil) + case cancel: + _, e = syscall.CancelIo(uint32(o.fd.sysfd)) + } + o.c <- e + } +} + func (fd *netFD) Read(p []byte) (n int, err os.Error) { if fd == nil { return 0, os.EINVAL @@ -213,9 +290,17 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { // Submit receive request. var pckt ioPacket pckt.c = fd.cr + pckt.w = newWSABuf(p) var done uint32 flags := uint32(0) - e := syscall.WSARecv(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &pckt.o, nil) + var e int + if fd.rdeadline_delta > 0 { + a := &arg{f: read, fd: fd, pckt: &pckt, done: &done, flags: &flags, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSARecv(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -225,7 +310,7 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'r') if r.errno != 0 { err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -253,11 +338,19 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { // Submit receive request. var pckt ioPacket pckt.c = fd.cr + pckt.w = newWSABuf(p) var done uint32 flags := uint32(0) var rsa syscall.RawSockaddrAny l := int32(unsafe.Sizeof(rsa)) - e := syscall.WSARecvFrom(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &rsa, &l, &pckt.o, nil) + var e int + if fd.rdeadline_delta > 0 { + a := &arg{f: readfrom, fd: fd, pckt: &pckt, done: &done, flags: &flags, rsa: &rsa, size: &l, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSARecvFrom(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &rsa, &l, &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -267,7 +360,7 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { return 0, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'r') if r.errno != 0 { err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -290,8 +383,16 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { // Submit send request. var pckt ioPacket pckt.c = fd.cw + pckt.w = newWSABuf(p) var done uint32 - e := syscall.WSASend(uint32(fd.sysfd), newWSABuf(p), 1, &done, uint32(0), &pckt.o, nil) + var e int + if fd.wdeadline_delta > 0 { + a := &arg{f: write, fd: fd, pckt: &pckt, done: &done, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSASend(uint32(fd.sysfd), pckt.w, 1, &done, uint32(0), &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -301,7 +402,7 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'w') if r.errno != 0 { err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -326,8 +427,16 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { // Submit send request. var pckt ioPacket pckt.c = fd.cw + pckt.w = newWSABuf(p) var done uint32 - e := syscall.WSASendto(uint32(fd.sysfd), newWSABuf(p), 1, &done, 0, sa, &pckt.o, nil) + var e int + if fd.wdeadline_delta > 0 { + a := &arg{f: writeto, fd: fd, pckt: &pckt, done: &done, sa: &sa, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSASendto(uint32(fd.sysfd), pckt.w, 1, &done, 0, sa, &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -337,7 +446,7 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { return 0, &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'w') if r.errno != 0 { err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -410,8 +519,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. sysfd: s, family: fd.family, proto: fd.proto, - cr: make(chan *ioResult), - cw: make(chan *ioResult), + cr: make(chan *ioResult, 1), + cw: make(chan *ioResult, 1), net: fd.net, laddr: laddr, raddr: raddr, diff --git a/src/pkg/net/hosts.go b/src/pkg/net/hosts.go index 556d57f11..8525f578d 100644 --- a/src/pkg/net/hosts.go +++ b/src/pkg/net/hosts.go @@ -19,16 +19,18 @@ var hostsPath = "/etc/hosts" // Simple cache. var hosts struct { sync.Mutex - data map[string][]string - time int64 - path string + byName map[string][]string + byAddr map[string][]string + time int64 + path string } func readHosts() { now, _, _ := os.Time() hp := hostsPath - if len(hosts.data) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp { + if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp { hs := make(map[string][]string) + is := make(map[string][]string) var file *file if file, _ = open(hp); file == nil { return @@ -45,12 +47,14 @@ func readHosts() { for i := 1; i < len(f); i++ { h := f[i] hs[h] = append(hs[h], f[0]) + is[f[0]] = append(is[f[0]], h) } } // Update the data cache. hosts.time, _, _ = os.Time() hosts.path = hp - hosts.data = hs + hosts.byName = hs + hosts.byAddr = is file.close() } } @@ -60,10 +64,23 @@ func lookupStaticHost(host string) []string { hosts.Lock() defer hosts.Unlock() readHosts() - if len(hosts.data) != 0 { - if ips, ok := hosts.data[host]; ok { + if len(hosts.byName) != 0 { + if ips, ok := hosts.byName[host]; ok { return ips } } return nil } + +// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts. +func lookupStaticAddr(addr string) []string { + hosts.Lock() + defer hosts.Unlock() + readHosts() + if len(hosts.byAddr) != 0 { + if hosts, ok := hosts.byAddr[addr]; ok { + return hosts + } + } + return nil +} diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go index b303254c6..1e6e99eec 100644 --- a/src/pkg/net/net_test.go +++ b/src/pkg/net/net_test.go @@ -7,6 +7,7 @@ package net import ( "flag" "regexp" + "runtime" "testing" ) @@ -52,6 +53,14 @@ var dialErrorTests = []DialErrorTest{ "unix", "", "/etc/", "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)", }, + { + "unixpacket", "", "/etc/file-not-found", + "dial unixpacket /etc/file-not-found: no such file or directory", + }, + { + "unixpacket", "", "/etc/", + "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", + }, } func TestDialError(t *testing.T) { @@ -75,3 +84,43 @@ func TestDialError(t *testing.T) { } } } + +var revAddrTests = []struct { + Addr string + Reverse string + ErrPrefix string +}{ + {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, + {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, + {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, + {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, + {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, + {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1.2.3", "", "unrecognized address"}, + {"1.2.3.4.5", "", "unrecognized address"}, + {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, + {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, +} + +func TestReverseAddress(t *testing.T) { + if runtime.GOOS == "windows" { + return + } + for i, tt := range revAddrTests { + a, e := reverseaddr(tt.Addr) + if len(tt.ErrPrefix) > 0 && e == nil { + t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) + continue + } + if len(tt.ErrPrefix) == 0 && e != nil { + t.Errorf("#%d: expected <nil>, got %q (error)", i, e) + } + if e != nil && e.(*DNSError).Error != tt.ErrPrefix { + t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error) + } + if a != tt.Reverse { + t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) + } + } +} diff --git a/src/pkg/net/port.go b/src/pkg/net/port.go index cd18d2b42..7d25058b2 100644 --- a/src/pkg/net/port.go +++ b/src/pkg/net/port.go @@ -18,7 +18,9 @@ var onceReadServices sync.Once func readServices() { services = make(map[string]map[string]int) var file *file - file, servicesError = open("/etc/services") + if file, servicesError = open("/etc/services"); servicesError != nil { + return + } for line, ok := file.readLine(); ok; line, ok = file.readLine() { // "http 80/tcp www www-http # World Wide Web HTTP" if i := byteIndex(line, '#'); i >= 0 { diff --git a/src/pkg/net/resolv_windows.go b/src/pkg/net/resolv_windows.go index d5292b8be..f3d854ff2 100644 --- a/src/pkg/net/resolv_windows.go +++ b/src/pkg/net/resolv_windows.go @@ -78,6 +78,35 @@ func LookupPort(network, service string) (port int, err os.Error) { return int(syscall.Ntohs(s.Port)), nil } +// TODO(brainman): Following code is only to get tests running. + func isDomainName(s string) bool { panic("unimplemented") } + +func reverseaddr(addr string) (arpa string, err os.Error) { + panic("unimplemented") +} + +// DNSError represents a DNS lookup error. +type DNSError struct { + Error string // description of the error + Name string // name looked for + Server string // server used + IsTimeout bool +} + +func (e *DNSError) String() string { + if e == nil { + return "<nil>" + } + s := "lookup " + e.Name + if e.Server != "" { + s += " on " + e.Server + } + s += ": " + e.Error + return s +} + +func (e *DNSError) Timeout() bool { return e.IsTimeout } +func (e *DNSError) Temporary() bool { return e.IsTimeout } diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go index 46bedaa5b..3dda500e5 100644 --- a/src/pkg/net/server_test.go +++ b/src/pkg/net/server_test.go @@ -25,7 +25,7 @@ func runEcho(fd io.ReadWriter, done chan<- int) { for { n, err := fd.Read(buf[0:]) - if err != nil || n == 0 { + if err != nil || n == 0 || string(buf[:n]) == "END" { break } fd.Write(buf[0:n]) @@ -79,6 +79,13 @@ func connect(t *testing.T, network, addr string, isEmpty bool) { if n != len(b) || err1 != nil { t.Fatalf("fd.Read() = %d, %v (want %d, nil)", n, err1, len(b)) } + + // Send explicit ending for unixpacket. + // Older Linux kernels do stop reads on close. + if network == "unixpacket" { + fd.Write([]byte("END")) + } + fd.Close() } @@ -117,8 +124,11 @@ func TestUnixServer(t *testing.T) { doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net") os.Remove("/tmp/gotest.net") if syscall.OS == "linux" { + doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net") + os.Remove("/tmp/gotest.net") // Test abstract unix domain socket, a Linux-ism doTest(t, "unix", "@gotest/net", "@gotest/net") + doTest(t, "unixpacket", "@gotest/net", "@gotest/net") } } @@ -130,13 +140,16 @@ func runPacket(t *testing.T, network, addr string, listening chan<- string, done listening <- c.LocalAddr().String() c.SetReadTimeout(10e6) // 10ms var buf [1000]byte +Run: for { n, addr, err := c.ReadFrom(buf[0:]) if e, ok := err.(Error); ok && e.Timeout() { - if done <- 1 { - break + select { + case done <- 1: + break Run + default: + continue Run } - continue } if err != nil { break diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go index 092781685..09a257dc8 100644 --- a/src/pkg/net/timeout_test.go +++ b/src/pkg/net/timeout_test.go @@ -8,14 +8,9 @@ import ( "os" "testing" "time" - "runtime" ) func testTimeout(t *testing.T, network, addr string, readFrom bool) { - // Timeouts are not implemented on windows. - if runtime.GOOS == "windows" { - return - } fd, err := Dial(network, "", addr) if err != nil { t.Errorf("dial %s %s failed: %v", network, addr, err) @@ -51,8 +46,12 @@ func TestTimeoutUDP(t *testing.T) { } func TestTimeoutTCP(t *testing.T) { - // 74.125.19.99 is www.google.com. - // could use dns, but dns depends on - // timeouts and this is the timeout test. - testTimeout(t, "tcp", "74.125.19.99:80", false) + // set up a listener that won't talk back + listening := make(chan string) + done := make(chan int) + go runServe(t, "tcp", "127.0.0.1:0", listening, done) + addr := <-listening + + testTimeout(t, "tcp", addr, false) + <-done } diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go index 2521969eb..8c26a7baf 100644 --- a/src/pkg/net/unixsock.go +++ b/src/pkg/net/unixsock.go @@ -20,6 +20,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err proto = syscall.SOCK_STREAM case "unixgram": proto = syscall.SOCK_DGRAM + case "unixpacket": + proto = syscall.SOCK_SEQPACKET } var la, ra syscall.Sockaddr @@ -48,9 +50,12 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err } f := sockaddrToUnix - if proto != syscall.SOCK_STREAM { + if proto == syscall.SOCK_DGRAM { f = sockaddrToUnixgram + } else if proto == syscall.SOCK_SEQPACKET { + f = sockaddrToUnixpacket } + fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f) if oserr != nil { goto Error @@ -67,30 +72,48 @@ Error: // UnixAddr represents the address of a Unix domain socket end point. type UnixAddr struct { - Name string - Datagram bool + Name string + Net string } func sockaddrToUnix(sa syscall.Sockaddr) Addr { if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &UnixAddr{s.Name, false} + return &UnixAddr{s.Name, "unix"} } return nil } func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &UnixAddr{s.Name, true} + return &UnixAddr{s.Name, "unixgram"} } return nil } -// Network returns the address's network name, "unix" or "unixgram". -func (a *UnixAddr) Network() string { - if a == nil || !a.Datagram { +func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { + if s, ok := sa.(*syscall.SockaddrUnix); ok { + return &UnixAddr{s.Name, "unixpacket"} + } + return nil +} + +func protoToNet(proto int) string { + switch proto { + case syscall.SOCK_STREAM: return "unix" + case syscall.SOCK_SEQPACKET: + return "unixpacket" + case syscall.SOCK_DGRAM: + return "unixgram" + default: + panic("protoToNet unknown protocol") } - return "unixgram" + return "" +} + +// Network returns the address's network name, "unix" or "unixgram". +func (a *UnixAddr) Network() string { + return a.Net } func (a *UnixAddr) String() string { @@ -108,17 +131,17 @@ func (a *UnixAddr) toAddr() Addr { } // ResolveUnixAddr parses addr as a Unix domain socket address. -// The string net gives the network name, "unix" or "unixgram". +// The string net gives the network name, "unix", "unixgram" or +// "unixpacket". func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) { - var datagram bool switch net { case "unix": + case "unixpacket": case "unixgram": - datagram = true default: return nil, UnknownNetworkError(net) } - return &UnixAddr{addr, datagram}, nil + return &UnixAddr{addr, net}, nil } // UnixConn is an implementation of the Conn interface @@ -234,7 +257,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) n, sa, err := c.fd.ReadFrom(b) switch sa := sa.(type) { case *syscall.SockaddrUnix: - addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM} + addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} } return } @@ -258,7 +281,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) { if !c.ok() { return 0, os.EINVAL } - if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) { + if addr.Net != protoToNet(c.fd.proto) { return 0, os.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} @@ -284,7 +307,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrUnix: - addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM} + addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} } return } @@ -294,7 +317,7 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err return 0, 0, os.EINVAL } if addr != nil { - if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) { + if addr.Net != protoToNet(c.fd.proto) { return 0, 0, os.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} @@ -330,11 +353,11 @@ type UnixListener struct { // ListenUnix announces on the Unix domain socket laddr and returns a Unix listener. // Net must be "unix" (stream sockets). func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) { - if net != "unix" && net != "unixgram" { + if net != "unix" && net != "unixgram" && net != "unixpacket" { return nil, UnknownNetworkError(net) } if laddr != nil { - laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy + laddr = &UnixAddr{laddr.Name, net} // make our own copy } fd, err := unixSocket(net, laddr, nil, "listen") if err != nil { diff --git a/src/pkg/netchan/common.go b/src/pkg/netchan/common.go index bde3087a5..6c085484e 100644 --- a/src/pkg/netchan/common.go +++ b/src/pkg/netchan/common.go @@ -38,21 +38,24 @@ const ( payData // user payload follows payAck // acknowledgement; no payload payClosed // channel is now closed + payAckSend // payload has been delivered. ) // A header is sent as a prefix to every transmission. It will be followed by // a request structure, an error structure, or an arbitrary user payload structure. type header struct { - Name string + Id int PayloadType int SeqNum int64 } // Sent with a header once per channel from importer to exporter to report // that it wants to bind to a channel with the specified direction for count -// messages. If count is -1, it means unlimited. +// messages, with space for size buffered values. If count is -1, it means unlimited. type request struct { + Name string Count int64 + Size int Dir Dir } @@ -78,7 +81,7 @@ type chanDir struct { // clients of an exporter and draining outstanding messages. type clientSet struct { mu sync.Mutex // protects access to channel and client maps - chans map[string]*chanDir + names map[string]*chanDir clients map[unackedCounter]bool } @@ -132,7 +135,7 @@ func (cs *clientSet) drain(timeout int64) os.Error { pending := false cs.mu.Lock() // Any messages waiting for a client? - for _, chDir := range cs.chans { + for _, chDir := range cs.names { if chDir.ch.Len() > 0 { pending = true } @@ -189,3 +192,140 @@ func (cs *clientSet) sync(timeout int64) os.Error { } return nil } + +// A netChan represents a channel imported or exported +// on a single connection. Flow is controlled by the receiving +// side by sending payAckSend messages when values +// are delivered into the local channel. +type netChan struct { + *chanDir + name string + id int + size int // buffer size of channel. + + // sender-specific state + ackCh chan bool // buffered with space for all the acks we need + space int // available space. + + // receiver-specific state + sendCh chan reflect.Value // buffered channel of values received from other end. + ed *encDec // so that we can send acks. + count int64 // number of values still to receive. +} + +// Create a new netChan with the given name (only used for +// messages), id, direction, buffer size, and count. +// The connection to the other side is represented by ed. +func newNetChan(name string, id int, ch *chanDir, ed *encDec, size int, count int64) *netChan { + c := &netChan{chanDir: ch, name: name, id: id, size: size, ed: ed, count: count} + if c.dir == Send { + c.ackCh = make(chan bool, size) + c.space = size + } + return c +} + +// Close the channel. +func (nch *netChan) close() { + if nch.dir == Recv { + if nch.sendCh != nil { + // If the sender goroutine is active, close the channel to it. + // It will close nch.ch when it can. + close(nch.sendCh) + } else { + nch.ch.Close() + } + } else { + nch.ch.Close() + close(nch.ackCh) + } +} + +// Send message from remote side to local receiver. +func (nch *netChan) send(val reflect.Value) { + if nch.dir != Recv { + panic("send on wrong direction of channel") + } + if nch.sendCh == nil { + // If possible, do local send directly and ack immediately. + if nch.ch.TrySend(val) { + nch.sendAck() + return + } + // Start sender goroutine to manage delayed delivery of values. + nch.sendCh = make(chan reflect.Value, nch.size) + go nch.sender() + } + select { + case nch.sendCh <- val: + // ok + default: + // TODO: should this be more resilient? + panic("netchan: remote sender sent more values than allowed") + } +} + +// sendAck sends an acknowledgment that a message has left +// the channel's buffer. If the messages remaining to be sent +// will fit in the channel's buffer, then we don't +// need to send an ack. +func (nch *netChan) sendAck() { + if nch.count < 0 || nch.count > int64(nch.size) { + nch.ed.encode(&header{Id: nch.id}, payAckSend, nil) + } + if nch.count > 0 { + nch.count-- + } +} + +// The sender process forwards items from the sending queue +// to the destination channel, acknowledging each item. +func (nch *netChan) sender() { + if nch.dir != Recv { + panic("sender on wrong direction of channel") + } + // When Exporter.Hangup is called, the underlying channel is closed, + // and so we may get a "too many operations on closed channel" error + // if there are outstanding messages in sendCh. + // Make sure that this doesn't panic the whole program. + defer func() { + if r := recover(); r != nil { + // TODO check that r is "too many operations", otherwise re-panic. + } + }() + for v := range nch.sendCh { + nch.ch.Send(v) + nch.sendAck() + } + nch.ch.Close() +} + +// Receive value from local side for sending to remote side. +func (nch *netChan) recv() (val reflect.Value, closed bool) { + if nch.dir != Send { + panic("recv on wrong direction of channel") + } + + if nch.space == 0 { + // Wait for buffer space. + <-nch.ackCh + nch.space++ + } + nch.space-- + return nch.ch.Recv(), nch.ch.Closed() +} + +// acked is called when the remote side indicates that +// a value has been delivered. +func (nch *netChan) acked() { + if nch.dir != Send { + panic("recv on wrong direction of channel") + } + select { + case nch.ackCh <- true: + // ok + default: + // TODO: should this be more resilient? + panic("netchan: remote receiver sent too many acks") + } +} diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go index 9ad388c18..0b28536ed 100644 --- a/src/pkg/netchan/export.go +++ b/src/pkg/netchan/export.go @@ -26,6 +26,7 @@ import ( "net" "os" "reflect" + "strconv" "sync" ) @@ -48,11 +49,12 @@ type Exporter struct { type expClient struct { *encDec exp *Exporter - mu sync.Mutex // protects remaining fields - errored bool // client has been sent an error - seqNum int64 // sequences messages sent to client; has value of highest sent - ackNum int64 // highest sequence number acknowledged - seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu + chans map[int]*netChan // channels in use by client + mu sync.Mutex // protects remaining fields + errored bool // client has been sent an error + seqNum int64 // sequences messages sent to client; has value of highest sent + ackNum int64 // highest sequence number acknowledged + seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu } func newClient(exp *Exporter, conn net.Conn) *expClient { @@ -61,8 +63,8 @@ func newClient(exp *Exporter, conn net.Conn) *expClient { client.encDec = newEncDec(conn) client.seqNum = 0 client.ackNum = 0 + client.chans = make(map[int]*netChan) return client - } func (client *expClient) sendError(hdr *header, err string) { @@ -74,20 +76,33 @@ func (client *expClient) sendError(hdr *header, err string) { client.mu.Unlock() } -func (client *expClient) getChan(hdr *header, dir Dir) *chanDir { +func (client *expClient) newChan(hdr *header, dir Dir, name string, size int, count int64) *netChan { exp := client.exp exp.mu.Lock() - ech, ok := exp.chans[hdr.Name] + ech, ok := exp.names[name] exp.mu.Unlock() if !ok { - client.sendError(hdr, "no such channel: "+hdr.Name) + client.sendError(hdr, "no such channel: "+name) return nil } if ech.dir != dir { - client.sendError(hdr, "wrong direction for channel: "+hdr.Name) + client.sendError(hdr, "wrong direction for channel: "+name) + return nil + } + nch := newNetChan(name, hdr.Id, ech, client.encDec, size, count) + client.chans[hdr.Id] = nch + return nch +} + +func (client *expClient) getChan(hdr *header, dir Dir) *netChan { + nch := client.chans[hdr.Id] + if nch == nil { return nil } - return ech + if nch.dir != dir { + client.sendError(hdr, "wrong direction for channel: "+nch.name) + } + return nch } // The function run manages sends and receives for a single client. For each @@ -113,12 +128,18 @@ func (client *expClient) run() { expLog("error decoding client request:", err) break } + if req.Size < 1 { + panic("netchan: remote requested " + strconv.Itoa(req.Size) + " values") + } switch req.Dir { case Recv: - go client.serveRecv(*hdr, req.Count) + // look up channel before calling serveRecv to + // avoid a lock around client.chans. + if nch := client.newChan(hdr, Send, req.Name, req.Size, req.Count); nch != nil { + go client.serveRecv(nch, *hdr, req.Count) + } case Send: - // Request to send is clear as a matter of protocol - // but not actually used by the implementation. + client.newChan(hdr, Recv, req.Name, req.Size, req.Count) // The actual sends will have payload type payData. // TODO: manage the count? default: @@ -143,8 +164,12 @@ func (client *expClient) run() { client.ackNum = hdr.SeqNum } client.mu.Unlock() + case payAckSend: + if nch := client.getChan(hdr, Send); nch != nil { + nch.acked() + } default: - log.Exit("netchan export: unknown payload type", hdr.PayloadType) + log.Fatal("netchan export: unknown payload type", hdr.PayloadType) } } client.exp.delClient(client) @@ -152,14 +177,10 @@ func (client *expClient) run() { // Send all the data on a single channel to a client asking for a Recv. // The header is passed by value to avoid issues of overwriting. -func (client *expClient) serveRecv(hdr header, count int64) { - ech := client.getChan(&hdr, Send) - if ech == nil { - return - } +func (client *expClient) serveRecv(nch *netChan, hdr header, count int64) { for { - val := ech.ch.Recv() - if ech.ch.Closed() { + val, closed := nch.recv() + if closed { if err := client.encode(&hdr, payClosed, nil); err != nil { expLog("error encoding server closed message:", err) } @@ -167,7 +188,7 @@ func (client *expClient) serveRecv(hdr header, count int64) { } // We hold the lock during transmission to guarantee messages are // sent in sequence number order. Also, we increment first so the - // value of client.seqNum is the value of the highest used sequence + // value of client.SeqNum is the value of the highest used sequence // number, not one beyond. client.mu.Lock() client.seqNum++ @@ -193,27 +214,27 @@ func (client *expClient) serveRecv(hdr header, count int64) { // Receive and deliver locally one item from a client asking for a Send // The header is passed by value to avoid issues of overwriting. func (client *expClient) serveSend(hdr header) { - ech := client.getChan(&hdr, Recv) - if ech == nil { + nch := client.getChan(&hdr, Recv) + if nch == nil { return } // Create a new value for each received item. - val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem()) + val := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem()) if err := client.decode(val); err != nil { - expLog("value decode:", err) + expLog("value decode:", err, "; type ", nch.ch.Type()) return } - ech.ch.Send(val) + nch.send(val) } // Report that client has closed the channel that is sending to us. // The header is passed by value to avoid issues of overwriting. func (client *expClient) serveClosed(hdr header) { - ech := client.getChan(&hdr, Recv) - if ech == nil { + nch := client.getChan(&hdr, Recv) + if nch == nil { return } - ech.ch.Close() + nch.close() } func (client *expClient) unackedCount() int64 { @@ -260,7 +281,7 @@ func NewExporter(network, localaddr string) (*Exporter, os.Error) { e := &Exporter{ listener: listener, clientSet: &clientSet{ - chans: make(map[string]*chanDir), + names: make(map[string]*chanDir), clients: make(map[unackedCounter]bool), }, } @@ -343,11 +364,11 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error { } exp.mu.Lock() defer exp.mu.Unlock() - _, present := exp.chans[name] + _, present := exp.names[name] if present { return os.ErrorString("channel name already being exported:" + name) } - exp.chans[name] = &chanDir{ch, dir} + exp.names[name] = &chanDir{ch, dir} return nil } @@ -355,10 +376,11 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error { // the channel. Messages in flight for the channel may be dropped. func (exp *Exporter) Hangup(name string) os.Error { exp.mu.Lock() - chDir, ok := exp.chans[name] + chDir, ok := exp.names[name] if ok { - exp.chans[name] = nil, false + exp.names[name] = nil, false } + // TODO drop all instances of channel from client sets exp.mu.Unlock() if !ok { return os.ErrorString("netchan export: hangup: no such channel: " + name) diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go index baae367a0..d220d9a66 100644 --- a/src/pkg/netchan/import.go +++ b/src/pkg/netchan/import.go @@ -27,8 +27,10 @@ type Importer struct { *encDec conn net.Conn chanLock sync.Mutex // protects access to channel map - chans map[string]*chanDir + names map[string]*netChan + chans map[int]*netChan errors chan os.Error + maxId int } // NewImporter creates a new Importer object to import channels @@ -43,7 +45,8 @@ func NewImporter(network, remoteaddr string) (*Importer, os.Error) { imp := new(Importer) imp.encDec = newEncDec(conn) imp.conn = conn - imp.chans = make(map[string]*chanDir) + imp.chans = make(map[int]*netChan) + imp.names = make(map[string]*netChan) imp.errors = make(chan os.Error, 10) go imp.run() return imp, nil @@ -54,7 +57,7 @@ func (imp *Importer) shutdown() { imp.chanLock.Lock() for _, ich := range imp.chans { if ich.dir == Recv { - ich.ch.Close() + ich.close() } } imp.chanLock.Unlock() @@ -88,50 +91,62 @@ func (imp *Importer) run() { } if err.Error != "" { impLog("response error:", err.Error) - if sent := imp.errors <- os.ErrorString(err.Error); !sent { + select { + case imp.errors <- os.ErrorString(err.Error): + continue // errors are not acknowledged + default: imp.shutdown() return } - continue // errors are not acknowledged. } case payClosed: - ich := imp.getChan(hdr.Name) - if ich != nil { - ich.ch.Close() + nch := imp.getChan(hdr.Id, false) + if nch != nil { + nch.close() } continue // closes are not acknowledged. + case payAckSend: + // we can receive spurious acks if the channel is + // hung up, so we ask getChan to ignore any errors. + nch := imp.getChan(hdr.Id, true) + if nch != nil { + nch.acked() + } + continue default: impLog("unexpected payload type:", hdr.PayloadType) return } - ich := imp.getChan(hdr.Name) - if ich == nil { + nch := imp.getChan(hdr.Id, false) + if nch == nil { continue } - if ich.dir != Recv { + if nch.dir != Recv { impLog("cannot happen: receive from non-Recv channel") return } // Acknowledge receipt - ackHdr.Name = hdr.Name + ackHdr.Id = hdr.Id ackHdr.SeqNum = hdr.SeqNum imp.encode(ackHdr, payAck, nil) // Create a new value for each received item. - value := reflect.MakeZero(ich.ch.Type().(*reflect.ChanType).Elem()) + value := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem()) if e := imp.decode(value); e != nil { impLog("importer value decode:", e) return } - ich.ch.Send(value) + nch.send(value) } } -func (imp *Importer) getChan(name string) *chanDir { +func (imp *Importer) getChan(id int, errOk bool) *netChan { imp.chanLock.Lock() - ich := imp.chans[name] + ich := imp.chans[id] imp.chanLock.Unlock() if ich == nil { - impLog("unknown name in netchan request:", name) + if !errOk { + impLog("unknown id in netchan request: ", id) + } return nil } return ich @@ -145,41 +160,49 @@ func (imp *Importer) Errors() chan os.Error { return imp.errors } -// Import imports a channel of the given type and specified direction. +// Import imports a channel of the given type, size and specified direction. // It is equivalent to ImportNValues with a count of -1, meaning unbounded. -func (imp *Importer) Import(name string, chT interface{}, dir Dir) os.Error { - return imp.ImportNValues(name, chT, dir, -1) +func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error { + return imp.ImportNValues(name, chT, dir, size, -1) } -// ImportNValues imports a channel of the given type and specified direction -// and then receives or transmits up to n values on that channel. A value of -// n==-1 implies an unbounded number of values. The channel to be bound to -// the remote site's channel is provided in the call and may be of arbitrary -// channel type. +// ImportNValues imports a channel of the given type and specified +// direction and then receives or transmits up to n values on that +// channel. A value of n==-1 implies an unbounded number of values. The +// channel will have buffer space for size values, or 1 value if size < 1. +// The channel to be bound to the remote site's channel is provided +// in the call and may be of arbitrary channel type. // Despite the literal signature, the effective signature is -// ImportNValues(name string, chT chan T, dir Dir, n int) os.Error +// ImportNValues(name string, chT chan T, dir Dir, size, n int) os.Error // Example usage: // imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234") -// if err != nil { log.Exit(err) } +// if err != nil { log.Fatal(err) } // ch := make(chan myType) -// err = imp.ImportNValues("name", ch, Recv, 1) -// if err != nil { log.Exit(err) } +// err = imp.ImportNValues("name", ch, Recv, 1, 1) +// if err != nil { log.Fatal(err) } // fmt.Printf("%+v\n", <-ch) -func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int) os.Error { +func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error { ch, err := checkChan(chT, dir) if err != nil { return err } imp.chanLock.Lock() defer imp.chanLock.Unlock() - _, present := imp.chans[name] + _, present := imp.names[name] if present { return os.ErrorString("channel name already being imported:" + name) } - imp.chans[name] = &chanDir{ch, dir} + if size < 1 { + size = 1 + } + id := imp.maxId + imp.maxId++ + nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n)) + imp.names[name] = nch + imp.chans[id] = nch // Tell the other side about this channel. - hdr := &header{Name: name} - req := &request{Count: int64(n), Dir: dir} + hdr := &header{Id: id} + req := &request{Name: name, Count: int64(n), Dir: dir, Size: size} if err = imp.encode(hdr, payRequest, req); err != nil { impLog("request encode:", err) return err @@ -187,8 +210,8 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int) if dir == Send { go func() { for i := 0; n == -1 || i < n; i++ { - val := ch.Recv() - if ch.Closed() { + val, closed := nch.recv() + if closed { if err = imp.encode(hdr, payClosed, nil); err != nil { impLog("error encoding client closed message:", err) } @@ -208,14 +231,15 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int) // the channel. Messages in flight for the channel may be dropped. func (imp *Importer) Hangup(name string) os.Error { imp.chanLock.Lock() - chDir, ok := imp.chans[name] + nc, ok := imp.names[name] if ok { - imp.chans[name] = nil, false + imp.names[name] = nil, false + imp.chans[nc.id] = nil, false } imp.chanLock.Unlock() if !ok { return os.ErrorString("netchan import: hangup: no such channel: " + name) } - chDir.ch.Close() + nc.close() return nil } diff --git a/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go index 766c4c474..4076aefeb 100644 --- a/src/pkg/netchan/netchan_test.go +++ b/src/pkg/netchan/netchan_test.go @@ -15,7 +15,7 @@ const closeCount = 5 // number of items when sender closes early const base = 23 -func exportSend(exp *Exporter, n int, t *testing.T) { +func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) { ch := make(chan int) err := exp.Export("exportedSend", ch, Send) if err != nil { @@ -23,9 +23,12 @@ func exportSend(exp *Exporter, n int, t *testing.T) { } go func() { for i := 0; i < n; i++ { - ch <- base+i + ch <- base + i } close(ch) + if done != nil { + done <- true + } }() } @@ -50,23 +53,26 @@ func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) { } } -func importSend(imp *Importer, n int, t *testing.T) { +func importSend(imp *Importer, n int, t *testing.T, done chan bool) { ch := make(chan int) - err := imp.ImportNValues("exportedRecv", ch, Send, count) + err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1) if err != nil { t.Fatal("importSend:", err) } go func() { for i := 0; i < n; i++ { - ch <- base+i + ch <- base + i } close(ch) + if done != nil { + done <- true + } }() } func importReceive(imp *Importer, t *testing.T, done chan bool) { ch := make(chan int) - err := imp.ImportNValues("exportedSend", ch, Recv, count) + err := imp.ImportNValues("exportedSend", ch, Recv, 3, count) if err != nil { t.Fatal("importReceive:", err) } @@ -78,7 +84,7 @@ func importReceive(imp *Importer, t *testing.T, done chan bool) { } break } - if v != 23+i { + if v != base+i { t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v) } } @@ -96,7 +102,7 @@ func TestExportSendImportReceive(t *testing.T) { if err != nil { t.Fatal("new importer:", err) } - exportSend(exp, count, t) + exportSend(exp, count, t, nil) importReceive(imp, t, nil) } @@ -116,7 +122,7 @@ func TestExportReceiveImportSend(t *testing.T) { done <- true }() <-expDone - importSend(imp, count, t) + importSend(imp, count, t, nil) <-done } @@ -129,7 +135,7 @@ func TestClosingExportSendImportReceive(t *testing.T) { if err != nil { t.Fatal("new importer:", err) } - exportSend(exp, closeCount, t) + exportSend(exp, closeCount, t, nil) importReceive(imp, t, nil) } @@ -149,7 +155,7 @@ func TestClosingImportSendExportReceive(t *testing.T) { done <- true }() <-expDone - importSend(imp, closeCount, t) + importSend(imp, closeCount, t, nil) <-done } @@ -172,7 +178,7 @@ func TestErrorForIllegalChannel(t *testing.T) { close(ch) // Now try to import a different channel. ch = make(chan int) - err = imp.Import("notAChannel", ch, Recv) + err = imp.Import("notAChannel", ch, Recv, 1) if err != nil { t.Fatal("import:", err) } @@ -204,7 +210,7 @@ func TestExportDrain(t *testing.T) { } done := make(chan bool) go func() { - exportSend(exp, closeCount, t) + exportSend(exp, closeCount, t, nil) done <- true }() <-done @@ -224,7 +230,7 @@ func TestExportSync(t *testing.T) { t.Fatal("new importer:", err) } done := make(chan bool) - exportSend(exp, closeCount, t) + exportSend(exp, closeCount, t, nil) go importReceive(imp, t, done) exp.Sync(0) <-done @@ -248,7 +254,7 @@ func TestExportHangup(t *testing.T) { } // Prepare to receive two values. We'll actually deliver only one. ich := make(chan int) - err = imp.ImportNValues("exportedSend", ich, Recv, 2) + err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2) if err != nil { t.Fatal("import exportedSend:", err) } @@ -285,7 +291,7 @@ func TestImportHangup(t *testing.T) { } // Prepare to Send two values. We'll actually deliver only one. ich := make(chan int) - err = imp.ImportNValues("exportedRecv", ich, Send, 2) + err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2) if err != nil { t.Fatal("import exportedRecv:", err) } @@ -304,10 +310,70 @@ func TestImportHangup(t *testing.T) { } } +// loop back exportedRecv to exportedSend, +// but receive a value from ctlch before starting the loop. +func exportLoopback(exp *Exporter, t *testing.T) { + inch := make(chan int) + if err := exp.Export("exportedRecv", inch, Recv); err != nil { + t.Fatal("exportRecv") + } + + outch := make(chan int) + if err := exp.Export("exportedSend", outch, Send); err != nil { + t.Fatal("exportSend") + } + + ctlch := make(chan int) + if err := exp.Export("exportedCtl", ctlch, Recv); err != nil { + t.Fatal("exportRecv") + } + + go func() { + <-ctlch + for i := 0; i < count; i++ { + x := <-inch + if x != base+i { + t.Errorf("exportLoopback expected %d; got %d", i, x) + } + outch <- x + } + }() +} + +// This test checks that channel operations can proceed +// even when other concurrent operations are blocked. +func TestIndependentSends(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + + exportLoopback(exp, t) + + importSend(imp, count, t, nil) + done := make(chan bool) + go importReceive(imp, t, done) + + // wait for export side to try to deliver some values. + time.Sleep(0.25e9) + + ctlch := make(chan int) + if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil { + t.Fatal("importSend:", err) + } + ctlch <- 0 + + <-done +} + // This test cross-connects a pair of exporter/importer pairs. type value struct { - i int - source string + I int + Source string } func TestCrossConnect(t *testing.T) { @@ -329,7 +395,7 @@ func TestCrossConnect(t *testing.T) { t.Fatal("new importer:", err) } - go crossExport(e1, e2, t) + crossExport(e1, e2, t) crossImport(i1, i2, t) } @@ -347,19 +413,19 @@ func crossExport(e1, e2 *Exporter, t *testing.T) { t.Fatal("exportReceive:", err) } - crossLoop("export", s, r, t) + go crossLoop("export", s, r, t) } // Import side of cross-traffic. func crossImport(i1, i2 *Importer, t *testing.T) { s := make(chan value) - err := i2.Import("exportedReceive", s, Send) + err := i2.Import("exportedReceive", s, Send, 2) if err != nil { t.Fatal("import of exportedReceive:", err) } r := make(chan value) - err = i1.Import("exportedSend", r, Recv) + err = i1.Import("exportedSend", r, Recv, 2) if err != nil { t.Fatal("import of exported Send:", err) } @@ -374,10 +440,76 @@ func crossLoop(name string, s, r chan value, t *testing.T) { case s <- value{si, name}: si++ case v := <-r: - if v.i != ri { + if v.I != ri { t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v) } ri++ } } } + +const flowCount = 100 + +// test flow control from exporter to importer. +func TestExportFlowControl(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + + sendDone := make(chan bool, 1) + exportSend(exp, flowCount, t, sendDone) + + ch := make(chan int) + err = imp.ImportNValues("exportedSend", ch, Recv, 20, -1) + if err != nil { + t.Fatal("importReceive:", err) + } + + testFlow(sendDone, ch, flowCount, t) +} + +// test flow control from importer to exporter. +func TestImportFlowControl(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + + ch := make(chan int) + err = exp.Export("exportedRecv", ch, Recv) + if err != nil { + t.Fatal("importReceive:", err) + } + + sendDone := make(chan bool, 1) + importSend(imp, flowCount, t, sendDone) + testFlow(sendDone, ch, flowCount, t) +} + +func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) { + go func() { + time.Sleep(1e9) + sendDone <- false + }() + + if <-sendDone { + t.Fatal("send did not block") + } + n := 0 + for i := range ch { + t.Log("after blocking, got value ", i) + n++ + } + if n != N { + t.Fatalf("expected %d values; got %d", N, n) + } +} diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go index 8cdf53254..4738d1a42 100644 --- a/src/pkg/os/error.go +++ b/src/pkg/os/error.go @@ -37,7 +37,7 @@ func (e Errno) Temporary() bool { } func (e Errno) Timeout() bool { - return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) + return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT) } // Commonly known Unix errors. @@ -79,6 +79,7 @@ var ( ECONNREFUSED Error = Errno(syscall.ECONNREFUSED) ENAMETOOLONG Error = Errno(syscall.ENAMETOOLONG) EAFNOSUPPORT Error = Errno(syscall.EAFNOSUPPORT) + ETIMEDOUT Error = Errno(syscall.ETIMEDOUT) ) // PathError records an error and the operation and file path that caused it. diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go index 501ebc270..100d984d1 100644 --- a/src/pkg/os/exec.go +++ b/src/pkg/os/exec.go @@ -67,10 +67,10 @@ type Waitmsg struct { // Options for Wait. const ( - WNOHANG = syscall.WNOHANG // Don't wait if no process has exited. - WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported. - WUNTRACED = WSTOPPED - WRUSAGE = 1 << 20 // Record resource usage. + WNOHANG = syscall.WNOHANG // Don't wait if no process has exited. + WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported. + WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED. + WRUSAGE = 1 << 20 // Record resource usage. ) // WRUSAGE must not be too high a bit, to avoid clashing with Linux's diff --git a/src/pkg/os/inotify/inotify_linux.go b/src/pkg/os/inotify/inotify_linux.go index 1e74c7fbc..9d7a07442 100644 --- a/src/pkg/os/inotify/inotify_linux.go +++ b/src/pkg/os/inotify/inotify_linux.go @@ -153,7 +153,11 @@ func (w *Watcher) readEvents() { for { n, errno = syscall.Read(w.fd, buf[0:]) // See if there is a message on the "done" channel - _, done := <-w.done + var done bool + select { + case done = <-w.done: + default: + } // If EOF or a "done" message is received if n == 0 || done { diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go index 6b4be07a9..ab0b48ad6 100644 --- a/src/pkg/path/path_test.go +++ b/src/pkg/path/path_test.go @@ -256,8 +256,11 @@ func TestWalk(t *testing.T) { // 2) handle errors, expect none errors := make(chan os.Error, 64) Walk(tree.name, v, errors) - if err, ok := <-errors; ok { + select { + case err := <-errors: t.Errorf("no error expected, found: %s", err) + default: + // ok } checkMarks(t) @@ -276,14 +279,21 @@ func TestWalk(t *testing.T) { errors = make(chan os.Error, 64) os.Chmod(Join(tree.name, tree.entries[1].name), 0) Walk(tree.name, v, errors) + Loop: for i := 1; i <= 2; i++ { - if _, ok := <-errors; !ok { + select { + case <-errors: + // ok + default: t.Errorf("%d. error expected, none found", i) - break + break Loop } } - if err, ok := <-errors; ok { + select { + case err := <-errors: t.Errorf("only two errors expected, found 3rd: %v", err) + default: + // ok } // the inaccessible subtrees were marked manually checkMarks(t) diff --git a/src/pkg/rand/rand.go b/src/pkg/rand/rand.go index 8c1219a7a..459aed1db 100644 --- a/src/pkg/rand/rand.go +++ b/src/pkg/rand/rand.go @@ -88,9 +88,6 @@ func (r *Rand) Float64() float64 { return float64(r.Int63()) / (1 << 63) } // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). func (r *Rand) Float32() float32 { return float32(r.Float64()) } -// Float returns, as a float, a pseudo-random number in [0.0,1.0). -func (r *Rand) Float() float { return float(r.Float64()) } - // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). func (r *Rand) Perm(n int) []int { m := make([]int, n) @@ -140,9 +137,6 @@ func Float64() float64 { return globalRand.Float64() } // Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). func Float32() float32 { return globalRand.Float32() } -// Float returns, as a float, a pseudo-random number in [0.0,1.0). -func Float() float { return globalRand.Float() } - // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). func Perm(n int) []int { return globalRand.Perm(n) } diff --git a/src/pkg/rand/rand_test.go b/src/pkg/rand/rand_test.go index b9bf43208..2476ebaf6 100644 --- a/src/pkg/rand/rand_test.go +++ b/src/pkg/rand/rand_test.go @@ -131,8 +131,8 @@ func TestStandardNormalValues(t *testing.T) { } func TestNonStandardNormalValues(t *testing.T) { - for sd := float64(0.5); sd < 1000; sd *= 2 { - for m := float64(0.5); m < 1000; m *= 2 { + for sd := 0.5; sd < 1000; sd *= 2 { + for m := 0.5; m < 1000; m *= 2 { for _, seed := range testSeeds { testNormalDistribution(t, numTestSamples, m, sd, seed) } @@ -182,7 +182,7 @@ func TestStandardExponentialValues(t *testing.T) { } func TestNonStandardExponentialValues(t *testing.T) { - for rate := float64(0.05); rate < 10; rate *= 2 { + for rate := 0.05; rate < 10; rate *= 2 { for _, seed := range testSeeds { testExponentialDistribution(t, numTestSamples, rate, seed) } diff --git a/src/pkg/rand/zipf.go b/src/pkg/rand/zipf.go index c4e7b7d93..38e8ec516 100644 --- a/src/pkg/rand/zipf.go +++ b/src/pkg/rand/zipf.go @@ -55,7 +55,7 @@ func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf { // Uint64 returns a value drawn from the Zipf distributed described // by the Zipf object. func (z *Zipf) Uint64() uint64 { - k := float64(0.0) + k := 0.0 for { r := z.r.Float64() // r on [0,1] diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go index 7d34e5ca3..3675be6f1 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -48,7 +48,6 @@ var typeTests = []pair{ {struct{ x uint16 }{}, "uint16"}, {struct{ x uint32 }{}, "uint32"}, {struct{ x uint64 }{}, "uint64"}, - {struct{ x float }{}, "float"}, {struct{ x float32 }{}, "float32"}, {struct{ x float64 }{}, "float64"}, {struct{ x int8 }{}, "int8"}, @@ -244,8 +243,6 @@ func TestSet(t *testing.T) { } case *FloatValue: switch v.Type().Kind() { - case Float: - v.Set(128.5) case Float32: v.Set(256.25) case Float64: @@ -253,8 +250,6 @@ func TestSet(t *testing.T) { } case *ComplexValue: switch v.Type().Kind() { - case Complex: - v.Set(53200.0 + 100i) case Complex64: v.Set(532.125 + 10i) case Complex128: @@ -304,17 +299,13 @@ func TestSetValue(t *testing.T) { } case *FloatValue: switch v.Type().Kind() { - case Float: - v.SetValue(NewValue(float(128.5))) case Float32: v.SetValue(NewValue(float32(256.25))) case Float64: - v.SetValue(NewValue(float64(512.125))) + v.SetValue(NewValue(512.125)) } case *ComplexValue: switch v.Type().Kind() { - case Complex: - v.SetValue(NewValue(complex(53200.0 + 100i))) case Complex64: v.SetValue(NewValue(complex64(532.125 + 10i))) case Complex128: @@ -470,7 +461,7 @@ func TestInterfaceGet(t *testing.T) { assert(t, v2.Type().String(), "interface { }") i2 := v2.(*InterfaceValue).Interface() v3 := NewValue(i2) - assert(t, v3.Type().String(), "float") + assert(t, v3.Type().String(), "float64") } func TestInterfaceValue(t *testing.T) { @@ -482,11 +473,11 @@ func TestInterfaceValue(t *testing.T) { v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0) assert(t, v2.Type().String(), "interface { }") v3 := v2.(*InterfaceValue).Elem() - assert(t, v3.Type().String(), "float") + assert(t, v3.Type().String(), "float64") i3 := v2.Interface() - if _, ok := i3.(float); !ok { - t.Error("v2.Interface() did not return float, got ", Typeof(i3)) + if _, ok := i3.(float64); !ok { + t.Error("v2.Interface() did not return float64, got ", Typeof(i3)) } } @@ -697,11 +688,11 @@ type _Complex struct { a int b [3]*_Complex c *string - d map[float]float + d map[float64]float64 } func TestDeepEqualComplexStruct(t *testing.T) { - m := make(map[float]float) + m := make(map[float64]float64) stra, strb := "hello", "hello" a, b := new(_Complex), new(_Complex) *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m} @@ -712,7 +703,7 @@ func TestDeepEqualComplexStruct(t *testing.T) { } func TestDeepEqualComplexStructInequality(t *testing.T) { - m := make(map[float]float) + m := make(map[float64]float64) stra, strb := "hello", "helloo" // Difference is here a, b := new(_Complex), new(_Complex) *a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m} @@ -1317,12 +1308,12 @@ func TestImportPath(t *testing.T) { func TestDotDotDot(t *testing.T) { // Test example from FuncType.DotDotDot documentation. - var f func(x int, y ...float) + var f func(x int, y ...float64) typ := Typeof(f).(*FuncType) if typ.NumIn() == 2 && typ.In(0) == Typeof(int(0)) { sl, ok := typ.In(1).(*SliceType) if ok { - if sl.Elem() == Typeof(float(0)) { + if sl.Elem() == Typeof(0.0) { // ok return } @@ -1330,7 +1321,7 @@ func TestDotDotDot(t *testing.T) { } // Failed - t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float") + t.Errorf("want NumIn() = 2, In(0) = int, In(1) = []float64") s := fmt.Sprintf("have NumIn() = %d", typ.NumIn()) for i := 0; i < typ.NumIn(); i++ { s += fmt.Sprintf(", In(%d) = %s", i, typ.In(i)) diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go index 9a7467b32..8dcbb2413 100644 --- a/src/pkg/reflect/type.go +++ b/src/pkg/reflect/type.go @@ -264,10 +264,8 @@ const ( Uint32 Uint64 Uintptr - Float Float32 Float64 - Complex Complex64 Complex128 Array @@ -306,9 +304,10 @@ var kindNames = []string{ Uint32: "uint32", Uint64: "uint64", Uintptr: "uintptr", - Float: "float", Float32: "float32", Float64: "float64", + Complex64: "complex64", + Complex128: "complex128", Array: "array", Chan: "chan", Func: "func", diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index e0bcb1a39..4d7d87237 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -142,8 +142,6 @@ type FloatValue struct { // Get returns the underlying int value. func (v *FloatValue) Get() float64 { switch v.typ.Kind() { - case Float: - return float64(*(*float)(v.addr)) case Float32: return float64(*(*float32)(v.addr)) case Float64: @@ -160,8 +158,6 @@ func (v *FloatValue) Set(x float64) { switch v.typ.Kind() { default: panic("reflect: invalid float kind") - case Float: - *(*float)(v.addr) = float(x) case Float32: *(*float32)(v.addr) = float32(x) case Float64: @@ -191,8 +187,6 @@ type ComplexValue struct { // Get returns the underlying complex value. func (v *ComplexValue) Get() complex128 { switch v.typ.Kind() { - case Complex: - return complex128(*(*complex)(v.addr)) case Complex64: return complex128(*(*complex64)(v.addr)) case Complex128: @@ -209,8 +203,6 @@ func (v *ComplexValue) Set(x complex128) { switch v.typ.Kind() { default: panic("reflect: invalid complex kind") - case Complex: - *(*complex)(v.addr) = complex(x) case Complex64: *(*complex64)(v.addr) = complex64(x) case Complex128: diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go index 3b2c489bc..aed733064 100644 --- a/src/pkg/regexp/all_test.go +++ b/src/pkg/regexp/all_test.go @@ -38,6 +38,8 @@ type stringError struct { var bad_re = []stringError{ {`*`, ErrBareClosure}, + {`+`, ErrBareClosure}, + {`?`, ErrBareClosure}, {`(abc`, ErrUnmatchedLpar}, {`abc)`, ErrUnmatchedRpar}, {`x[a-z`, ErrUnmatchedLbkt}, @@ -47,7 +49,6 @@ var bad_re = []stringError{ {`a**`, ErrBadClosure}, {`a*+`, ErrBadClosure}, {`a??`, ErrBadClosure}, - {`*`, ErrBareClosure}, {`\x`, ErrBadBackslash}, } diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go index 2e03b798a..d274ccdf5 100644 --- a/src/pkg/regexp/regexp.go +++ b/src/pkg/regexp/regexp.go @@ -283,6 +283,24 @@ func escape(c int) int { return -1 } +func (p *parser) checkBackslash() int { + c := p.c() + if c == '\\' { + c = p.nextc() + switch { + case c == endOfFile: + p.error(ErrExtraneousBackslash) + case ispunct(c): + // c is as delivered + case escape(c) >= 0: + c = int(escaped[escape(c)]) + default: + p.error(ErrBadBackslash) + } + } + return c +} + func (p *parser) charClass() *instr { i := newCharClass() cc := i.cclass @@ -314,20 +332,8 @@ func (p *parser) charClass() *instr { return i case '-': // do this before backslash processing p.error(ErrBadRange) - case '\\': - c = p.nextc() - switch { - case c == endOfFile: - p.error(ErrExtraneousBackslash) - case ispunct(c): - // c is as delivered - case escape(c) >= 0: - c = int(escaped[escape(c)]) - default: - p.error(ErrBadBackslash) - } - fallthrough default: + c = p.checkBackslash() p.nextc() switch { case left < 0: // first of pair @@ -345,14 +351,14 @@ func (p *parser) charClass() *instr { } } } - return nil + panic("unreachable") } func (p *parser) term() (start, end *instr) { switch c := p.c(); c { case '|', endOfFile: return nil, nil - case '*', '+': + case '*', '+', '?': p.error(ErrBareClosure) case ')': if p.nlpar == 0 { @@ -407,20 +413,8 @@ func (p *parser) term() (start, end *instr) { } bra.next = start return bra, ebra - case '\\': - c = p.nextc() - switch { - case c == endOfFile: - p.error(ErrExtraneousBackslash) - case ispunct(c): - // c is as delivered - case escape(c) >= 0: - c = int(escaped[escape(c)]) - default: - p.error(ErrBadBackslash) - } - fallthrough default: + c = p.checkBackslash() p.nextc() start = &instr{kind: iChar, char: c} p.re.add(start) diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go index 601c49715..6f028c10d 100644 --- a/src/pkg/rpc/client.go +++ b/src/pkg/rpc/client.go @@ -58,7 +58,7 @@ func (client *Client) send(c *Call) { if client.shutdown != nil { c.Error = client.shutdown client.mutex.Unlock() - _ = c.Done <- c // do not block + c.done() return } c.seq = client.seq @@ -102,16 +102,14 @@ func (client *Client) input() { // Empty strings should turn into nil os.Errors c.Error = nil } - // We don't want to block here. It is the caller's responsibility to make - // sure the channel has enough buffer space. See comment in Go(). - _ = c.Done <- c // do not block + c.done() } // Terminate pending calls. client.mutex.Lock() client.shutdown = err for _, call := range client.pending { call.Error = err - _ = call.Done <- call // do not block + call.done() } client.mutex.Unlock() if err != os.EOF || !client.closing { @@ -119,6 +117,16 @@ func (client *Client) input() { } } +func (call *Call) done() { + select { + case call.Done <- call: + // ok + default: + // We don't want to block here. It is the caller's responsibility to make + // sure the channel has enough buffer space. See comment in Go(). + } +} + // NewClient returns a new Client to handle requests to the // set of services at the other end of the connection. func NewClient(conn io.ReadWriteCloser) *Client { @@ -233,7 +241,7 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface c.Done = done if client.shutdown != nil { c.Error = client.shutdown - _ = c.Done <- c // do not block + c.done() return c } client.send(c) diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go index 5c50bcc3a..91e9cd5c8 100644 --- a/src/pkg/rpc/server.go +++ b/src/pkg/rpc/server.go @@ -73,7 +73,7 @@ rpc.HandleHTTP() l, e := net.Listen("tcp", ":1234") if e != nil { - log.Exit("listen error:", e) + log.Fatal("listen error:", e) } go http.Serve(l, nil) @@ -82,7 +82,7 @@ client, err := rpc.DialHTTP("tcp", serverAddress + ":1234") if err != nil { - log.Exit("dialing:", err) + log.Fatal("dialing:", err) } Then it can make a remote call: @@ -92,7 +92,7 @@ var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { - log.Exit("arith error:", err) + log.Fatal("arith error:", err) } fmt.Printf("Arith: %d*%d=%d", args.A, args.B, *reply) @@ -225,7 +225,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E sname = name } if sname == "" { - log.Exit("rpc: no service name for type", s.typ.String()) + log.Fatal("rpc: no service name for type", s.typ.String()) } if s.typ.PkgPath() != "" && !isExported(sname) && !useName { s := "rpc Register: type " + sname + " is not exported" @@ -445,7 +445,7 @@ func (server *Server) Accept(lis net.Listener) { for { conn, err := lis.Accept() if err != nil { - log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit? + log.Fatal("rpc.Serve: accept:", err.String()) // TODO(r): exit? } go server.ServeConn(conn) } diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go index 355d51ce4..1f080faa5 100644 --- a/src/pkg/rpc/server_test.go +++ b/src/pkg/rpc/server_test.go @@ -72,7 +72,7 @@ func (t *Arith) Error(args *Args, reply *Reply) os.Error { func listenTCP() (net.Listener, string) { l, e := net.Listen("tcp", "127.0.0.1:0") // any available address if e != nil { - log.Exitf("net.Listen tcp :0: %v", e) + log.Fatalf("net.Listen tcp :0: %v", e) } return l, l.Addr().String() } @@ -364,14 +364,12 @@ func TestSendDeadlock(t *testing.T) { testSendDeadlock(client) done <- true }() - for i := 0; i < 50; i++ { - time.Sleep(100 * 1e6) - _, ok := <-done - if ok { - return - } + select { + case <-done: + return + case <-time.After(5e9): + t.Fatal("deadlock") } - t.Fatal("deadlock") } func testSendDeadlock(client *Client) { diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s index 84f5367e5..63d582606 100644 --- a/src/pkg/runtime/386/asm.s +++ b/src/pkg/runtime/386/asm.s @@ -18,9 +18,10 @@ TEXT _rt0_386(SB),7,$0 // we set up GS ourselves. MOVL initcgo(SB), AX TESTL AX, AX - JZ 3(PC) + JZ 4(PC) CALL AX - JMP ok + CMPL runtime·iswindows(SB), $0 + JEQ ok // set up %gs CALL runtime·ldt0setup(SB) @@ -46,7 +47,7 @@ ok: MOVL CX, m_g0(AX) // create istack out of the OS stack - LEAL (-8192+104)(SP), AX // TODO: 104? + LEAL (-64*1024+104)(SP), AX // TODO: 104? MOVL AX, g_stackguard(CX) MOVL SP, g_stackbase(CX) CALL runtime·emptyfunc(SB) // fault if stack check is wrong @@ -156,8 +157,8 @@ TEXT runtime·morestack(SB),7,$0 // frame size in DX // arg size in AX // Save in m. - MOVL DX, m_moreframe(BX) - MOVL AX, m_moreargs(BX) + MOVL DX, m_moreframesize(BX) + MOVL AX, m_moreargsize(BX) // Called from f. // Set m->morebuf to f's caller. @@ -165,7 +166,7 @@ TEXT runtime·morestack(SB),7,$0 MOVL DI, (m_morebuf+gobuf_pc)(BX) LEAL 8(SP), CX // f's caller's SP MOVL CX, (m_morebuf+gobuf_sp)(BX) - MOVL CX, (m_morefp)(BX) + MOVL CX, m_moreargp(BX) get_tls(CX) MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) @@ -213,9 +214,9 @@ TEXT reflect·call(SB), 7, $0 MOVL 12(SP), CX // arg size MOVL AX, m_morepc(BX) // f's PC - MOVL DX, m_morefp(BX) // argument frame pointer - MOVL CX, m_moreargs(BX) // f's argument size - MOVL $1, m_moreframe(BX) // f's frame size + MOVL DX, m_moreargp(BX) // f's argument pointer + MOVL CX, m_moreargsize(BX) // f's argument size + MOVL $1, m_moreframesize(BX) // f's frame size // Call newstack on m's scheduling stack. MOVL m_g0(BX), BP diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile index e62dbe393..e9488cfb5 100644 --- a/src/pkg/runtime/Makefile +++ b/src/pkg/runtime/Makefile @@ -26,16 +26,7 @@ GOFILES=\ softfloat64.go\ type.go\ version.go\ - chan_defs.go\ - hashmap_defs.go\ - iface_defs.go\ - malloc_defs.go\ - mheapmap$(SIZE)_defs.go\ runtime_defs.go\ - $(GOOS)/runtime_defs.go\ - -GOFILES_tiny=\ - tiny/io.go\ OFILES_windows=\ syscall.$O\ @@ -73,7 +64,6 @@ OFILES=\ mfixalloc.$O\ mgc0.$O\ mheap.$O\ - mheapmap$(SIZE).$O\ mprof.$O\ msize.$O\ print.$O\ @@ -122,7 +112,7 @@ $(pkgdir)/%.h: %.h clean: clean-local clean-local: - rm -f goc2c mkversion version.go */asm.h runtime.acid.* $$(ls *.goc | sed 's/goc$$/c/') + rm -f goc2c mkversion version.go */asm.h runtime.acid.* runtime_defs.go $$(ls *.goc | sed 's/goc$$/c/') $(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH) ./mkasmh.sh >$@.x @@ -165,3 +155,7 @@ ifeq ($(GOARCH),386) traceback.$O: amd64/traceback.c $(CC) $(CFLAGS) $< endif + +runtime_defs.go: proc.c iface.c hashmap.c chan.c + CC="$(CC)" CFLAGS="$(CFLAGS)" ./mkgodefs.sh $^ > $@.x + mv -f $@.x $@ diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s index 235f27206..b6642c13c 100644 --- a/src/pkg/runtime/amd64/asm.s +++ b/src/pkg/runtime/amd64/asm.s @@ -151,7 +151,7 @@ TEXT runtime·morestack(SB),7,$0 MOVQ AX, (m_morebuf+gobuf_pc)(BX) LEAQ 16(SP), AX // f's caller's SP MOVQ AX, (m_morebuf+gobuf_sp)(BX) - MOVQ AX, (m_morefp)(BX) + MOVQ AX, m_moreargp(BX) get_tls(CX) MOVQ g(CX), SI MOVQ SI, (m_morebuf+gobuf_g)(BX) @@ -197,9 +197,9 @@ TEXT reflect·call(SB), 7, $0 MOVL 24(SP), CX // arg size MOVQ AX, m_morepc(BX) // f's PC - MOVQ DX, m_morefp(BX) // argument frame pointer - MOVL CX, m_moreargs(BX) // f's argument size - MOVL $1, m_moreframe(BX) // f's frame size + MOVQ DX, m_moreargp(BX) // argument frame pointer + MOVL CX, m_moreargsize(BX) // f's argument size + MOVL $1, m_moreframesize(BX) // f's frame size // Call newstack on m's scheduling stack. MOVQ m_g0(BX), BP @@ -230,7 +230,7 @@ TEXT runtime·morestack00(SB),7,$0 get_tls(CX) MOVQ m(CX), BX MOVQ $0, AX - MOVQ AX, m_moreframe(BX) + MOVQ AX, m_moreframesize(BX) MOVQ $runtime·morestack(SB), AX JMP AX @@ -238,7 +238,7 @@ TEXT runtime·morestack01(SB),7,$0 get_tls(CX) MOVQ m(CX), BX SHLQ $32, AX - MOVQ AX, m_moreframe(BX) + MOVQ AX, m_moreframesize(BX) MOVQ $runtime·morestack(SB), AX JMP AX @@ -246,14 +246,14 @@ TEXT runtime·morestack10(SB),7,$0 get_tls(CX) MOVQ m(CX), BX MOVLQZX AX, AX - MOVQ AX, m_moreframe(BX) + MOVQ AX, m_moreframesize(BX) MOVQ $runtime·morestack(SB), AX JMP AX TEXT runtime·morestack11(SB),7,$0 get_tls(CX) MOVQ m(CX), BX - MOVQ AX, m_moreframe(BX) + MOVQ AX, m_moreframesize(BX) MOVQ $runtime·morestack(SB), AX JMP AX @@ -294,7 +294,7 @@ TEXT morestack<>(SB),7,$0 MOVQ m(CX), BX POPQ AX SHLQ $35, AX - MOVQ AX, m_moreframe(BX) + MOVQ AX, m_moreframesize(BX) MOVQ $runtime·morestack(SB), AX JMP AX @@ -407,9 +407,9 @@ TEXT runtime·stackcheck(SB), 7, $0 TEXT runtime·memclr(SB),7,$0 MOVQ 8(SP), DI // arg 1 addr - MOVL 16(SP), CX // arg 2 count - ADDL $7, CX - SHRL $3, CX + MOVQ 16(SP), CX // arg 2 count + ADDQ $7, CX + SHRQ $3, CX MOVQ $0, AX CLD REP diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c index 3ea80a661..86e96f348 100644 --- a/src/pkg/runtime/amd64/traceback.c +++ b/src/pkg/runtime/amd64/traceback.c @@ -60,7 +60,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m) // The 0x48 byte is only on amd64. p = (byte*)pc; // We check p < p+8 to avoid wrapping and faulting if we lose track. - if(runtime·mheap.min < p && p < p+8 && p+8 < runtime·mheap.max && // pointer in allocated memory + if(runtime·mheap.arena_start < p && p < p+8 && p+8 < runtime·mheap.arena_used && // pointer in allocated memory (sizeof(uintptr) != 8 || *p++ == 0x48) && // skip 0x48 byte on amd64 p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) { sp += *(uint32*)(p+2); @@ -154,7 +154,7 @@ isclosureentry(uintptr pc) int32 i, siz; p = (byte*)pc; - if(p < runtime·mheap.min || p+32 > runtime·mheap.max) + if(p < runtime·mheap.arena_start || p+32 > runtime·mheap.arena_used) return 0; // SUBQ $siz, SP diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s index 44c47bad1..a4e4b3283 100644 --- a/src/pkg/runtime/arm/asm.s +++ b/src/pkg/runtime/arm/asm.s @@ -145,14 +145,15 @@ TEXT runtime·morestack(SB),7,$-4 BL.EQ runtime·abort(SB) // Save in m. - MOVW R1, m_moreframe(m) - MOVW R2, m_moreargs(m) + MOVW R1, m_moreframesize(m) + MOVW R2, m_moreargsize(m) // Called from f. // Set m->morebuf to f's caller. MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP - MOVW SP, m_morefp(m) // f's caller's SP + MOVW $4(SP), R3 // f's argument pointer + MOVW R3, m_moreargp(m) MOVW g, (m_morebuf+gobuf_g)(m) // Set m->morepc to f's PC. @@ -185,14 +186,11 @@ TEXT reflect·call(SB), 7, $-4 MOVW 8(SP), R1 // arg frame MOVW 12(SP), R2 // arg size - SUB $4,R1 // add the saved LR to the frame - ADD $4,R2 - MOVW R0, m_morepc(m) // f's PC - MOVW R1, m_morefp(m) // argument frame pointer - MOVW R2, m_moreargs(m) // f's argument size + MOVW R1, m_moreargp(m) // f's argument pointer + MOVW R2, m_moreargsize(m) // f's argument size MOVW $1, R3 - MOVW R3, m_moreframe(m) // f's frame size + MOVW R3, m_moreframesize(m) // f's frame size // Call newstack on m's scheduling stack. MOVW m_g0(m), g @@ -218,8 +216,9 @@ TEXT runtime·lessstack(SB), 7, $-4 TEXT runtime·jmpdefer(SB), 7, $0 MOVW 0(SP), LR MOVW $-4(LR), LR // BL deferreturn - MOVW 4(SP), R0 // fn - MOVW 8(SP), SP + MOVW fn+0(FP), R0 + MOVW argp+4(FP), SP + MOVW $-4(SP), SP // SP is 4 below argp, due to saved LR B (R0) TEXT runtime·memclr(SB),7,$20 diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile index 55b6967d9..768fe80ac 100644 --- a/src/pkg/runtime/cgo/Makefile +++ b/src/pkg/runtime/cgo/Makefile @@ -10,6 +10,10 @@ ifeq ($(GOARCH),arm) ENABLED:=0 endif +ifeq ($(DISABLE_CGO),1) +ENABLED:=0 +endif + TARG=runtime/cgo GOFILES=\ @@ -30,7 +34,11 @@ OFILES=\ _cgo_import.$O\ $(CGO_OFILES)\ +ifeq ($(GOOS),windows) +CGO_LDFLAGS=-lm -mthreads +else CGO_LDFLAGS=-lpthread +endif ifeq ($(GOOS),freebsd) OFILES+=\ @@ -48,7 +56,6 @@ _cgo_defun.c: _cgo_main.c: echo 'int main() { return 0; }' >$@ - echo 'void *crosscall2;' >>$@ endif $(GOARCH).o: $(GOARCH).S diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/windows_386.c index 5f5235bd2..f39309cb1 100755 --- a/src/pkg/runtime/cgo/windows_386.c +++ b/src/pkg/runtime/cgo/windows_386.c @@ -30,6 +30,7 @@ static void* threadentry(void *v) { ThreadStart ts; + void *tls0; ts = *(ThreadStart*)v; free(v); @@ -45,13 +46,17 @@ threadentry(void *v) /* * Set specific keys in thread local storage. */ + tls0 = (void*)LocalAlloc(LPTR, 32); asm volatile ( - "MOVL %%fs:0x2c, %%eax\n" // MOVL 0x24(FS), tmp - "movl %0, 0(%%eax)\n" // MOVL g, 0(FS) - "movl %1, 4(%%eax)\n" // MOVL m, 4(FS) - :: "r"(ts.g), "r"(ts.m) : "%eax" + "movl %0, %%fs:0x2c\n" // MOVL tls0, 0x2c(FS) + "movl %%fs:0x2c, %%eax\n" // MOVL 0x2c(FS), tmp + "movl %1, 0(%%eax)\n" // MOVL g, 0(FS) + "movl %2, 4(%%eax)\n" // MOVL m, 4(FS) + :: "r"(tls0), "r"(ts.g), "r"(ts.m) : "%eax" ); crosscall_386(ts.fn); + + LocalFree(tls0); return nil; } diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c index 80ae97e7a..e6ece9542 100644 --- a/src/pkg/runtime/cgocall.c +++ b/src/pkg/runtime/cgocall.c @@ -53,12 +53,13 @@ runtime·cgocall(void (*fn)(void*), void *arg) // (arg/argsize) on to the stack, calls the function, copies the // arguments back where they came from, and finally returns to the old // stack. -void +uintptr runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize) { Gobuf oldsched, oldg1sched; G *g1; void *sp; + uintptr ret; if(g != m->g0) runtime·throw("bad g in cgocallback"); @@ -70,11 +71,11 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize) runtime·startcgocallback(g1); sp = g1->sched.sp - argsize; - if(sp < g1->stackguard) + if(sp < g1->stackguard - StackGuard + 4) // +4 for return address runtime·throw("g stack overflow in cgocallback"); runtime·mcpy(sp, arg, argsize); - runtime·runcgocallback(g1, sp, fn); + ret = runtime·runcgocallback(g1, sp, fn); runtime·mcpy(arg, sp, argsize); @@ -82,6 +83,8 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize) m->sched = oldsched; g1->sched = oldg1sched; + + return ret; } void diff --git a/src/pkg/runtime/cgocall.h b/src/pkg/runtime/cgocall.h index 1ad954eb1..7c24e167b 100644 --- a/src/pkg/runtime/cgocall.h +++ b/src/pkg/runtime/cgocall.h @@ -7,6 +7,6 @@ */ void runtime·cgocall(void (*fn)(void*), void*); -void runtime·cgocallback(void (*fn)(void), void*, int32); +uintptr runtime·cgocallback(void (*fn)(void), void*, int32); void *runtime·cmalloc(uintptr); void runtime·cfree(void*); diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index 94ea513e7..8d3ac2ca4 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -11,8 +11,6 @@ enum { Wclosed = 0x0001, // writer has closed Rclosed = 0x0002, // reader has seen close - Eincr = 0x0004, // increment errors - Emax = 0x0800, // error limit before throw }; typedef struct Link Link; @@ -76,6 +74,7 @@ struct Select uint16 tcase; // total count of scase[] uint16 ncase; // currently filled scase[] Select* link; // for freelist + uint16* order; Scase* scase[1]; // one per case }; @@ -84,9 +83,7 @@ static SudoG* dequeue(WaitQ*, Hchan*); static void enqueue(WaitQ*, SudoG*); static SudoG* allocsg(Hchan*); static void freesg(Hchan*, SudoG*); -static uint32 gcd(uint32, uint32); -static uint32 fastrand1(void); -static uint32 fastrand2(void); +static uint32 fastrandn(uint32); static void destroychan(Hchan*); Hchan* @@ -152,16 +149,6 @@ runtime·makechan(Type *elem, int64 hint, Hchan *ret) FLUSH(&ret); } -static void -incerr(Hchan* c) -{ - c->closed += Eincr; - if(c->closed & Emax) { - // Note that channel locks may still be held at this point. - runtime·throw("too many operations on a closed channel"); - } -} - /* * generic single channel send/recv * if the bool pointer is nil, @@ -277,14 +264,12 @@ asynch: return; closed: - incerr(c); - if(pres != nil) - *pres = true; runtime·unlock(c); + runtime·panicstring("send on closed channel"); } void -runtime·chanrecv(Hchan* c, byte *ep, bool* pres) +runtime·chanrecv(Hchan* c, byte *ep, bool *pres, bool *closed) { SudoG *sg; G *gp; @@ -299,6 +284,9 @@ runtime·chanrecv(Hchan* c, byte *ep, bool* pres) runtime·printf("chanrecv: chan=%p\n", c); runtime·lock(c); + if(closed != nil) + *closed = false; + loop: if(c->dataqsiz > 0) goto asynch; @@ -308,7 +296,8 @@ loop: sg = dequeue(&c->sendq, c); if(sg != nil) { - c->elemalg->copy(c->elemsize, ep, sg->elem); + if(ep != nil) + c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemalg->copy(c->elemsize, sg->elem, nil); gp = sg->g; @@ -323,7 +312,6 @@ loop: if(pres != nil) { runtime·unlock(c); - c->elemalg->copy(c->elemsize, ep, nil); *pres = false; return; } @@ -340,7 +328,8 @@ loop: if(sg == nil) goto loop; - c->elemalg->copy(c->elemsize, ep, sg->elem); + if(ep != nil) + c->elemalg->copy(c->elemsize, ep, sg->elem); c->elemalg->copy(c->elemsize, sg->elem, nil); freesg(c, sg); runtime·unlock(c); @@ -353,7 +342,6 @@ asynch: if(pres != nil) { runtime·unlock(c); - c->elemalg->copy(c->elemsize, ep, nil); *pres = false; return; } @@ -366,7 +354,8 @@ asynch: runtime·lock(c); goto asynch; } - c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); + if(ep != nil) + c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem); c->elemalg->copy(c->elemsize, c->recvdataq->elem, nil); c->recvdataq = c->recvdataq->link; c->qcount--; @@ -387,9 +376,11 @@ asynch: return; closed: - c->elemalg->copy(c->elemsize, ep, nil); + if(closed != nil) + *closed = true; + if(ep != nil) + c->elemalg->copy(c->elemsize, ep, nil); c->closed |= Rclosed; - incerr(c); if(pres != nil) *pres = true; runtime·unlock(c); @@ -411,55 +402,99 @@ runtime·chansend1(Hchan* c, ...) runtime·chansend(c, ae, nil); } -// chansend2(hchan *chan any, elem any) (pres bool); +// chanrecv1(hchan *chan any) (elem any); #pragma textflag 7 void -runtime·chansend2(Hchan* c, ...) +runtime·chanrecv1(Hchan* c, ...) { int32 o; - byte *ae, *ap; - - if(c == nil) - runtime·panicstring("send to nil channel"); + byte *ae; - o = runtime·rnd(sizeof(c), c->elemalign); + o = runtime·rnd(sizeof(c), Structrnd); ae = (byte*)&c + o; - o = runtime·rnd(o+c->elemsize, Structrnd); - ap = (byte*)&c + o; - runtime·chansend(c, ae, ap); + runtime·chanrecv(c, ae, nil, nil); } -// chanrecv1(hchan *chan any) (elem any); +// chanrecv3(hchan *chan any) (elem any, closed bool); #pragma textflag 7 void -runtime·chanrecv1(Hchan* c, ...) +runtime·chanrecv3(Hchan* c, ...) { int32 o; - byte *ae; + byte *ae, *ac; + + if(c == nil) + runtime·panicstring("range over nil channel"); o = runtime·rnd(sizeof(c), Structrnd); ae = (byte*)&c + o; + o = runtime·rnd(o+c->elemsize, 1); + ac = (byte*)&c + o; - runtime·chanrecv(c, ae, nil); + runtime·chanrecv(c, ae, nil, ac); } -// chanrecv2(hchan *chan any) (elem any, pres bool); +// func selectnbsend(c chan any, elem any) bool +// +// compiler implements +// +// select { +// case c <- v: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if c != nil && selectnbsend(c, v) { +// ... foo +// } else { +// ... bar +// } +// #pragma textflag 7 void -runtime·chanrecv2(Hchan* c, ...) +runtime·selectnbsend(Hchan *c, ...) { int32 o; byte *ae, *ap; - o = runtime·rnd(sizeof(c), Structrnd); + o = runtime·rnd(sizeof(c), c->elemalign); ae = (byte*)&c + o; - o = runtime·rnd(o+c->elemsize, 1); + o = runtime·rnd(o+c->elemsize, Structrnd); ap = (byte*)&c + o; - runtime·chanrecv(c, ae, ap); + runtime·chansend(c, ae, ap); } +// func selectnbrecv(elem *any, c chan any) bool +// +// compiler implements +// +// select { +// case v = <-c: +// ... foo +// default: +// ... bar +// } +// +// as +// +// if c != nil && selectnbrecv(&v, c) { +// ... foo +// } else { +// ... bar +// } +// +#pragma textflag 7 +void +runtime·selectnbrecv(byte *v, Hchan *c, bool ok) +{ + runtime·chanrecv(c, v, &ok, nil); +} + // newselect(size uint32) (sel *byte); #pragma textflag 7 void @@ -475,10 +510,11 @@ runtime·newselect(int32 size, ...) if(size > 1) n = size-1; - sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0])); + sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0]) + size*sizeof(sel->order[0])); sel->tcase = size; sel->ncase = 0; + sel->order = (void*)(sel->scase + size); *selp = sel; if(debug) runtime·printf("newselect s=%p size=%d\n", sel, size); @@ -619,6 +655,13 @@ selunlock(Select *sel) } } +void +runtime·block(void) +{ + g->status = Gwaiting; // forever + runtime·gosched(); +} + // selectgo(sel *byte); // // overwrites return pc on stack to signal which case of the select @@ -629,7 +672,7 @@ selunlock(Select *sel) void runtime·selectgo(Select *sel) { - uint32 p, o, i, j; + uint32 o, i, j; Scase *cas, *dfl; Hchan *c; SudoG *sg; @@ -642,29 +685,24 @@ runtime·selectgo(Select *sel) if(debug) runtime·printf("select: sel=%p\n", sel); - if(sel->ncase < 2) { - if(sel->ncase < 1) { - g->status = Gwaiting; // forever - runtime·gosched(); - } - // TODO: make special case of one. - } + // The compiler rewrites selects that statically have + // only 0 or 1 cases plus default into simpler constructs. + // The only way we can end up with such small sel->ncase + // values here is for a larger select in which most channels + // have been nilled out. The general code handles those + // cases correctly, and they are rare enough not to bother + // optimizing (and needing to test). - // select a (relative) prime - for(i=0;; i++) { - p = fastrand1(); - if(gcd(p, sel->ncase) == 1) - break; - if(i > 1000) - runtime·throw("select: failed to select prime"); + // generate permuted order + for(i=0; i<sel->ncase; i++) + sel->order[i] = i; + for(i=1; i<sel->ncase; i++) { + o = sel->order[i]; + j = fastrandn(i+1); + sel->order[i] = sel->order[j]; + sel->order[j] = o; } - // select an initial offset - o = fastrand2(); - - p %= sel->ncase; - o %= sel->ncase; - // sort the cases by Hchan address to get the locking order. for(i=1; i<sel->ncase; i++) { cas = sel->scase[i]; @@ -672,13 +710,13 @@ runtime·selectgo(Select *sel) sel->scase[j] = sel->scase[j-1]; sel->scase[j] = cas; } - sellock(sel); loop: // pass 1 - look for something already waiting dfl = nil; for(i=0; i<sel->ncase; i++) { + o = sel->order[i]; cas = sel->scase[o]; c = cas->chan; @@ -713,10 +751,6 @@ loop: dfl = cas; break; } - - o += p; - if(o >= sel->ncase) - o -= sel->ncase; } if(dfl != nil) { @@ -727,6 +761,7 @@ loop: // pass 2 - enqueue on all chans for(i=0; i<sel->ncase; i++) { + o = sel->order[i]; cas = sel->scase[o]; c = cas->chan; sg = allocsg(c); @@ -734,32 +769,15 @@ loop: switch(cas->send) { case 0: // recv - if(c->dataqsiz > 0) { - if(c->qcount > 0) - runtime·throw("select: pass 2 async recv"); - } else { - if(dequeue(&c->sendq, c)) - runtime·throw("select: pass 2 sync recv"); - } enqueue(&c->recvq, sg); break; case 1: // send - if(c->dataqsiz > 0) { - if(c->qcount < c->dataqsiz) - runtime·throw("select: pass 2 async send"); - } else { - if(dequeue(&c->recvq, c)) - runtime·throw("select: pass 2 sync send"); + if(c->dataqsiz == 0) c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem); - } enqueue(&c->sendq, sg); break; } - - o += p; - if(o >= sel->ncase) - o -= sel->ncase; } g->param = nil; @@ -773,18 +791,14 @@ loop: // pass 3 - dequeue from unsuccessful chans // otherwise they stack up on quiet channels for(i=0; i<sel->ncase; i++) { - if(sg == nil || o != sg->offset) { - cas = sel->scase[o]; + if(sg == nil || i != sg->offset) { + cas = sel->scase[i]; c = cas->chan; if(cas->send) dequeueg(&c->sendq, c); else dequeueg(&c->recvq, c); } - - o += p; - if(o >= sel->ncase) - o -= sel->ncase; } if(sg == nil) @@ -858,7 +872,6 @@ rclose: if(cas->u.elemp != nil) c->elemalg->copy(c->elemsize, cas->u.elemp, nil); c->closed |= Rclosed; - incerr(c); goto retc; syncsend: @@ -871,12 +884,6 @@ syncsend: gp = sg->g; gp->param = sg; runtime·ready(gp); - goto retc; - -sclose: - // send on closed channel - incerr(c); - goto retc; retc: selunlock(sel); @@ -886,6 +893,12 @@ retc: as = (byte*)&sel + cas->so; freesel(sel); *as = true; + return; + +sclose: + // send on closed channel + selunlock(sel); + runtime·panicstring("send on closed channel"); } // closechan(sel *byte); @@ -899,7 +912,11 @@ runtime·closechan(Hchan *c) runtime·gosched(); runtime·lock(c); - incerr(c); + if(c->closed & Wclosed) { + runtime·unlock(c); + runtime·panicstring("close of closed channel"); + } + c->closed |= Wclosed; // release all readers @@ -1039,22 +1056,6 @@ freesg(Hchan *c, SudoG *sg) } static uint32 -gcd(uint32 u, uint32 v) -{ - for(;;) { - if(u > v) { - if(v == 0) - return u; - u = u%v; - continue; - } - if(u == 0) - return v; - v = v%u; - } -} - -static uint32 fastrand1(void) { static uint32 x = 0x49f6428aUL; @@ -1066,12 +1067,19 @@ fastrand1(void) } static uint32 -fastrand2(void) +fastrandn(uint32 n) { - static uint32 x = 0x49f6428aUL; + uint32 max, r; - x += x; - if(x & 0x80000000L) - x ^= 0xfafd871bUL; - return x; + if(n <= 1) + return 0; + + r = fastrand1(); + if(r < (1ULL<<31)-n) // avoid computing max in common case + return r%n; + + max = (1ULL<<31)/n * n; + while(r >= max) + r = fastrand1(); + return r%n; } diff --git a/src/pkg/runtime/chan_defs.go b/src/pkg/runtime/chan_defs.go deleted file mode 100644 index 5cfea6e15..000000000 --- a/src/pkg/runtime/chan_defs.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is chan.c - -package runtime - -type sudoG struct { - g *g_ - selgen uint32 - offset int16 - isfree int8 - link *sudoG - elem [8]byte -} - -type waitQ struct { - first *sudoG - last *sudoG -} - -type hChan struct { - qcount uint32 - dataqsiz uint32 - elemsize uint16 - closed uint16 - elemalign uint8 - elemalg *alg - senddataq *link - recvdataq *link - recvq waitQ - sendq waitQ - free sudoG - lock -} - -type link struct { - link *link - elem [8]byte -} - -type scase struct { - chan_ *hChan - pc *byte - send uint16 - so uint16 - elemp *byte // union elem [8]byte -} - -type select_ struct { - tcase uint16 - ncase uint16 - link *select_ - scase [1]*scase -} diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c index 53a4e2f17..33f47d44f 100644 --- a/src/pkg/runtime/darwin/386/signal.c +++ b/src/pkg/runtime/darwin/386/signal.c @@ -66,6 +66,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->eip; // Only push runtime·sigpanic if r->eip != 0. // If r->eip == 0, probably panicked because of a diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s index 79bbfb68b..7961e369c 100644 --- a/src/pkg/runtime/darwin/386/sys.s +++ b/src/pkg/runtime/darwin/386/sys.s @@ -138,7 +138,7 @@ TEXT runtime·bsdthread_create(SB),7,$32 MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM INT $0x80 JAE 3(PC) - MOVL $-1, AX + NEGL AX RET MOVL $0, AX RET diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c index 474a1bd5c..948b6c9c2 100644 --- a/src/pkg/runtime/darwin/amd64/signal.c +++ b/src/pkg/runtime/darwin/amd64/signal.c @@ -76,6 +76,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->rip; // Only push runtime·sigpanic if r->rip != 0. // If r->rip == 0, probably panicked because of a diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s index 05dbc7b93..bc970156a 100644 --- a/src/pkg/runtime/darwin/amd64/sys.s +++ b/src/pkg/runtime/darwin/amd64/sys.s @@ -141,7 +141,7 @@ TEXT runtime·bsdthread_create(SB),7,$0 MOVQ $(0x2000000+360), AX // bsdthread_create SYSCALL JCC 3(PC) - MOVL $-1, AX + NEGL AX RET MOVL $0, AX RET diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c index 7fb2c2807..cbae18718 100644 --- a/src/pkg/runtime/darwin/mem.c +++ b/src/pkg/runtime/darwin/mem.c @@ -10,10 +10,8 @@ runtime·SysAlloc(uintptr n) mstats.sys += n; v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); - if(v < (void*)4096) { - runtime·printf("mmap: errno=%p\n", v); - runtime·throw("mmap"); - } + if(v < (void*)4096) + return nil; return v; } @@ -32,8 +30,19 @@ runtime·SysFree(void *v, uintptr n) runtime·munmap(v, n); } +void* +runtime·SysReserve(void *v, uintptr n) +{ + return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); +} void -runtime·SysMemInit(void) +runtime·SysMap(void *v, uintptr n) { + void *p; + + mstats.sys += n; + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); } diff --git a/src/pkg/runtime/darwin/runtime_defs.go b/src/pkg/runtime/darwin/runtime_defs.go deleted file mode 100644 index cf0b414a9..000000000 --- a/src/pkg/runtime/darwin/runtime_defs.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is runtime.h - -package runtime - -type lock struct { - key uint32 - sema uint32 -} - -type usema struct { - u uint32 - k uint32 -} - - -type note struct { - wakeup int32 - sema usema -} diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c index d69c62412..57e813109 100644 --- a/src/pkg/runtime/darwin/thread.c +++ b/src/pkg/runtime/darwin/thread.c @@ -157,13 +157,17 @@ runtime·goenvs(void) void runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) { + int32 errno; + m->tls[0] = m->id; // so 386 asm can find it if(0){ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n", stk, m, g, fn, m->id, m->tls[0], &m); } - if(runtime·bsdthread_create(stk, m, g, fn) < 0) - runtime·throw("cannot create new OS thread"); + if((errno = runtime·bsdthread_create(stk, m, g, fn)) < 0) { + runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno); + runtime·throw("runtime.newosproc"); + } } // Called to initialize a new m (including the bootstrap m). diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go index 3ce35cc5b..d09db1be6 100644 --- a/src/pkg/runtime/debug.go +++ b/src/pkg/runtime/debug.go @@ -39,6 +39,7 @@ type MemStatsType struct { Sys uint64 // bytes obtained from system (should be sum of XxxSys below) Lookups uint64 // number of pointer lookups Mallocs uint64 // number of mallocs + Frees uint64 // number of frees // Main allocation heap statistics. HeapAlloc uint64 // bytes allocated and still in use @@ -56,15 +57,15 @@ type MemStatsType struct { MSpanSys uint64 MCacheInuse uint64 // mcache structures MCacheSys uint64 - MHeapMapSys uint64 // heap map BuckHashSys uint64 // profiling bucket hash table // Garbage collector statistics. - NextGC uint64 - PauseNs uint64 - NumGC uint32 - EnableGC bool - DebugGC bool + NextGC uint64 + PauseTotalNs uint64 + PauseNs [256]uint64 // most recent GC pause times + NumGC uint32 + EnableGC bool + DebugGC bool // Per-size allocation statistics. // Not locked during update; approximate. diff --git a/src/pkg/runtime/debug/Makefile b/src/pkg/runtime/debug/Makefile new file mode 100644 index 000000000..885f66aca --- /dev/null +++ b/src/pkg/runtime/debug/Makefile @@ -0,0 +1,11 @@ +# Copyright 2011 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. + +include ../../../Make.inc + +TARG=runtime/debug +GOFILES=\ + stack.go\ + +include ../../../Make.pkg diff --git a/src/pkg/runtime/debug/stack.go b/src/pkg/runtime/debug/stack.go new file mode 100644 index 000000000..e7d56ac23 --- /dev/null +++ b/src/pkg/runtime/debug/stack.go @@ -0,0 +1,90 @@ +// Copyright 2011 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. + +// The debug package contains facilities for programs to debug themselves +// while they are running. +package debug + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "runtime" +) + +var ( + dunno = []byte("???") + centerDot = []byte("·") + dot = []byte(".") +) + +// PrintStack prints to standard error the stack trace returned by Stack. +func PrintStack() { + os.Stderr.Write(stack()) +} + +// Stack returns a formatted stack trace of the goroutine that calls it. +// For each routine, it includes the source line information and PC value, +// then attempts to discover, for Go functions, the calling function or +// method and the text of the line containing the invocation. +func Stack() []byte { + return stack() +} + +// stack implements Stack, skipping 2 frames +func stack() []byte { + buf := new(bytes.Buffer) // the returned data + // As we loop, we open files and read them. These variables record the currently + // loaded file. + var lines [][]byte + var lastFile string + for i := 2; ; i++ { // Caller we care about is the user, 2 frames up + pc, file, line, ok := runtime.Caller(i) + if !ok { + break + } + // Print this much at least. If we can't find the source, it won't show. + fmt.Fprintf(buf, "%s:%d (0x%x)\n", file, line, pc) + if file != lastFile { + data, err := ioutil.ReadFile(file) + if err != nil { + continue + } + lines = bytes.Split(data, []byte{'\n'}, -1) + lastFile = file + } + line-- // in stack trace, lines are 1-indexed but our array is 0-indexed + fmt.Fprintf(buf, "\t%s: %s\n", function(pc), source(lines, line)) + } + return buf.Bytes() +} + +// source returns a space-trimmed slice of the n'th line. +func source(lines [][]byte, n int) []byte { + if n < 0 || n >= len(lines) { + return dunno + } + return bytes.Trim(lines[n], " \t") +} + +// function returns, if possible, the name of the function containing the PC. +func function(pc uintptr) []byte { + fn := runtime.FuncForPC(pc) + if fn == nil { + return dunno + } + name := []byte(fn.Name()) + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + if period := bytes.Index(name, dot); period >= 0 { + name = name[period+1:] + } + name = bytes.Replace(name, centerDot, dot, -1) + return name +} diff --git a/src/pkg/runtime/debug/stack_test.go b/src/pkg/runtime/debug/stack_test.go new file mode 100644 index 000000000..f4bdc4624 --- /dev/null +++ b/src/pkg/runtime/debug/stack_test.go @@ -0,0 +1,55 @@ +// Copyright 2011 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. + +package debug + +import ( + "strings" + "testing" +) + +type T int + +func (t *T) ptrmethod() []byte { + return Stack() +} +func (t T) method() []byte { + return t.ptrmethod() +} + +/* + The traceback should look something like this, modulo line numbers and hex constants. + Don't worry much about the base levels, but check the ones in our own package. + + /Users/r/go/src/pkg/runtime/debug/stack_test.go:15 (0x13878) + *T.ptrmethod: return Stack() + /Users/r/go/src/pkg/runtime/debug/stack_test.go:18 (0x138dd) + T.method: return t.ptrmethod() + /Users/r/go/src/pkg/runtime/debug/stack_test.go:23 (0x13920) + TestStack: b := T(0).method() + /Users/r/go/src/pkg/testing/testing.go:132 (0x14a7a) + tRunner: test.F(t) + /Users/r/go/src/pkg/runtime/proc.c:145 (0xc970) + ???: runtime·unlock(&runtime·sched); +*/ +func TestStack(t *testing.T) { + b := T(0).method() + lines := strings.Split(string(b), "\n", -1) + if len(lines) <= 6 { + t.Fatal("too few lines") + } + check(t, lines[0], "src/pkg/runtime/debug/stack_test.go") + check(t, lines[1], "\t*T.ptrmethod: return Stack()") + check(t, lines[2], "src/pkg/runtime/debug/stack_test.go") + check(t, lines[3], "\tT.method: return t.ptrmethod()") + check(t, lines[4], "src/pkg/runtime/debug/stack_test.go") + check(t, lines[5], "\tTestStack: b := T(0).method()") + check(t, lines[6], "src/pkg/testing/testing.go") +} + +func check(t *testing.T, line, has string) { + if strings.Index(line, has) < 0 { + t.Errorf("expected %q in %q", has, line) + } +} diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go index 77c3e8e3a..dba28324c 100644 --- a/src/pkg/runtime/extern.go +++ b/src/pkg/runtime/extern.go @@ -31,6 +31,19 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) // It returns the number of entries written to pc. func Callers(skip int, pc []uintptr) int +type Func struct { // Keep in sync with runtime.h:struct Func + name string + typ string // go type string + src string // src file name + pcln []byte // pc/ln tab for this func + entry uintptr // entry pc + pc0 uintptr // starting pc, ln for table + ln0 int32 + frame int32 // stack frame size + args int32 // number of 32-bit in/out args + locals int32 // number of 32-bit locals +} + // FuncForPC returns a *Func describing the function that contains the // given program counter address, or else nil. func FuncForPC(pc uintptr) *Func diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c index 52b820df1..ddb11fc3b 100644 --- a/src/pkg/runtime/freebsd/386/signal.c +++ b/src/pkg/runtime/freebsd/386/signal.c @@ -63,6 +63,7 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->mc_eip; // Only push runtime·sigpanic if r->mc_eip != 0. // If r->mc_eip == 0, probably panicked because of a diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c index c74ddad0b..9f873d276 100644 --- a/src/pkg/runtime/freebsd/amd64/signal.c +++ b/src/pkg/runtime/freebsd/amd64/signal.c @@ -71,6 +71,7 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = (uintptr)info->si_addr; + gp->sigpc = r->mc_rip; // Only push runtime·sigpanic if r->mc_rip != 0. // If r->mc_rip == 0, probably panicked because of a diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c index 7fb2c2807..cbae18718 100644 --- a/src/pkg/runtime/freebsd/mem.c +++ b/src/pkg/runtime/freebsd/mem.c @@ -10,10 +10,8 @@ runtime·SysAlloc(uintptr n) mstats.sys += n; v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); - if(v < (void*)4096) { - runtime·printf("mmap: errno=%p\n", v); - runtime·throw("mmap"); - } + if(v < (void*)4096) + return nil; return v; } @@ -32,8 +30,19 @@ runtime·SysFree(void *v, uintptr n) runtime·munmap(v, n); } +void* +runtime·SysReserve(void *v, uintptr n) +{ + return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); +} void -runtime·SysMemInit(void) +runtime·SysMap(void *v, uintptr n) { + void *p; + + mstats.sys += n; + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); } diff --git a/src/pkg/runtime/freebsd/runtime_defs.go b/src/pkg/runtime/freebsd/runtime_defs.go deleted file mode 100644 index 86de13316..000000000 --- a/src/pkg/runtime/freebsd/runtime_defs.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2010 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. - -// OS-Specific Go definitions of internal structures. Master is runtime.h - -package runtime - -type lock struct { - key uint32 - sema uint32 -} - -type note lock diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c index a03202ed6..f0d5ce90a 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -9,7 +9,7 @@ /* Return a pointer to the struct/union of type "type" whose "field" field is addressed by pointer "p". */ -struct hash { /* a hash table; initialize with hash_init() */ +struct Hmap { /* a hash table; initialize with hash_init() */ uint32 count; /* elements in table - must be first */ uint8 datasize; /* amount of data to store in entry */ @@ -82,7 +82,7 @@ struct hash_subtable { /* return a hash layer with 2**power empty entries */ static struct hash_subtable * -hash_subtable_new (struct hash *h, int32 power, int32 used) +hash_subtable_new (Hmap *h, int32 power, int32 used) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); int32 bytes = elemsize << power; @@ -127,7 +127,7 @@ init_sizes (int64 hint, int32 *init_power, int32 *max_power) } static void -hash_init (struct hash *h, +hash_init (Hmap *h, int32 datasize, hash_hash_t (*data_hash) (uint32, void *), uint32 (*data_eq) (uint32, void *, void *), @@ -200,10 +200,10 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n) static int32 hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, - struct hash *h, void *data, void **pres); + Hmap *h, void *data, void **pres); static void -hash_conv (struct hash *h, +hash_conv (Hmap *h, struct hash_subtable *st, int32 flags, hash_hash_t hash, struct hash_entry *e) @@ -266,7 +266,7 @@ hash_conv (struct hash *h, } static void -hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags) +hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags) { struct hash_subtable *old_st = *pst; int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); @@ -290,7 +290,7 @@ hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags) } static int32 -hash_lookup (struct hash *h, void *data, void **pres) +hash_lookup (Hmap *h, void *data, void **pres) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; @@ -331,7 +331,7 @@ hash_lookup (struct hash *h, void *data, void **pres) } static int32 -hash_remove (struct hash *h, void *data, void *arg) +hash_remove (Hmap *h, void *data, void *arg) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK; @@ -374,7 +374,7 @@ hash_remove (struct hash *h, void *data, void *arg) static int32 hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, - struct hash *h, void *data, void **pres) + Hmap *h, void *data, void **pres) { int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); @@ -455,7 +455,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash, } static int32 -hash_insert (struct hash *h, void *data, void **pres) +hash_insert (Hmap *h, void *data, void **pres) { int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres); @@ -464,7 +464,7 @@ hash_insert (struct hash *h, void *data, void **pres) } static uint32 -hash_count (struct hash *h) +hash_count (Hmap *h) { return (h->count); } @@ -571,7 +571,7 @@ hash_next (struct hash_iter *it) } static void -hash_iter_init (struct hash *h, struct hash_iter *it) +hash_iter_init (Hmap *h, struct hash_iter *it) { it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]); it->changes = h->changes; @@ -607,7 +607,7 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used) } static void -hash_destroy (struct hash *h) +hash_destroy (Hmap *h) { int32 slots = 0; int32 used = 0; @@ -646,7 +646,7 @@ hash_visit_internal (struct hash_subtable *st, } static void -hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg) +hash_visit (Hmap *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg) { hash_visit_internal (h->st, 0, 0, data_visit, arg); } diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h index 0737535b5..d0fd3527f 100644 --- a/src/pkg/runtime/hashmap.h +++ b/src/pkg/runtime/hashmap.h @@ -70,7 +70,7 @@ #define free(x) runtime·free(x) #define memmove(a,b,c) runtime·memmove(a, b, c) -struct hash; /* opaque */ +struct Hmap; /* opaque */ struct hash_subtable; /* opaque */ struct hash_entry; /* opaque */ @@ -83,7 +83,7 @@ struct hash_iter { int32 changes; /* number of changes observed last time */ int32 i; /* stack pointer in subtable_state */ hash_hash_t last_hash; /* last hash value returned */ - struct hash *h; /* the hash table */ + struct Hmap *h; /* the hash table */ struct hash_iter_sub { struct hash_entry *e; /* pointer into subtable */ struct hash_entry *start; /* start of subtable */ diff --git a/src/pkg/runtime/hashmap_defs.go b/src/pkg/runtime/hashmap_defs.go deleted file mode 100644 index 57780df87..000000000 --- a/src/pkg/runtime/hashmap_defs.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is hashmap.[c,h] - -package runtime - -type hash_hash uintptr - -type hash_entry struct { - hash hash_hash - key byte // dwarf.c substitutes the real type - val byte // for key and val -} - -type hash_subtable struct { - power uint8 - used uint8 - datasize uint8 - max_probes uint8 - limit_bytes int16 - end *hash_entry - entry hash_entry // TODO: [0]hash_entry -} - -type hash struct { - count uint32 - datasize uint8 - max_power uint8 - max_probes uint8 - indirectval uint8 - changes int32 - data_hash func(uint32, uintptr) hash_hash - data_eq func(uint32, uintptr, uintptr) uint32 - data_del func(uint32, uintptr, uintptr) - st *hash_subtable - keysize uint32 - valsize uint32 - datavo uint32 - ko0 uint32 - vo0 uint32 - ko1 uint32 - vo1 uint32 - po1 uint32 - ko2 uint32 - vo2 uint32 - po2 uint32 - keyalg *alg - valalg *alg -} diff --git a/src/pkg/runtime/iface_defs.go b/src/pkg/runtime/iface_defs.go deleted file mode 100644 index 69d52ef9a..000000000 --- a/src/pkg/runtime/iface_defs.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2010 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. - -package runtime - -/* - * Must match iface.c:/Itable and compilers. - * NOTE: type.go has an Itable, that is the version of Itab used by the reflection code. - */ -type itab struct { - Itype *Type - Type *Type - link *itab - bad int32 - unused int32 - Fn func() // TODO: [0]func() -} diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c index 0dbfcf9ff..9651a6f28 100644 --- a/src/pkg/runtime/linux/386/signal.c +++ b/src/pkg/runtime/linux/386/signal.c @@ -60,6 +60,7 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = ((uintptr*)info)[3]; + gp->sigpc = r->eip; // Only push runtime·sigpanic if r->eip != 0. // If r->eip == 0, probably panicked because of a diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c index e78bbda9d..9e501c96d 100644 --- a/src/pkg/runtime/linux/amd64/signal.c +++ b/src/pkg/runtime/linux/amd64/signal.c @@ -70,6 +70,7 @@ runtime·sighandler(int32 sig, Siginfo* info, void* context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = ((uintptr*)info)[2]; + gp->sigpc = r->rip; // Only push runtime·sigpanic if r->rip != 0. // If r->rip == 0, probably panicked because of a diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c index c65aff913..481bd13c6 100644 --- a/src/pkg/runtime/linux/arm/signal.c +++ b/src/pkg/runtime/linux/arm/signal.c @@ -67,6 +67,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context) gp->sig = sig; gp->sigcode0 = info->si_code; gp->sigcode1 = r->fault_address; + gp->sigpc = r->arm_pc; // If this is a leaf function, we do smash LR, // but we're not going back there anyway. diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c index e750f97ea..3a83e7394 100644 --- a/src/pkg/runtime/linux/mem.c +++ b/src/pkg/runtime/linux/mem.c @@ -12,12 +12,11 @@ runtime·SysAlloc(uintptr n) p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0); if(p < (void*)4096) { if(p == (void*)EACCES) { - runtime·printf("mmap: access denied\n"); - runtime·printf("If you're running SELinux, enable execmem for this process.\n"); + runtime·printf("runtime: mmap: access denied\n"); + runtime·printf("if you're running SELinux, enable execmem for this process.\n"); runtime·exit(2); } - runtime·printf("mmap: errno=%p\n", p); - runtime·throw("mmap"); + return nil; } return p; } @@ -37,7 +36,19 @@ runtime·SysFree(void *v, uintptr n) runtime·munmap(v, n); } +void* +runtime·SysReserve(void *v, uintptr n) +{ + return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); +} + void -runtime·SysMemInit(void) +runtime·SysMap(void *v, uintptr n) { + void *p; + + mstats.sys += n; + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); } diff --git a/src/pkg/runtime/linux/runtime_defs.go b/src/pkg/runtime/linux/runtime_defs.go deleted file mode 100644 index 86de13316..000000000 --- a/src/pkg/runtime/linux/runtime_defs.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2010 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. - -// OS-Specific Go definitions of internal structures. Master is runtime.h - -package runtime - -type lock struct { - key uint32 - sema uint32 -} - -type note lock diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c index 979260ba1..d5f9a8fb0 100644 --- a/src/pkg/runtime/linux/thread.c +++ b/src/pkg/runtime/linux/thread.c @@ -238,8 +238,7 @@ runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) /* * note: strace gets confused if we use CLONE_PTRACE here. */ - flags = CLONE_PARENT /* getppid doesn't change in child */ - | CLONE_VM /* share memory */ + flags = CLONE_VM /* share memory */ | CLONE_FS /* share cwd, etc */ | CLONE_FILES /* share fd table */ | CLONE_SIGHAND /* share sig handler table */ diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc index f5ca9f918..cc28b943d 100644 --- a/src/pkg/runtime/malloc.goc +++ b/src/pkg/runtime/malloc.goc @@ -175,7 +175,7 @@ runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref) MSpan *s; mstats.nlookup++; - s = runtime·MHeap_LookupMaybe(&runtime·mheap, (uintptr)v>>PageShift); + s = runtime·MHeap_LookupMaybe(&runtime·mheap, v); if(sp) *sp = s; if(s == nil) { @@ -249,8 +249,45 @@ int32 runtime·sizeof_C_MStats = sizeof(MStats); void runtime·mallocinit(void) { - runtime·SysMemInit(); + byte *p; + uintptr arena_size; + runtime·InitSizes(); + + if(sizeof(void*) == 8) { + // On a 64-bit machine, allocate from a single contiguous reservation. + // 16 GB should be big enough for now. + // + // The code will work with the reservation at any address, but ask + // SysReserve to use 0x000000f800000000 if possible. + // Allocating a 16 GB region takes away 36 bits, and the amd64 + // doesn't let us choose the top 17 bits, so that leaves the 11 bits + // in the middle of 0x00f8 for us to choose. Choosing 0x00f8 means + // that the valid memory addresses will begin 0x00f8, 0x00f9, 0x00fa, 0x00fb. + // None of the bytes f8 f9 fa fb can appear in valid UTF-8, and + // they are otherwise as far from ff (likely a common byte) as possible. + // Choosing 0x00 for the leading 6 bits was more arbitrary, but it + // is not a common ASCII code point either. Using 0x11f8 instead + // caused out of memory errors on OS X during thread allocations. + // These choices are both for debuggability and to reduce the + // odds of the conservative garbage collector not collecting memory + // because some non-pointer block of memory had a bit pattern + // that matched a memory address. + arena_size = 16LL<<30; + p = runtime·SysReserve((void*)(0x00f8ULL<<32), arena_size); + if(p == nil) + runtime·throw("runtime: cannot reserve arena virtual address space"); + runtime·mheap.arena_start = p; + runtime·mheap.arena_used = p; + runtime·mheap.arena_end = p + arena_size; + } else { + // On a 32-bit machine, we'll take what we can get for each allocation + // and maintain arena_start and arena_end as min, max we've seen. + runtime·mheap.arena_start = (byte*)0xffffffff; + runtime·mheap.arena_end = 0; + } + + // Initialize the rest of the allocator. runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc); m->mcache = runtime·allocmcache(); @@ -258,6 +295,32 @@ runtime·mallocinit(void) runtime·free(runtime·malloc(1)); } +void* +runtime·MHeap_SysAlloc(MHeap *h, uintptr n) +{ + byte *p; + + if(sizeof(void*) == 8) { + // Keep taking from our reservation. + if(h->arena_end - h->arena_used < n) + return nil; + p = h->arena_used; + runtime·SysMap(p, n); + h->arena_used += n; + return p; + } else { + // Take what we can get from the OS. + p = runtime·SysAlloc(n); + if(p == nil) + return nil; + if(p+n > h->arena_used) + h->arena_used = p+n; + if(p > h->arena_end) + h->arena_end = p; + return p; + } +} + // Runtime stubs. void* @@ -282,13 +345,17 @@ static struct { FixAlloc; } stacks; +enum { + FixedStack = StackBig + StackExtra +}; + void* runtime·stackalloc(uint32 n) { void *v; uint32 *ref; - if(m->mallocing || m->gcing) { + if(m->mallocing || m->gcing || n == FixedStack) { runtime·lock(&stacks); if(stacks.size == 0) runtime·FixAlloc_Init(&stacks, n, runtime·SysAlloc, nil, nil); @@ -310,9 +377,9 @@ runtime·stackalloc(uint32 n) } void -runtime·stackfree(void *v) +runtime·stackfree(void *v, uintptr n) { - if(m->mallocing || m->gcing) { + if(m->mallocing || m->gcing || n == FixedStack) { runtime·lock(&stacks); runtime·FixAlloc_Free(&stacks, v); mstats.stacks_inuse = stacks.inuse; diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h index 0cee6c0dd..e2472e8d2 100644 --- a/src/pkg/runtime/malloc.h +++ b/src/pkg/runtime/malloc.h @@ -19,7 +19,6 @@ // used to manage storage used by the allocator. // MHeap: the malloc heap, managed at page (4096-byte) granularity. // MSpan: a run of pages managed by the MHeap. -// MHeapMap: a mapping from page IDs to MSpans. // MCentral: a shared free list for a given size class. // MCache: a per-thread (in Go, per-M) cache for small objects. // MStats: allocation statistics. @@ -84,7 +83,6 @@ typedef struct FixAlloc FixAlloc; typedef struct MCentral MCentral; typedef struct MHeap MHeap; -typedef struct MHeapMap MHeapMap; typedef struct MSpan MSpan; typedef struct MStats MStats; typedef struct MLink MLink; @@ -108,13 +106,16 @@ enum MaxMCacheSize = 2<<20, // Maximum bytes in one MCache MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap. HeapAllocChunk = 1<<20, // Chunk size for heap growth -}; + // Number of bits in page to span calculations (4k pages). + // On 64-bit, we limit the arena to 16G, so 22 bits suffices. + // On 32-bit, we don't bother limiting anything: 20 bits for 4G. #ifdef _64BIT -#include "mheapmap64.h" + MHeapMap_Bits = 22, #else -#include "mheapmap32.h" + MHeapMap_Bits = 20, #endif +}; // A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).) struct MLink @@ -124,7 +125,8 @@ struct MLink // SysAlloc obtains a large chunk of zeroed memory from the // operating system, typically on the order of a hundred kilobytes -// or a megabyte. +// or a megabyte. If the pointer argument is non-nil, the caller +// wants a mapping there or nowhere. // // SysUnused notifies the operating system that the contents // of the memory region are no longer needed and can be reused @@ -134,11 +136,19 @@ struct MLink // SysFree returns it unconditionally; this is only used if // an out-of-memory error has been detected midway through // an allocation. It is okay if SysFree is a no-op. +// +// SysReserve reserves address space without allocating memory. +// If the pointer passed to it is non-nil, the caller wants the +// reservation there, but SysReserve can still choose another +// location if that one is unavailable. +// +// SysMap maps previously reserved address space for use. void* runtime·SysAlloc(uintptr nbytes); void runtime·SysFree(void *v, uintptr nbytes); void runtime·SysUnused(void *v, uintptr nbytes); -void runtime·SysMemInit(void); +void runtime·SysMap(void *v, uintptr nbytes); +void* runtime·SysReserve(void *v, uintptr nbytes); // FixAlloc is a simple free-list allocator for fixed size objects. // Malloc uses a FixAlloc wrapped around SysAlloc to manages its @@ -176,6 +186,7 @@ struct MStats uint64 sys; // bytes obtained from system (should be sum of xxx_sys below) uint64 nlookup; // number of pointer lookups uint64 nmalloc; // number of mallocs + uint64 nfree; // number of frees // Statistics about malloc heap. // protected by mheap.Lock @@ -193,13 +204,13 @@ struct MStats uint64 mspan_sys; uint64 mcache_inuse; // MCache structures uint64 mcache_sys; - uint64 heapmap_sys; // heap map uint64 buckhash_sys; // profiling bucket hash table // Statistics about garbage collector. // Protected by stopping the world during GC. uint64 next_gc; // next GC (in heap_alloc time) - uint64 pause_ns; + uint64 pause_total_ns; + uint64 pause_ns[256]; uint32 numgc; bool enablegc; bool debuggc; @@ -321,11 +332,13 @@ struct MHeap MSpan *allspans; // span lookup - MHeapMap map; + MSpan *map[1<<MHeapMap_Bits]; // range of addresses we might see in the heap - byte *min; - byte *max; + byte *bitmap; + byte *arena_start; + byte *arena_used; + byte *arena_end; // central free lists for small size classes. // the union makes sure that the MCentrals are @@ -344,18 +357,15 @@ extern MHeap runtime·mheap; void runtime·MHeap_Init(MHeap *h, void *(*allocator)(uintptr)); MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct); void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct); -MSpan* runtime·MHeap_Lookup(MHeap *h, PageID p); -MSpan* runtime·MHeap_LookupMaybe(MHeap *h, PageID p); +MSpan* runtime·MHeap_Lookup(MHeap *h, void *v); +MSpan* runtime·MHeap_LookupMaybe(MHeap *h, void *v); void runtime·MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj); +void* runtime·MHeap_SysAlloc(MHeap *h, uintptr n); void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed); int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref); void runtime·gc(int32 force); -void* runtime·SysAlloc(uintptr); -void runtime·SysUnused(void*, uintptr); -void runtime·SysFree(void*, uintptr); - enum { RefcountOverhead = 4, // one uint32 per object diff --git a/src/pkg/runtime/malloc_defs.go b/src/pkg/runtime/malloc_defs.go deleted file mode 100644 index bfb96f409..000000000 --- a/src/pkg/runtime/malloc_defs.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is malloc.h - -package runtime - -import "unsafe" - -const ( - pageShift = 12 - pageSize = 1 << pageShift - pageMask = pageSize - 1 -) - -type pageID uintptr - -const ( - numSizeClasses = 67 - maxSmallSize = 32 << 10 - fixAllocChunk = 128 << 10 - maxMCacheListLen = 256 - maxMCacheSize = 2 << 20 - maxMHeapList = 1 << 8 // 1 << (20 - pageShift) - heapAllocChunk = 1 << 20 -) - -type mLink struct { - next *mLink -} - -type fixAlloc struct { - size uintptr - alloc func(uintptr) - first func(unsafe.Pointer, *byte) - arg unsafe.Pointer - list *mLink - chunk *byte - nchunk uint32 - inuse uintptr - sys uintptr -} - - -// MStats? used to be in extern.go - -type mCacheList struct { - list *mLink - nlist uint32 - nlistmin uint32 -} - -type mCache struct { - list [numSizeClasses]mCacheList - size uint64 - local_alloc int64 - local_objects int64 - next_sample int32 -} - -type mSpan struct { - next *mSpan - prev *mSpan - allnext *mSpan - start pageID - npages uintptr - freelist *mLink - ref uint32 - sizeclass uint32 - state uint32 - // union { - gcref *uint32 // sizeclass > 0 - // gcref0 uint32; // sizeclass == 0 - // } -} - -type mCentral struct { - lock - sizeclass int32 - nonempty mSpan - empty mSpan - nfree int32 -} - -type mHeap struct { - lock - free [maxMHeapList]mSpan - large mSpan - allspans *mSpan - map_ mHeapMap - min *byte - max *byte - closure_min *byte - closure_max *byte - - central [numSizeClasses]struct { - pad [64]byte - // union: mCentral - } - - spanalloc fixAlloc - cachealloc fixAlloc -} - -const ( - refFree = iota - refStack - refNone - refSome - refcountOverhead = 4 - refNoPointers = 0x80000000 - refHasFinalizer = 0x40000000 - refProfiled = 0x20000000 - refNoProfiling = 0x10000000 - refFlags = 0xFFFF0000 -) - -const ( - mProf_None = iota - mProf_Sample - mProf_All -) - -type finalizer struct { - next *finalizer - fn func(unsafe.Pointer) - arg unsafe.Pointer - nret int32 -} diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c index 8855dc663..f1ad119d3 100644 --- a/src/pkg/runtime/mcentral.c +++ b/src/pkg/runtime/mcentral.c @@ -118,8 +118,7 @@ MCentral_Free(MCentral *c, void *v) int32 size; // Find span for v. - page = (uintptr)v >> PageShift; - s = runtime·MHeap_Lookup(&runtime·mheap, page); + s = runtime·MHeap_Lookup(&runtime·mheap, v); if(s == nil || s->ref == 0) runtime·throw("invalid free"); diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 6dcb61091..af1c721e8 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -76,7 +76,7 @@ scanblock(byte *b, int64 n) obj = vp[i]; if(obj == nil) continue; - if(runtime·mheap.min <= (byte*)obj && (byte*)obj < runtime·mheap.max) { + if(runtime·mheap.arena_start <= (byte*)obj && (byte*)obj < runtime·mheap.arena_end) { if(runtime·mlookup(obj, &obj, &size, nil, &refp)) { ref = *refp; switch(ref & ~RefFlags) { @@ -210,6 +210,7 @@ sweepspan(MSpan *s) case RefNone: // Free large object. mstats.alloc -= s->npages<<PageShift; + mstats.nfree++; runtime·memclr(p, s->npages<<PageShift); if(ref & RefProfiled) runtime·MProf_Free(p, s->npages<<PageShift); @@ -251,6 +252,7 @@ sweepspan(MSpan *s) if(size > sizeof(uintptr)) ((uintptr*)p)[1] = 1; // mark as "needs to be zeroed" mstats.alloc -= size; + mstats.nfree++; mstats.by_size[s->sizeclass].nfree++; runtime·MCache_Free(c, p, s->sizeclass, size); break; @@ -381,7 +383,8 @@ runtime·gc(int32 force) t1 = runtime·nanotime(); mstats.numgc++; - mstats.pause_ns += t1 - t0; + mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t1 - t0; + mstats.pause_total_ns += t1 - t0; if(mstats.debuggc) runtime·printf("pause %D\n", t1-t0); runtime·semrelease(&gcsema); diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c index 4bb7f14e3..0c9ac0a09 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -41,7 +41,6 @@ runtime·MHeap_Init(MHeap *h, void *(*alloc)(uintptr)) runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h); runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil); - runtime·MHeapMap_Init(&h->map, alloc); // h->mapcache needs no init for(i=0; i<nelem(h->free); i++) runtime·MSpanList_Init(&h->free[i]); @@ -79,6 +78,7 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass) { uintptr n; MSpan *s, *t; + PageID p; // Try in fixed-size lists up to max. for(n=npage; n < nelem(h->free); n++) { @@ -112,18 +112,29 @@ HaveSpan: mstats.mspan_sys = h->spanalloc.sys; runtime·MSpan_Init(t, s->start + npage, s->npages - npage); s->npages = npage; - runtime·MHeapMap_Set(&h->map, t->start - 1, s); - runtime·MHeapMap_Set(&h->map, t->start, t); - runtime·MHeapMap_Set(&h->map, t->start + t->npages - 1, t); + p = t->start; + if(sizeof(void*) == 8) + p -= ((uintptr)h->arena_start>>PageShift); + if(p > 0) + h->map[p-1] = s; + h->map[p] = t; + h->map[p+t->npages-1] = t; + *(uintptr*)(t->start<<PageShift) = *(uintptr*)(s->start<<PageShift); // copy "needs zeroing" mark t->state = MSpanInUse; MHeap_FreeLocked(h, t); } + if(*(uintptr*)(s->start<<PageShift) != 0) + runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift); + // Record span info, because gc needs to be // able to map interior pointer to containing span. s->sizeclass = sizeclass; + p = s->start; + if(sizeof(void*) == 8) + p -= ((uintptr)h->arena_start>>PageShift); for(n=0; n<npage; n++) - runtime·MHeapMap_Set(&h->map, s->start+n, s); + h->map[p+n] = s; return s; } @@ -161,6 +172,7 @@ MHeap_Grow(MHeap *h, uintptr npage) uintptr ask; void *v; MSpan *s; + PageID p; // Ask for a big chunk, to reduce the number of mappings // the operating system needs to track; also amortizes @@ -171,29 +183,21 @@ MHeap_Grow(MHeap *h, uintptr npage) if(ask < HeapAllocChunk) ask = HeapAllocChunk; - v = runtime·SysAlloc(ask); + v = runtime·MHeap_SysAlloc(h, ask); if(v == nil) { if(ask > (npage<<PageShift)) { ask = npage<<PageShift; - v = runtime·SysAlloc(ask); + v = runtime·MHeap_SysAlloc(h, ask); } if(v == nil) return false; } mstats.heap_sys += ask; - if((byte*)v < h->min || h->min == nil) - h->min = v; - if((byte*)v+ask > h->max) - h->max = (byte*)v+ask; - - // NOTE(rsc): In tcmalloc, if we've accumulated enough - // system allocations, the heap map gets entirely allocated - // in 32-bit mode. (In 64-bit mode that's not practical.) - if(!runtime·MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) { - runtime·SysFree(v, ask); - return false; - } + if((byte*)v < h->arena_start || h->arena_start == nil) + h->arena_start = v; + if((byte*)v+ask > h->arena_end) + h->arena_end = (byte*)v+ask; // Create a fake "in use" span and free it, so that the // right coalescing happens. @@ -201,35 +205,50 @@ MHeap_Grow(MHeap *h, uintptr npage) mstats.mspan_inuse = h->spanalloc.inuse; mstats.mspan_sys = h->spanalloc.sys; runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift); - runtime·MHeapMap_Set(&h->map, s->start, s); - runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s); + p = s->start; + if(sizeof(void*) == 8) + p -= ((uintptr)h->arena_start>>PageShift); + h->map[p] = s; + h->map[p + s->npages - 1] = s; s->state = MSpanInUse; MHeap_FreeLocked(h, s); return true; } -// Look up the span at the given page number. -// Page number is guaranteed to be in map +// Look up the span at the given address. +// Address is guaranteed to be in map // and is guaranteed to be start or end of span. MSpan* -runtime·MHeap_Lookup(MHeap *h, PageID p) +runtime·MHeap_Lookup(MHeap *h, void *v) { - return runtime·MHeapMap_Get(&h->map, p); + uintptr p; + + p = (uintptr)v; + if(sizeof(void*) == 8) + p -= (uintptr)h->arena_start; + return h->map[p >> PageShift]; } -// Look up the span at the given page number. -// Page number is *not* guaranteed to be in map +// Look up the span at the given address. +// Address is *not* guaranteed to be in map // and may be anywhere in the span. // Map entries for the middle of a span are only // valid for allocated spans. Free spans may have // other garbage in their middles, so we have to // check for that. MSpan* -runtime·MHeap_LookupMaybe(MHeap *h, PageID p) +runtime·MHeap_LookupMaybe(MHeap *h, void *v) { MSpan *s; + PageID p, q; - s = runtime·MHeapMap_GetMaybe(&h->map, p); + if((byte*)v < h->arena_start || (byte*)v >= h->arena_used) + return nil; + p = (uintptr)v>>PageShift; + q = p; + if(sizeof(void*) == 8) + q -= (uintptr)h->arena_start >> PageShift; + s = h->map[q]; if(s == nil || p < s->start || p - s->start >= s->npages) return nil; if(s->state != MSpanInUse) @@ -258,7 +277,9 @@ runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct) static void MHeap_FreeLocked(MHeap *h, MSpan *s) { + uintptr *sp, *tp; MSpan *t; + PageID p; if(s->state != MSpanInUse || s->ref != 0) { runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref); @@ -266,21 +287,30 @@ MHeap_FreeLocked(MHeap *h, MSpan *s) } s->state = MSpanFree; runtime·MSpanList_Remove(s); + sp = (uintptr*)(s->start<<PageShift); // Coalesce with earlier, later spans. - if((t = runtime·MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) { + p = s->start; + if(sizeof(void*) == 8) + p -= (uintptr)h->arena_start >> PageShift; + if(p > 0 && (t = h->map[p-1]) != nil && t->state != MSpanInUse) { + tp = (uintptr*)(t->start<<PageShift); + *tp |= *sp; // propagate "needs zeroing" mark s->start = t->start; s->npages += t->npages; - runtime·MHeapMap_Set(&h->map, s->start, s); + p -= t->npages; + h->map[p] = s; runtime·MSpanList_Remove(t); t->state = MSpanDead; runtime·FixAlloc_Free(&h->spanalloc, t); mstats.mspan_inuse = h->spanalloc.inuse; mstats.mspan_sys = h->spanalloc.sys; } - if((t = runtime·MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) { + if(p+s->npages < nelem(h->map) && (t = h->map[p+s->npages]) != nil && t->state != MSpanInUse) { + tp = (uintptr*)(t->start<<PageShift); + *sp |= *tp; // propagate "needs zeroing" mark s->npages += t->npages; - runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s); + h->map[p + s->npages - 1] = s; runtime·MSpanList_Remove(t); t->state = MSpanDead; runtime·FixAlloc_Free(&h->spanalloc, t); diff --git a/src/pkg/runtime/mheapmap32.c b/src/pkg/runtime/mheapmap32.c deleted file mode 100644 index 323f8b87a..000000000 --- a/src/pkg/runtime/mheapmap32.c +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2009 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. - -// Heap map, 32-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)) -{ - m->allocator = allocator; -} - -MSpan* -runtime·MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Get"); - - return m->p[i1]->s[i2]; -} - -MSpan* -runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2; - MHeapMapNode2 *p2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - return p2->s[i2]; -} - -void -runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2; - - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Set"); - - m->p[i1]->s[i2] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1; - MHeapMapNode2 *p2; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask; - - // first-level pointer - if(m->p[i1] == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - mstats.heapmap_sys += sizeof *p2; - m->p[i1] = p2; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits; - } - return true; -} - diff --git a/src/pkg/runtime/mheapmap32.h b/src/pkg/runtime/mheapmap32.h deleted file mode 100644 index 29e619071..000000000 --- a/src/pkg/runtime/mheapmap32.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009 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. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans. - -typedef struct MHeapMapNode2 MHeapMapNode2; - -enum -{ - // 32 bit address - 12 bit page size = 20 bits to map - MHeapMap_Level1Bits = 10, - MHeapMap_Level2Bits = 10, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits, - - MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1, - MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1, -}; - -struct MHeapMap -{ - void *(*allocator)(uintptr); - MHeapMapNode2 *p[1<<MHeapMap_Level1Bits]; -}; - -struct MHeapMapNode2 -{ - MSpan *s[1<<MHeapMap_Level2Bits]; -}; - -void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)); -bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages); -MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k); -MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k); -void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v); - - diff --git a/src/pkg/runtime/mheapmap32_defs.go b/src/pkg/runtime/mheapmap32_defs.go deleted file mode 100644 index 755725b46..000000000 --- a/src/pkg/runtime/mheapmap32_defs.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2010 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. - -package runtime - -const ( - mHeapMap_Level1Bits = 10 - mHeapMap_Level2Bits = 10 - mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits - - mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1 - mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1 -) - -type mHeapMap struct { - allocator func(uintptr) - p [1 << mHeapMap_Level1Bits]*mHeapMapNode2 -} - -type mHeapMapNode2 struct { - s [1 << mHeapMap_Level2Bits]*mSpan -} diff --git a/src/pkg/runtime/mheapmap64.c b/src/pkg/runtime/mheapmap64.c deleted file mode 100644 index e45ac9413..000000000 --- a/src/pkg/runtime/mheapmap64.c +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2009 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. - -// Heap map, 64-bit version -// See malloc.h and mheap.c for overview. - -#include "runtime.h" -#include "malloc.h" - -// 3-level radix tree mapping page ids to Span*. -void -runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)) -{ - m->allocator = allocator; -} - -MSpan* -runtime·MHeapMap_Get(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Get"); - - return m->p[i1]->p[i2]->s[i3]; -} - -MSpan* -runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k) -{ - int32 i1, i2, i3; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Get"); - - p2 = m->p[i1]; - if(p2 == nil) - return nil; - p3 = p2->p[i2]; - if(p3 == nil) - return nil; - return p3->s[i3]; -} - -void -runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) -{ - int32 i1, i2, i3; - - i3 = k & MHeapMap_Level3Mask; - k >>= MHeapMap_Level3Bits; - i2 = k & MHeapMap_Level2Mask; - k >>= MHeapMap_Level2Bits; - i1 = k & MHeapMap_Level1Mask; - k >>= MHeapMap_Level1Bits; - if(k != 0) - runtime·throw("MHeapMap_Set"); - - m->p[i1]->p[i2]->s[i3] = s; -} - -// Allocate the storage required for entries [k, k+1, ..., k+len-1] -// so that Get and Set calls need not check for nil pointers. -bool -runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) -{ - uintptr end; - int32 i1, i2; - MHeapMapNode2 *p2; - MHeapMapNode3 *p3; - - end = k+len; - while(k < end) { - if((k >> MHeapMap_TotalBits) != 0) - return false; - i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask; - i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask; - - // first-level pointer - if((p2 = m->p[i1]) == nil) { - p2 = m->allocator(sizeof *p2); - if(p2 == nil) - return false; - mstats.heapmap_sys += sizeof *p2; - m->p[i1] = p2; - } - - // second-level pointer - if(p2->p[i2] == nil) { - p3 = m->allocator(sizeof *p3); - if(p3 == nil) - return false; - mstats.heapmap_sys += sizeof *p3; - p2->p[i2] = p3; - } - - // advance key past this leaf node - k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits; - } - return true; -} - diff --git a/src/pkg/runtime/mheapmap64.h b/src/pkg/runtime/mheapmap64.h deleted file mode 100644 index a9934d2b1..000000000 --- a/src/pkg/runtime/mheapmap64.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2009 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. - -// Free(v) must be able to determine the MSpan containing v. -// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans. -// -// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers), -// we can swap in a 2-level radix tree. -// -// NOTE(rsc): We use a 3-level tree because tcmalloc does, but -// having only three levels requires approximately 1 MB per node -// in the tree, making the minimum map footprint 3 MB. -// Using a 4-level tree would cut the minimum footprint to 256 kB. -// On the other hand, it's just virtual address space: most of -// the memory is never going to be touched, thus never paged in. - -typedef struct MHeapMapNode2 MHeapMapNode2; -typedef struct MHeapMapNode3 MHeapMapNode3; - -enum -{ - // 64 bit address - 12 bit page size = 52 bits to map - MHeapMap_Level1Bits = 18, - MHeapMap_Level2Bits = 18, - MHeapMap_Level3Bits = 16, - - MHeapMap_TotalBits = - MHeapMap_Level1Bits + - MHeapMap_Level2Bits + - MHeapMap_Level3Bits, - - MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1, - MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1, - MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1, -}; - -struct MHeapMap -{ - void *(*allocator)(uintptr); - MHeapMapNode2 *p[1<<MHeapMap_Level1Bits]; -}; - -struct MHeapMapNode2 -{ - MHeapMapNode3 *p[1<<MHeapMap_Level2Bits]; -}; - -struct MHeapMapNode3 -{ - MSpan *s[1<<MHeapMap_Level3Bits]; -}; - -void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)); -bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages); -MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k); -MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k); -void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v); - - diff --git a/src/pkg/runtime/mheapmap64_defs.go b/src/pkg/runtime/mheapmap64_defs.go deleted file mode 100644 index d7ba2b420..000000000 --- a/src/pkg/runtime/mheapmap64_defs.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2010 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. - -package runtime - -const ( - mHeapMap_Level1Bits = 18 - mHeapMap_Level2Bits = 18 - mHeapMap_Level3Bits = 16 - mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits + mHeapMap_Level3Bits - - mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1 - mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1 - mHeapMap_Level3Mask = (1 << mHeapMap_Level3Bits) - 1 -) - -type mHeapMap struct { - allocator func(uintptr) - p [1 << mHeapMap_Level1Bits]*mHeapMapNode2 -} - - -type mHeapMapNode2 struct { - p [1 << mHeapMap_Level2Bits]*mHeapMapNode3 -} - - -type mHeapMapNode3 struct { - s [1 << mHeapMap_Level3Bits]*mSpan -} diff --git a/src/pkg/runtime/mkgodefs.sh b/src/pkg/runtime/mkgodefs.sh new file mode 100755 index 000000000..b6e97213e --- /dev/null +++ b/src/pkg/runtime/mkgodefs.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Copyright 2011 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. + +set -e + +cat <<EOF +// Go definitions for C variables and types. +// AUTOMATICALLY GENERATED BY THE FOLLOWING COMMAND. DO NOT EDIT. +// CC="$CC" CFLAGS="$CFLAGS" ./mkgodefs.sh $@ + +package runtime +import "unsafe" +var _ unsafe.Pointer + +EOF + +for i in "$@"; do + $CC $CFLAGS -q $i +done | awk ' +/^func/ { next } +/^const/ { next } +/^\/\/.*type/ { next } + +/^(const|func|type|var) / { + if(seen[$2]++) { + skip = /{[^}]*$/; + next; + } +} + +skip { + skip = !/^}/ + next; +} + +{print} +' diff --git a/src/pkg/runtime/plan9/runtime_defs.go b/src/pkg/runtime/plan9/runtime_defs.go deleted file mode 100644 index cf0b414a9..000000000 --- a/src/pkg/runtime/plan9/runtime_defs.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is runtime.h - -package runtime - -type lock struct { - key uint32 - sema uint32 -} - -type usema struct { - u uint32 - k uint32 -} - - -type note struct { - wakeup int32 - sema usema -} diff --git a/src/pkg/runtime/pprof/pprof.go b/src/pkg/runtime/pprof/pprof.go index d0cc73089..9bee51128 100644 --- a/src/pkg/runtime/pprof/pprof.go +++ b/src/pkg/runtime/pprof/pprof.go @@ -88,7 +88,6 @@ func WriteHeapProfile(w io.Writer) os.Error { fmt.Fprintf(b, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) fmt.Fprintf(b, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) fmt.Fprintf(b, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) - fmt.Fprintf(b, "# MHeapMapSys = %d\n", s.MHeapMapSys) fmt.Fprintf(b, "# BuckHashSys = %d\n", s.BuckHashSys) fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC) diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index e9a19d950..998cbc7bc 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -470,8 +470,8 @@ scheduler(void) d = gp->defer; gp->defer = d->link; - // unwind to the stack frame with d->sp in it. - unwindstack(gp, d->sp); + // unwind to the stack frame with d's arguments in it. + unwindstack(gp, d->argp); // make the deferproc for this d return again, // this time returning 1. function will jump to @@ -481,7 +481,11 @@ scheduler(void) // each call to deferproc. // (the pc we're returning to does pop pop // before it tests the return value.) - gp->sched.sp = runtime·getcallersp(d->sp - 2*sizeof(uintptr)); + // on the arm there are 2 saved LRs mixed in too. + if(thechar == '5') + gp->sched.sp = (byte*)d->argp - 4*sizeof(uintptr); + else + gp->sched.sp = (byte*)d->argp - 2*sizeof(uintptr); gp->sched.pc = d->pc; gp->status = Grunning; runtime·free(d); @@ -633,7 +637,6 @@ void runtime·startcgocallback(G* g1) { Defer *d; - uintptr arg; runtime·lock(&runtime·sched); g1->status = Grunning; @@ -675,80 +678,11 @@ runtime·endcgocallback(G* g1) runtime·free(d); } -/* - * stack layout parameters. - * known to linkers. - * - * g->stackguard is set to point StackGuard bytes - * above the bottom of the stack. each function - * compares its stack pointer against g->stackguard - * to check for overflow. to cut one instruction from - * the check sequence for functions with tiny frames, - * the stack is allowed to protrude StackSmall bytes - * below the stack guard. functions with large frames - * don't bother with the check and always call morestack. - * the sequences are: - * - * guard = g->stackguard - * frame = function's stack frame size - * argsize = size of function arguments (call + return) - * - * stack frame size <= StackSmall: - * CMPQ guard, SP - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size > StackSmall but < StackBig - * LEAQ (frame-StackSmall)(SP), R0 - * CMPQ guard, R0 - * JHI 3(PC) - * MOVQ m->morearg, $(argsize << 32) - * CALL sys.morestack(SB) - * - * stack frame size >= StackBig: - * MOVQ m->morearg, $((argsize << 32) | frame) - * CALL sys.morestack(SB) - * - * the bottom StackGuard - StackSmall bytes are important: - * there has to be enough room to execute functions that - * refuse to check for stack overflow, either because they - * need to be adjacent to the actual caller's frame (sys.deferproc) - * or because they handle the imminent stack overflow (sys.morestack). - * - * for example, sys.deferproc might call malloc, - * which does one of the above checks (without allocating a full frame), - * which might trigger a call to sys.morestack. - * this sequence needs to fit in the bottom section of the stack. - * on amd64, sys.morestack's frame is 40 bytes, and - * sys.deferproc's frame is 56 bytes. that fits well within - * the StackGuard - StackSmall = 128 bytes at the bottom. - * there may be other sequences lurking or yet to be written - * that require more stack. sys.morestack checks to make sure - * the stack has not completely overflowed and should - * catch such sequences. - */ -enum -{ - // byte offset of stack guard (g->stackguard) above bottom of stack. - StackGuard = 256, - - // checked frames are allowed to protrude below the guard by - // this many bytes. this saves an instruction in the checking - // sequence when the stack frame is tiny. - StackSmall = 128, - - // extra space in the frame (beyond the function for which - // the frame is allocated) is assumed not to be much bigger - // than this amount. it may not be used efficiently if it is. - StackBig = 4096, -}; - void runtime·oldstack(void) { Stktop *top, old; - uint32 args; + uint32 argsize; byte *sp; G *g1; static int32 goid; @@ -759,15 +693,15 @@ runtime·oldstack(void) top = (Stktop*)g1->stackbase; sp = (byte*)top; old = *top; - args = old.args; - if(args > 0) { - sp -= args; - runtime·mcpy(top->fp, sp, args); + argsize = old.argsize; + if(argsize > 0) { + sp -= argsize; + runtime·mcpy(top->argp, sp, argsize); } goid = old.gobuf.g->goid; // fault if g is bad, before gogo - if(old.free) - runtime·stackfree(g1->stackguard - StackGuard); + if(old.free != 0) + runtime·stackfree(g1->stackguard - StackGuard, old.free); g1->stackbase = old.stackbase; g1->stackguard = old.stackguard; @@ -777,40 +711,45 @@ runtime·oldstack(void) void runtime·newstack(void) { - int32 frame, args; + int32 framesize, argsize; Stktop *top; byte *stk, *sp; G *g1; Gobuf label; - bool free; + bool reflectcall; + uintptr free; - frame = m->moreframe; - args = m->moreargs; + framesize = m->moreframesize; + argsize = m->moreargsize; g1 = m->curg; - if(m->morebuf.sp < g1->stackguard - StackGuard) - runtime·throw("split stack overflow"); + if(m->morebuf.sp < g1->stackguard - StackGuard) { + runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, g1->stackguard - StackGuard); + runtime·throw("runtime: split stack overflow"); + } + + reflectcall = framesize==1; + if(reflectcall) + framesize = 0; - if(frame == 1 && args > 0 && m->morebuf.sp - sizeof(Stktop) - args - 32 > g1->stackguard) { - // special case: called from reflect.call (frame == 1) + if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > g1->stackguard) { + // special case: called from reflect.call (framesize==1) // to call code with an arbitrary argument size, // and we have enough space on the current stack. // the new Stktop* is necessary to unwind, but // we don't need to create a new segment. top = (Stktop*)(m->morebuf.sp - sizeof(*top)); stk = g1->stackguard - StackGuard; - free = false; + free = 0; } else { // allocate new segment. - if(frame == 1) // failed reflect.call hint - frame = 0; - frame += args; - if(frame < StackBig) - frame = StackBig; - frame += 1024; // room for more functions, Stktop. - stk = runtime·stackalloc(frame); - top = (Stktop*)(stk+frame-sizeof(*top)); - free = true; + framesize += argsize; + if(framesize < StackBig) + framesize = StackBig; + framesize += StackExtra; // room for more functions, Stktop. + stk = runtime·stackalloc(framesize); + top = (Stktop*)(stk+framesize-sizeof(*top)); + free = framesize; } //printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", @@ -819,8 +758,8 @@ runtime·newstack(void) top->stackbase = g1->stackbase; top->stackguard = g1->stackguard; top->gobuf = m->morebuf; - top->fp = m->morefp; - top->args = args; + top->argp = m->moreargp; + top->argsize = argsize; top->free = free; // copy flag from panic @@ -831,9 +770,14 @@ runtime·newstack(void) g1->stackguard = stk + StackGuard; sp = (byte*)top; - if(args > 0) { - sp -= args; - runtime·mcpy(sp, m->morefp, args); + if(argsize > 0) { + sp -= argsize; + runtime·mcpy(sp, m->moreargp, argsize); + } + if(thechar == '5') { + // caller would have saved its LR below args. + sp -= sizeof(void*); + *(void**)sp = nil; } // Continue as if lessstack had just called m->morepc @@ -876,7 +820,13 @@ runtime·malg(int32 stacksize) void runtime·newproc(int32 siz, byte* fn, ...) { - runtime·newproc1(fn, (byte*)(&fn+1), siz, 0); + byte *argp; + + if(thechar == '5') + argp = (byte*)(&fn+2); // skip caller's saved LR + else + argp = (byte*)(&fn+1); + runtime·newproc1(fn, argp, siz, 0); } G* @@ -899,7 +849,7 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) if(newg->stackguard - StackGuard != newg->stack0) runtime·throw("invalid stack in newg"); } else { - newg = runtime·malg(4096); + newg = runtime·malg(StackBig); newg->status = Gwaiting; newg->alllink = runtime·allg; runtime·allg = newg; @@ -908,6 +858,11 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret) sp = newg->stackbase; sp -= siz; runtime·mcpy(sp, argp, narg); + if(thechar == '5') { + // caller's LR + sp -= sizeof(void*); + *(void**)sp = nil; + } newg->sched.sp = sp; newg->sched.pc = (byte*)runtime·goexit; @@ -933,10 +888,13 @@ runtime·deferproc(int32 siz, byte* fn, ...) d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args)); d->fn = fn; - d->sp = (byte*)(&fn+1); d->siz = siz; d->pc = runtime·getcallerpc(&siz); - runtime·mcpy(d->args, d->sp, d->siz); + if(thechar == '5') + d->argp = (byte*)(&fn+2); // skip caller's saved link register + else + d->argp = (byte*)(&fn+1); + runtime·mcpy(d->args, d->argp, d->siz); d->link = g->defer; g->defer = d; @@ -955,19 +913,19 @@ void runtime·deferreturn(uintptr arg0) { Defer *d; - byte *sp, *fn; + byte *argp, *fn; d = g->defer; if(d == nil) return; - sp = runtime·getcallersp(&arg0); - if(d->sp != sp) + argp = (byte*)&arg0; + if(d->argp != argp) return; - runtime·mcpy(d->sp, d->args, d->siz); + runtime·mcpy(argp, d->args, d->siz); g->defer = d->link; fn = d->fn; runtime·free(d); - runtime·jmpdefer(fn, sp); + runtime·jmpdefer(fn, argp); } static void @@ -983,7 +941,7 @@ rundefer(void) } // Free stack frames until we hit the last one -// or until we find the one that contains the sp. +// or until we find the one that contains the argp. static void unwindstack(G *gp, byte *sp) { @@ -1000,8 +958,8 @@ unwindstack(G *gp, byte *sp) break; gp->stackbase = top->stackbase; gp->stackguard = top->stackguard; - if(top->free) - runtime·stackfree(stk); + if(top->free != 0) + runtime·stackfree(stk, top->free); } if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) { @@ -1043,12 +1001,11 @@ runtime·panic(Eface e) // take defer off list in case of recursive panic g->defer = d->link; g->ispanic = true; // rock for newstack, where reflect.call ends up - if(thechar == '5') - reflect·call(d->fn, d->args+4, d->siz-4); // reflect.call does not expect LR - else - reflect·call(d->fn, d->args, d->siz); + reflect·call(d->fn, d->args, d->siz); if(p->recovered) { g->panic = p->link; + if(g->panic == nil) // must be done with signal + g->sig = 0; runtime·free(p); // put recovering defer back on list // for scheduler to find. @@ -1068,13 +1025,11 @@ runtime·panic(Eface e) #pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */ void -runtime·recover(byte *fp, Eface ret) +runtime·recover(byte *argp, Eface ret) { Stktop *top, *oldtop; Panic *p; - fp = runtime·getcallersp(fp); - // Must be a panic going on. if((p = g->panic) == nil || p->recovered) goto nomatch; @@ -1097,11 +1052,11 @@ runtime·recover(byte *fp, Eface ret) // allocated a second segment (see below), // the fp is slightly above top - top->args. // That condition can't happen normally though - // (stack pointer go down, not up), so we can accept + // (stack pointers go down, not up), so we can accept // any fp between top and top - top->args as // indicating the top of the segment. top = (Stktop*)g->stackbase; - if(fp < (byte*)top - top->args || (byte*)top < fp) + if(argp < (byte*)top - top->argsize || (byte*)top < argp) goto nomatch; // The deferred call makes a new segment big enough @@ -1117,7 +1072,7 @@ runtime·recover(byte *fp, Eface ret) // bytes above top->fp) abuts the old top of stack. // This is a correct test for both closure and non-closure code. oldtop = (Stktop*)top->stackbase; - if(oldtop != nil && top->fp == (byte*)oldtop - top->args) + if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize) top = oldtop; // Now we have the segment that was created to @@ -1237,3 +1192,9 @@ runtime·Goroutines(int32 ret) ret = runtime·sched.gcount; FLUSH(&ret); } + +int32 +runtime·mcount(void) +{ + return runtime·sched.mcount; +} diff --git a/src/pkg/runtime/reflect.goc b/src/pkg/runtime/reflect.goc index a2e3c6ee1..71d648266 100644 --- a/src/pkg/runtime/reflect.goc +++ b/src/pkg/runtime/reflect.goc @@ -75,7 +75,7 @@ func chansend(ch *byte, val *byte, pres *bool) { } func chanrecv(ch *byte, val *byte, pres *bool) { - runtime·chanrecv((Hchan*)ch, val, pres); + runtime·chanrecv((Hchan*)ch, val, pres, nil); } func chanclose(ch *byte) { diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py index a7ca94cdb..677e9bde4 100644 --- a/src/pkg/runtime/runtime-gdb.py +++ b/src/pkg/runtime/runtime-gdb.py @@ -161,7 +161,7 @@ def is_iface(val): def is_eface(val): try: - return str(val['type_'].type) == "runtime.Type *" \ + return str(val['_type'].type) == "struct runtime._type *" \ and str(val['data'].type) == "void *" except: pass @@ -185,14 +185,14 @@ def iface_dtype(obj): "Decode type of the data field of an eface or iface struct." if is_iface(obj): - go_type_ptr = obj['tab']['Type'] + go_type_ptr = obj['tab']['_type'] elif is_eface(obj): - go_type_ptr = obj['type_'] + go_type_ptr = obj['_type'] else: return ct = gdb.lookup_type("struct runtime.commonType").pointer() - dynamic_go_type = go_type_ptr['data'].cast(ct).dereference() + dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference() dtype_name = dynamic_go_type['string'].dereference()['str'].string() type_size = int(dynamic_go_type['size']) uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c index 9d3efe966..284b1e458 100644 --- a/src/pkg/runtime/runtime.c +++ b/src/pkg/runtime/runtime.c @@ -30,11 +30,16 @@ runtime·dopanic(int32 unused) } runtime·panicking++; - runtime·printf("\npanic PC=%X\n", (uint64)(uintptr)&unused); + if(g->sig != 0) + runtime·printf("\n[signal %x code=%p addr=%p pc=%p]\n", + g->sig, g->sigcode0, g->sigcode1, g->sigpc); + + runtime·printf("\n"); if(runtime·gotraceback()){ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g); runtime·tracebackothers(g); } + runtime·breakpoint(); // so we can grab it in a debugger runtime·exit(2); } @@ -79,6 +84,10 @@ runtime·panicstring(int8 *s) { Eface err; + if(m->gcing) { + runtime·printf("panic: %s\n", s); + runtime·throw("panic during gc"); + } runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err); runtime·panic(err); } @@ -148,6 +157,7 @@ runtime·args(int32 c, uint8 **v) } int32 runtime·isplan9; +int32 runtime·iswindows; void runtime·goargs(void) diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index bde62833e..2c19f851e 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -63,7 +63,7 @@ typedef struct Eface Eface; typedef struct Type Type; typedef struct Defer Defer; typedef struct Panic Panic; -typedef struct hash Hmap; +typedef struct Hmap Hmap; typedef struct Hchan Hchan; typedef struct Complex64 Complex64; typedef struct Complex128 Complex128; @@ -199,18 +199,19 @@ struct G int32 sig; uintptr sigcode0; uintptr sigcode1; + uintptr sigpc; }; struct M { // The offsets of these fields are known to (hard-coded in) libmach. G* g0; // goroutine with scheduling stack void (*morepc)(void); - void* morefp; // frame pointer for more stack + void* moreargp; // argument pointer for more stack Gobuf morebuf; // gobuf arg to morestack // Fields not known to debuggers. - uint32 moreframe; // size arguments to morestack - uint32 moreargs; + uint32 moreframesize; // size arguments to morestack + uint32 moreargsize; uintptr cret; // return value from C uint64 procid; // for debuggers, but offset not hard-coded G* gsignal; // signal-handling G @@ -234,7 +235,7 @@ struct M uint32 freghi[16]; // D[i] msb and F[i+16] uint32 fflag; // floating point compare flags #ifdef __WINDOWS__ - void* gostack; // bookmark to keep track of go stack during stdcall + void* sehframe; #endif }; struct Stktop @@ -243,13 +244,10 @@ struct Stktop uint8* stackguard; uint8* stackbase; Gobuf gobuf; - uint32 args; + uint32 argsize; - // Frame pointer: where args start in old frame. - // fp == gobuf.sp except in the case of a reflected - // function call, which uses an off-stack argument frame. - uint8* fp; - bool free; // call stackfree for this frame? + uint8* argp; // pointer to arguments in old frame + uintptr free; // if free>0, call stackfree using free as size bool panic; // is this frame the top of a panic? }; struct Alg @@ -333,7 +331,7 @@ enum { struct Defer { int32 siz; - byte* sp; + byte* argp; // where args were copied from byte* pc; byte* fn; Defer* link; @@ -423,7 +421,7 @@ void runtime·minit(void); Func* runtime·findfunc(uintptr); int32 runtime·funcline(Func*, uint64); void* runtime·stackalloc(uint32); -void runtime·stackfree(void*); +void runtime·stackfree(void*, uintptr); MCache* runtime·allocmcache(void); void runtime·mallocinit(void); bool runtime·ifaceeq_c(Iface, Iface); @@ -438,13 +436,14 @@ void runtime·addfinalizer(void*, void(*fn)(void*), int32); void runtime·walkfintab(void (*fn)(void*)); void runtime·runpanic(Panic*); void* runtime·getcallersp(void*); +int32 runtime·mcount(void); void runtime·exit(int32); void runtime·breakpoint(void); void runtime·gosched(void); void runtime·goexit(void); void runtime·runcgo(void (*fn)(void*), void*); -void runtime·runcgocallback(G*, void*, void (*fn)()); +uintptr runtime·runcgocallback(G*, void*, void (*fn)()); void runtime·entersyscall(void); void runtime·exitsyscall(void); void runtime·startcgocallback(G*); @@ -508,11 +507,11 @@ void runtime·notewakeup(Note*); #define EACCES 13 /* - * low level go-called + * low level C-called */ uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32); void runtime·munmap(uint8*, uintptr); -void runtime·memclr(byte*, uint32); +void runtime·memclr(byte*, uintptr); void runtime·setcallerpc(void*, void*); void* runtime·getcallerpc(void*); @@ -583,10 +582,91 @@ Hmap* runtime·makemap_c(Type*, Type*, int64); Hchan* runtime·makechan_c(Type*, int64); void runtime·chansend(Hchan*, void*, bool*); -void runtime·chanrecv(Hchan*, void*, bool*); +void runtime·chanrecv(Hchan*, void*, bool*, bool*); void runtime·chanclose(Hchan*); bool runtime·chanclosed(Hchan*); int32 runtime·chanlen(Hchan*); int32 runtime·chancap(Hchan*); void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*); + +/* + * Stack layout parameters. + * Known to linkers. + * + * The per-goroutine g->stackguard is set to point + * StackGuard bytes above the bottom of the stack. + * Each function compares its stack pointer against + * g->stackguard to check for overflow. To cut one + * instruction from the check sequence for functions + * with tiny frames, the stack is allowed to protrude + * StackSmall bytes below the stack guard. Functions + * with large frames don't bother with the check and + * always call morestack. The sequences are + * (for amd64, others are similar): + * + * guard = g->stackguard + * frame = function's stack frame size + * argsize = size of function arguments (call + return) + * + * stack frame size <= StackSmall: + * CMPQ guard, SP + * JHI 3(PC) + * MOVQ m->morearg, $(argsize << 32) + * CALL morestack(SB) + * + * stack frame size > StackSmall but < StackBig + * LEAQ (frame-StackSmall)(SP), R0 + * CMPQ guard, R0 + * JHI 3(PC) + * MOVQ m->morearg, $(argsize << 32) + * CALL morestack(SB) + * + * stack frame size >= StackBig: + * MOVQ m->morearg, $((argsize << 32) | frame) + * CALL morestack(SB) + * + * The bottom StackGuard - StackSmall bytes are important: + * there has to be enough room to execute functions that + * refuse to check for stack overflow, either because they + * need to be adjacent to the actual caller's frame (deferproc) + * or because they handle the imminent stack overflow (morestack). + * + * For example, deferproc might call malloc, which does one + * of the above checks (without allocating a full frame), + * which might trigger a call to morestack. This sequence + * needs to fit in the bottom section of the stack. On amd64, + * morestack's frame is 40 bytes, and deferproc's frame is 56 bytes. + * That fits well within the StackGuard - StackSmall = 128 bytes + * at the bottom. There may be other sequences lurking or yet to + * be written that require more stack. Morestack checks to make + * sure the stack has not completely overflowed and should catch + * such sequences. + */ +enum +{ +#ifdef __WINDOWS__ + // need enough room in guard area for exception handler. + // use larger stacks to compensate for larger stack guard. + StackSmall = 256, + StackGuard = 2048, + StackBig = 8192, + StackExtra = StackGuard, +#else + // byte offset of stack guard (g->stackguard) above bottom of stack. + StackGuard = 256, + + // checked frames are allowed to protrude below the guard by + // this many bytes. this saves an instruction in the checking + // sequence when the stack frame is tiny. + StackSmall = 128, + + // extra space in the frame (beyond the function for which + // the frame is allocated) is assumed not to be much bigger + // than this amount. it may not be used efficiently if it is. + StackBig = 4096, + + // extra room over frame size when allocating a stack. + StackExtra = 1024, +#endif +}; diff --git a/src/pkg/runtime/runtime_defs.go b/src/pkg/runtime/runtime_defs.go deleted file mode 100644 index ba3c3ed75..000000000 --- a/src/pkg/runtime/runtime_defs.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is runtime.h - -// TODO(lvd): automate conversion to all the _defs.go files - -package runtime - -import "unsafe" - -const ( - gidle = iota - grunnable - grunning - gsyscall - gwaiting - gmoribund - gdead - grecovery -) - -// const ( Structrnd = sizeof(uintptr) ) - -type string_ struct { - str *byte - len int32 -} - -type iface struct { - tab *itab - data unsafe.Pointer -} - -type eface struct { - type_ *Type - data unsafe.Pointer -} - -type complex64 struct { - real float32 - imag float32 -} - -type complex128 struct { - real float64 - imag float64 -} - -type slice struct { - array *byte - len uint32 - cap uint32 -} - -type gobuf struct { - sp unsafe.Pointer - pc unsafe.Pointer - g *g_ -} - -type g_ struct { - stackguard unsafe.Pointer - stackbase unsafe.Pointer - defer_ *defer_ - panic_ *panic_ - sched gobuf - stack0 unsafe.Pointer - entry unsafe.Pointer - alllink *g_ - param unsafe.Pointer - status int16 - goid int32 - selgen uint32 - schedlink *g_ - readyonstop bool - ispanic bool - m *m_ - lockedm *m_ - sig int32 - sigcode0 uintptr - sigcode1 uintptr -} - -type m_ struct { - g0 *g_ - morepc unsafe.Pointer - morefp unsafe.Pointer - morebuf gobuf - moreframe uint32 - moreargs uint32 - cret uintptr - procid uint64 - gsignal *g_ - tls [8]uint32 - sched gobuf - curg *g_ - id int32 - mallocing int32 - gcing int32 - locks int32 - nomemprof int32 - waitnextg int32 - havenextg note - nextg *g_ - alllink *m_ - schedlink *m_ - machport uint32 - mcache *mCache - lockedg *g_ - freg [8]uint64 - // gostack unsafe.Pointer // __WINDOWS__ -} - -type stktop struct { - stackguard *uint8 - stackbase *uint8 - gobuf gobuf - args uint32 - fp *uint8 - free bool - panic_ bool -} - -type alg struct { - hash func(uint32, unsafe.Pointer) uintptr - equal func(uint32, unsafe.Pointer, unsafe.Pointer) uint32 - print func(uint32, unsafe.Pointer) - copy func(uint32, unsafe.Pointer, unsafe.Pointer) -} - -type sigtab struct { - flags int32 - name *int8 -} - -const ( - sigCatch = (1 << iota) - sigIgnore - sigRestart - sigQueue - sigPanic -) - -type Func struct { - name string - typ string - src string - pcln []byte - entry uintptr - pc0 uintptr - ln0 int32 - frame int32 - args int32 - locals int32 -} - -const ( - aMEM = iota - aNOEQ - aSTRING - aINTER - aNILINTER - aMEMWORD - amax -) - -type defer_ struct { - siz int32 - sp unsafe.Pointer - pc unsafe.Pointer - fn unsafe.Pointer - link *defer_ - args [8]byte // padded to actual size -} - -type panic_ struct { - arg eface - stackbase unsafe.Pointer - link *panic_ - recovered bool -} - -/* - * External data. - */ - -var ( - algarray [amax]alg - emptystring string - allg *g_ - allm *m_ - goidgen int32 - gomaxprocs int32 - panicking int32 - fd int32 - gcwaiting int32 - goos *int8 -) diff --git a/src/pkg/runtime/tiny/386/defs.h b/src/pkg/runtime/tiny/386/defs.h deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/386/defs.h +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/386/rt0.s b/src/pkg/runtime/tiny/386/rt0.s deleted file mode 100644 index 524ac7664..000000000 --- a/src/pkg/runtime/tiny/386/rt0.s +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2010 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. - -TEXT _rt0_386_tiny(SB), 7, $0 - // Disable interrupts. - CLI - - // Establish stack. - MOVL $0x10000, AX - MOVL AX, SP - - // Set up memory hardware. - CALL runtime·msetup(SB) - - // _rt0_386 expects to find argc, argv, envv on stack. - // Set up argv=["kernel"] and envv=[]. - SUBL $64, SP - MOVL $1, 0(SP) - MOVL $runtime·kernel(SB), 4(SP) - MOVL $0, 8(SP) - MOVL $0, 12(SP) - JMP _rt0_386(SB) - -DATA runtime·kernel(SB)/7, $"kernel\z" -GLOBL runtime·kernel(SB), $7 - - diff --git a/src/pkg/runtime/tiny/386/signal.c b/src/pkg/runtime/tiny/386/signal.c deleted file mode 100644 index 88e634e9d..000000000 --- a/src/pkg/runtime/tiny/386/signal.c +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" - -extern void runtime·write(int32 fd, void *v, int32 len, int32 cap); // slice, spelled out - -int32 -runtime·write(int32 fd, void *v, int32 len) -{ - runtime·write(fd, v, len, len); - return len; -} - -void -runtime·gettime(int64*, int32*) -{ -} diff --git a/src/pkg/runtime/tiny/386/sys.s b/src/pkg/runtime/tiny/386/sys.s deleted file mode 100644 index 851171476..000000000 --- a/src/pkg/runtime/tiny/386/sys.s +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2010 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. - -// Manipulation of segment tables. -// -// Descriptor entry format for system call -// is the native machine format, ugly as it is: -// -// 2-byte limit -// 3-byte base -// 1-byte: 0x80=present, 0x60=dpl<<5, 0x1F=type -// 1-byte: 0x80=limit is *4k, 0x40=32-bit operand size, -// 0x0F=4 more bits of limit -// 1 byte: 8 more bits of base - -// Called to set up memory hardware. -// Already running in 32-bit mode thanks to boot block, -// but we need to install our new GDT that we can modify. -TEXT runtime·msetup(SB), 7, $0 - MOVL runtime·gdtptr(SB), GDTR - MOVL $(1*8+0), AX - MOVW AX, DS - MOVW AX, ES - MOVW AX, SS - MOVW $0, AX - MOVW AX, FS - MOVW AX, GS - - // long jmp to cs:mret - BYTE $0xEA - LONG $runtime·mret(SB) - WORD $(2*8+0) - -TEXT runtime·mret(SB), 7, $0 - RET - -// GDT memory -TEXT runtime·gdt(SB), 7, $0 - // null segment - LONG $0 - LONG $0 - - // 4GB data segment - LONG $0xFFFF - LONG $0x00CF9200 - - // 4GB code segment - LONG $0xFFFF - LONG $0x00CF9A00 - - // null segment (will be thread-local storage segment) - LONG $0 - LONG $0 - -// GDT pseudo-descriptor -TEXT runtime·gdtptr(SB), 7, $0 - WORD $(4*8) - LONG $runtime·gdt(SB) - -// Called to establish the per-thread segment. -// Write to gdt[3] and reload the gdt register. -// setldt(int entry, int address, int limit) -TEXT runtime·setldt(SB),7,$32 - MOVL address+4(FP), BX // aka base - MOVL limit+8(FP), CX - - // set up segment descriptor - LEAL gdt+(3*8)(SB), AX // gdt entry #3 - MOVL $0, 0(AX) - MOVL $0, 4(AX) - - MOVW BX, 2(AX) - SHRL $16, BX - MOVB BX, 4(AX) - SHRL $8, BX - MOVB BX, 7(AX) - - MOVW CX, 0(AX) - SHRL $16, CX - ANDL $0x0F, CX - ORL $0x40, CX // 32-bit operand size - MOVB CX, 6(AX) - MOVB $0xF2, 5(AX) // r/w data descriptor, dpl=3, present - - MOVL runtime·gdtptr(SB), GDTR - - // Compute segment selector - (entry*8+0) - MOVL $(3*8+0), AX - MOVW AX, GS - RET - diff --git a/src/pkg/runtime/tiny/README b/src/pkg/runtime/tiny/README deleted file mode 100755 index cf001d1e6..000000000 --- a/src/pkg/runtime/tiny/README +++ /dev/null @@ -1,123 +0,0 @@ -This directory contains a simple example of how one might -start Go running on bare hardware. There is currently code -for 386 and arm. - - -386 - -It is very primitive but can run go/test/sieve.go, the concurrent -prime sieve, on a uniprocessor. - -To run, first build the tools by running all.bash with GOARCH=386 -and GOOS set to your normal GOOS (linux, darwin). Then: - - export GOOS=tiny - cd $GOROOT/src/pkg/runtime - make clean - make install - cd tiny - 8g $GOROOT/test/sieve.go - 8l sieve.8 - 8l -a sieve.8 >sieve.asm # can consult sieve.asm for debugging - dd if=/dev/zero of=disk count=10000 - cat bootblock 8.out | dd of=disk conv=notrunc - -Use the built-in print(text string) function to print to the -console. - - -BOCHS - -You may have to tweak the .bochsrc depending on your system, -and you may need to install the Bochs emulator. - - $ cp dot-bochsrc .bochsrc - $ $EDITOR .bochsrc # tweak it if required - $ bochs - - -ORACLE xVM VIRTUALBOX - -Install VirtualBox. Then: - - Build 'disk' (described above under '386'). - - $ VBoxManage convertfromraw disk go-tiny.vdi - $ VirtualBox - create a new VM; as disk use the go-tiny.vdi image. - start the vm. - - -QEMU / KVM - -This should work the same for qemu and kvm (really: qemu-kvm). - - Build 'disk' (described above under '386'). - - $ qemu -hda disk - - -ARM - -First build the toolchain using GOARCH=arm and GOOS=linux. When -you build your embedded code set GOARCH=tiny. - - export GOOS=tiny - cd $GOROOT/src/pkg/runtime - make clean - make install - -On arm the tiny runtime doesn't define a low level write function. You can either -define a stub if you don't need debug output, or more usefully, define it to -print to some debug serial port. Here is a sample function that prints to -the DBGU on an at91sam7s: - -#define DBGU_CSR ((uint32*) 0xFFFFF214) // (DBGU) Channel Status Register -#define US_TXRDY ((uint32) 0x1 << 1) // (DBGU) TXRDY Interrupt -#define DBGU_THR ((uint32*) 0xFFFFF21C) // (DBGU) Transmitter Holding Register - -int32 -write(int32 fd, void* b, int32 n) -{ - uint32 i; - uint8* s = (uint8*)b; - - for (i = 0; i < n; i++) { - while ((*DBGU_CSR & US_TXRDY) == 0) { - } - *DBGU_THR = *s; - s++; - } - return n; -} - - - -The 386 bootblock is from MIT's xv6 project and carries this notice: - - The xv6 software is: - - Copyright (c) 2006-2009 Frans Kaashoek, Robert Morris, Russ Cox, - Massachusetts Institute of Technology - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -http://pdos.csail.mit.edu/6.828/xv6/ - diff --git a/src/pkg/runtime/tiny/arm/defs.h b/src/pkg/runtime/tiny/arm/defs.h deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/arm/defs.h +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/arm/rt0.s b/src/pkg/runtime/tiny/arm/rt0.s deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/arm/rt0.s +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/arm/signal.c b/src/pkg/runtime/tiny/arm/signal.c deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/arm/signal.c +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/arm/sys.s b/src/pkg/runtime/tiny/arm/sys.s deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/arm/sys.s +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/bootblock b/src/pkg/runtime/tiny/bootblock Binary files differdeleted file mode 100755 index 54dd7c632..000000000 --- a/src/pkg/runtime/tiny/bootblock +++ /dev/null diff --git a/src/pkg/runtime/tiny/dot-bochsrc b/src/pkg/runtime/tiny/dot-bochsrc deleted file mode 100644 index 3f5c813a2..000000000 --- a/src/pkg/runtime/tiny/dot-bochsrc +++ /dev/null @@ -1,18 +0,0 @@ -romimage: file=$BXSHARE/BIOS-bochs-latest -cpu: count=1, ips=100000000, reset_on_triple_fault=0 -megs: 32 -vgaromimage: file=/usr/share/vgabios/vgabios.bin -vga: extension=none -ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 -ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 -ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 -ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9 -ata0-master: type=disk, mode=flat, path="disk", cylinders=100, heads=10, spt=10 -boot: disk -panic: action=ask -error: action=report -info: action=report -debug: action=ignore -debugger_log: - -config_interface: wx -display_library: wx diff --git a/src/pkg/runtime/tiny/io.go b/src/pkg/runtime/tiny/io.go deleted file mode 100644 index f30e68889..000000000 --- a/src/pkg/runtime/tiny/io.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2010 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. - -// Simple CGA screen output - -package runtime - -import "unsafe" - -var crt *[25 * 80]uint16 -var pos int - -func putc(c int) { - const ( - port = 0x3d4 - color = 0x0700 // white on black - ) - - if crt == nil { - // init on demand in case printf is called before - // initialization runs. - var mem uintptr = 0xb8000 - crt = (*[25 * 80]uint16)(unsafe.Pointer(mem)) - pos = 0 - for i := range crt[0:] { - crt[i] = 0 - } - } - - switch c { - case '\n': - pos += 80 - pos%80 - default: - crt[pos] = uint16(c&0xff | color) - pos++ - } - - if pos/80 >= 24 { - copy(crt[0:], crt[80:]) - pos -= 80 - for i := 0; i < 80; i++ { - crt[24*80+i] = 0 - } - } - crt[pos] = ' ' | color -} - -func write(fd int32, b []byte) { - for _, c := range b { - putc(int(c)) - } -} diff --git a/src/pkg/runtime/tiny/mem.c b/src/pkg/runtime/tiny/mem.c deleted file mode 100644 index 7abecfba0..000000000 --- a/src/pkg/runtime/tiny/mem.c +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" -#include "malloc.h" - -// Assume there's an arbitrary amount of memory starting at "end". -// Sizing PC memory is beyond the scope of this demo. - -static byte *allocp; - -void* -runtime·SysAlloc(uintptr ask) -{ - extern byte end[]; - byte *q; - - if(allocp == nil) { - allocp = end; - allocp += 7 & -(uintptr)allocp; - } - ask += 7 & -ask; - - q = allocp; - allocp += ask; - runtime·memclr(q, ask); - return q; -} - -void -runtime·SysFree(void *v, uintptr n) -{ - // Push pointer back if this is a free - // of the most recent SysAlloc. - n += 7 & -n; - if(allocp == (byte*)v+n) - allocp -= n; -} - -void -runtime·SysUnused(void *v, uintptr n) -{ - USED(v, n); -} - -void -runtime·SysMemInit(void) -{ -} diff --git a/src/pkg/runtime/tiny/os.h b/src/pkg/runtime/tiny/os.h deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/os.h +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/runtime_defs.go b/src/pkg/runtime/tiny/runtime_defs.go deleted file mode 100644 index 86de13316..000000000 --- a/src/pkg/runtime/tiny/runtime_defs.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2010 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. - -// OS-Specific Go definitions of internal structures. Master is runtime.h - -package runtime - -type lock struct { - key uint32 - sema uint32 -} - -type note lock diff --git a/src/pkg/runtime/tiny/signals.h b/src/pkg/runtime/tiny/signals.h deleted file mode 100644 index 5df757613..000000000 --- a/src/pkg/runtime/tiny/signals.h +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/src/pkg/runtime/tiny/thread.c b/src/pkg/runtime/tiny/thread.c deleted file mode 100644 index 0572ecb77..000000000 --- a/src/pkg/runtime/tiny/thread.c +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2010 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. - -#include "runtime.h" - -int8 *goos = "tiny"; - -void -runtime·minit(void) -{ -} - -void -runtime·osinit(void) -{ -} - -void -runtime·goenvs(void) -{ - runtime·goenvs_unix(); -} - -void -runtime·initsig(int32 queue) -{ -} - -void -runtime·exit(int32) -{ - for(;;); -} - -// single processor, no interrupts, -// so no need for real concurrency or atomicity - -void -runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void)) -{ - USED(m, g, stk, fn); - runtime·throw("newosproc"); -} - -void -runtime·lock(Lock *l) -{ - if(m->locks < 0) - runtime·throw("lock count"); - m->locks++; - if(l->key != 0) - runtime·throw("deadlock"); - l->key = 1; -} - -void -runtime·unlock(Lock *l) -{ - m->locks--; - if(m->locks < 0) - runtime·throw("lock count"); - if(l->key != 1) - runtime·throw("unlock of unlocked lock"); - l->key = 0; -} - -void -runtime·destroylock(Lock *l) -{ - // nothing -} - -void -runtime·noteclear(Note *n) -{ - n->lock.key = 0; -} - -void -runtime·notewakeup(Note *n) -{ - n->lock.key = 1; -} - -void -runtime·notesleep(Note *n) -{ - if(n->lock.key != 1) - runtime·throw("notesleep"); -} - diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go index d92fe5f2a..87268db4c 100644 --- a/src/pkg/runtime/type.go +++ b/src/pkg/runtime/type.go @@ -51,10 +51,8 @@ const ( kindUint32 kindUint64 kindUintptr - kindFloat kindFloat32 kindFloat64 - kindComplex kindComplex64 kindComplex128 kindArray @@ -72,7 +70,7 @@ const ( ) // Method on non-interface type -type method struct { +type _method struct { // underscore is to avoid collision with C name *string // name of method pkgPath *string // nil for exported Names; otherwise import path mtyp *Type // method type (without receiver) @@ -86,9 +84,9 @@ type method struct { // Using a pointer to this struct reduces the overall size required // to describe an unnamed type with no methods. type uncommonType struct { - name *string // name of type - pkgPath *string // import path; nil for built-in types like int, string - methods []method // methods associated with type + name *string // name of type + pkgPath *string // import path; nil for built-in types like int, string + methods []_method // methods associated with type } // BoolType represents a boolean type. @@ -153,7 +151,7 @@ type FuncType struct { } // Method on interface type -type imethod struct { +type _imethod struct { // underscore is to avoid collision with C name *string // name of method pkgPath *string // nil for exported Names; otherwise import path typ *Type // .(*FuncType) underneath @@ -162,7 +160,7 @@ type imethod struct { // InterfaceType represents an interface type. type InterfaceType struct { commonType - methods []imethod // sorted by hash + methods []_imethod // sorted by hash } // MapType represents a map type. diff --git a/src/pkg/runtime/type.h b/src/pkg/runtime/type.h index 4b5bd7ac2..c7d9dace2 100644 --- a/src/pkg/runtime/type.h +++ b/src/pkg/runtime/type.h @@ -4,6 +4,11 @@ /* * Runtime type representation; master is type.go + * + * The *Types here correspond 1-1 to type.go's *Type's, but are + * prefixed with an extra header of 2 pointers, corresponding to the + * interface{} structure, which itself is called type Type again on + * the Go side. */ typedef struct CommonType CommonType; @@ -41,10 +46,8 @@ enum { KindUint32, KindUint64, KindUintptr, - KindFloat, KindFloat32, KindFloat64, - KindComplex, KindComplex64, KindComplex128, KindArray, diff --git a/src/pkg/runtime/windows/386/defs.h b/src/pkg/runtime/windows/386/defs.h index f5a16367e..a2a882103 100644 --- a/src/pkg/runtime/windows/386/defs.h +++ b/src/pkg/runtime/windows/386/defs.h @@ -10,8 +10,69 @@ enum { PROT_EXEC = 0x4, MAP_ANON = 0x1, MAP_PRIVATE = 0x2, + EXCEPTION_ACCESS_VIOLATION = 0xc0000005, + EXCEPTION_BREAKPOINT = 0x80000003, + EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d, + EXCEPTION_FLT_DIVIDE_BY_ZERO = 0xc000008e, + EXCEPTION_FLT_INEXACT_RESULT = 0xc000008f, + EXCEPTION_FLT_OVERFLOW = 0xc0000091, + EXCEPTION_FLT_UNDERFLOW = 0xc0000093, + EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094, + EXCEPTION_INT_OVERFLOW = 0xc0000095, }; // Types #pragma pack on + +typedef struct ExceptionRecord ExceptionRecord; +struct ExceptionRecord { + uint32 ExceptionCode; + uint32 ExceptionFlags; + ExceptionRecord *ExceptionRecord; + void *ExceptionAddress; + uint32 NumberParameters; + uint32 ExceptionInformation[15]; +}; + +typedef struct FloatingSaveArea FloatingSaveArea; +struct FloatingSaveArea { + uint32 ControlWord; + uint32 StatusWord; + uint32 TagWord; + uint32 ErrorOffset; + uint32 ErrorSelector; + uint32 DataOffset; + uint32 DataSelector; + uint8 RegisterArea[80]; + uint32 Cr0NpxState; +}; + +typedef struct Context Context; +struct Context { + uint32 ContextFlags; + uint32 Dr0; + uint32 Dr1; + uint32 Dr2; + uint32 Dr3; + uint32 Dr6; + uint32 Dr7; + FloatingSaveArea FloatSave; + uint32 SegGs; + uint32 SegFs; + uint32 SegEs; + uint32 SegDs; + uint32 Edi; + uint32 Esi; + uint32 Ebx; + uint32 Edx; + uint32 Ecx; + uint32 Eax; + uint32 Ebp; + uint32 Eip; + uint32 SegCs; + uint32 EFlags; + uint32 Esp; + uint32 SegSs; + uint8 ExtendedRegisters[512]; +}; #pragma pack off diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/windows/386/rt0.s index e379830fb..3b023de2f 100644 --- a/src/pkg/runtime/windows/386/rt0.s +++ b/src/pkg/runtime/windows/386/rt0.s @@ -3,4 +3,12 @@ // license that can be found in the LICENSE file. TEXT _rt0_386_windows(SB),7,$0 + // Set up SEH frame for bootstrap m + PUSHL $runtime·sigtramp(SB) + PUSHL 0(FS) + MOVL SP, 0(FS) + JMP _rt0_386(SB) + +DATA runtime·iswindows(SB)/4, $1 +GLOBL runtime·iswindows(SB), $4 diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c index 2ae79e5b5..69178cdd0 100644 --- a/src/pkg/runtime/windows/386/signal.c +++ b/src/pkg/runtime/windows/386/signal.c @@ -3,6 +3,26 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "defs.h" +#include "os.h" + +void +runtime·dumpregs(Context *r) +{ + runtime·printf("eax %x\n", r->Eax); + runtime·printf("ebx %x\n", r->Ebx); + runtime·printf("ecx %x\n", r->Ecx); + runtime·printf("edx %x\n", r->Edx); + runtime·printf("edi %x\n", r->Edi); + runtime·printf("esi %x\n", r->Esi); + runtime·printf("ebp %x\n", r->Ebp); + runtime·printf("esp %x\n", r->Esp); + runtime·printf("eip %x\n", r->Eip); + runtime·printf("eflags %x\n", r->EFlags); + runtime·printf("cs %x\n", r->SegCs); + runtime·printf("fs %x\n", r->SegFs); + runtime·printf("gs %x\n", r->SegGs); +} void runtime·initsig(int32) @@ -15,3 +35,62 @@ runtime·signame(int32) return runtime·emptystring; } +uint32 +runtime·sighandler(ExceptionRecord *info, void *frame, Context *r) +{ + uintptr *sp; + G *gp; + + USED(frame); + + switch(info->ExceptionCode) { + case EXCEPTION_BREAKPOINT: + r->Eip--; // because 8l generates 2 bytes for INT3 + return 1; + } + + if((gp = m->curg) != nil && runtime·issigpanic(info->ExceptionCode)) { + // Make it look like a call to the signal func. + // Have to pass arguments out of band since + // augmenting the stack frame would break + // the unwinding code. + gp->sig = info->ExceptionCode; + gp->sigcode0 = info->ExceptionInformation[0]; + gp->sigcode1 = info->ExceptionInformation[1]; + gp->sigpc = r->Eip; + + // Only push runtime·sigpanic if r->eip != 0. + // If r->eip == 0, probably panicked because of a + // call to a nil func. Not pushing that onto sp will + // make the trace look like a call to runtime·sigpanic instead. + // (Otherwise the trace will end at runtime·sigpanic and we + // won't get to see who faulted.) + if(r->Eip != 0) { + sp = (uintptr*)r->Esp; + *--sp = r->Eip; + r->Esp = (uintptr)sp; + } + r->Eip = (uintptr)runtime·sigpanic; + return 0; + } + + if(runtime·panicking) // traceback already printed + runtime·exit(2); + runtime·panicking = 1; + + runtime·printf("Exception %x %p %p\n", info->ExceptionCode, + info->ExceptionInformation[0], info->ExceptionInformation[1]); + + runtime·printf("PC=%x\n", r->Eip); + runtime·printf("\n"); + + if(runtime·gotraceback()){ + runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, m->curg); + runtime·tracebackothers(m->curg); + runtime·dumpregs(r); + } + + runtime·breakpoint(); + runtime·exit(2); + return 0; +} diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s index 7f99b34de..d1a8a49a9 100644 --- a/src/pkg/runtime/windows/386/sys.s +++ b/src/pkg/runtime/windows/386/sys.s @@ -5,7 +5,7 @@ #include "386/asm.h" // void *stdcall_raw(void *fn, int32 count, uintptr *args) -TEXT runtime·stdcall_raw(SB),7,$4 +TEXT runtime·stdcall_raw(SB),7,$0 // Copy arguments from stack. MOVL fn+0(FP), AX MOVL count+4(FP), CX // words @@ -14,17 +14,18 @@ TEXT runtime·stdcall_raw(SB),7,$4 // Switch to m->g0 if needed. get_tls(DI) MOVL m(DI), DX - MOVL g(DI), SI - MOVL SI, 0(SP) // save g - MOVL SP, m_gostack(DX) // save SP + MOVL 0(FS), SI + MOVL SI, m_sehframe(DX) MOVL m_g0(DX), SI CMPL g(DI), SI - JEQ 3(PC) + MOVL SP, BX + JEQ 2(PC) MOVL (m_sched+gobuf_sp)(DX), SP + PUSHL BX + PUSHL g(DI) MOVL SI, g(DI) // Copy args to new stack. - SUBL $(10*4), SP // padding MOVL CX, BX SALL $2, BX SUBL BX, SP // room for args @@ -38,28 +39,122 @@ TEXT runtime·stdcall_raw(SB),7,$4 // Restore original SP, g. get_tls(DI) - MOVL m(DI), DX - MOVL m_gostack(DX), SP // restore SP - MOVL 0(SP), SI // restore g - MOVL SI, g(DI) + POPL g(DI) + POPL SP // Someday the convention will be D is always cleared. CLD - RET + RET + +// faster get/set last error +TEXT runtime·getlasterror(SB),7,$0 + MOVL 0x34(FS), AX + RET + +TEXT runtime·setlasterror(SB),7,$0 + MOVL err+0(FP), AX + MOVL AX, 0x34(FS) + RET + +TEXT runtime·sigtramp(SB),7,$0 + PUSHL BP // cdecl + PUSHL 0(FS) + CALL runtime·sigtramp1(SB) + POPL 0(FS) + POPL BP + RET + +TEXT runtime·sigtramp1(SB),0,$16-28 + // unwinding? + MOVL info+12(FP), BX + MOVL 4(BX), CX // exception flags + ANDL $6, CX + MOVL $1, AX + JNZ sigdone + + // place ourselves at the top of the SEH chain to + // ensure SEH frames lie within thread stack bounds + MOVL frame+16(FP), CX // our SEH frame + MOVL CX, 0(FS) + + // copy arguments for call to sighandler + MOVL BX, 0(SP) + MOVL CX, 4(SP) + MOVL context+20(FP), BX + MOVL BX, 8(SP) + MOVL dispatcher+24(FP), BX + MOVL BX, 12(SP) + + CALL runtime·sighandler(SB) + TESTL AX, AX + JZ sigdone + + // call windows default handler early + MOVL 4(SP), BX // our SEH frame + MOVL 0(BX), BX // SEH frame of default handler + MOVL BX, 4(SP) // set establisher frame + CALL 4(BX) + +sigdone: + RET + +// Called from dynamic function created by ../thread.c compilecallback, +// running on Windows stack (not Go stack). +// BX, BP, SI, DI registers and DF flag are preserved +// as required by windows callback convention. +// AX = address of go func we need to call +// DX = total size of arguments +// +TEXT runtime·callbackasm+0(SB),7,$0 + LEAL 8(SP), CX + + // save registers as required for windows callback + PUSHL 0(FS) + PUSHL DI + PUSHL SI + PUSHL BP + PUSHL BX + PUSHL DX + PUSHL CX + PUSHL AX + + // reinstall our SEH handler + get_tls(CX) + MOVL m(CX), CX + MOVL m_sehframe(CX), CX + MOVL CX, 0(FS) + CLD + + CALL runtime·cgocallback(SB) + + // restore registers as required for windows callback + POPL CX + POPL CX + POPL DX + POPL BX + POPL BP + POPL SI + POPL DI + POPL 0(FS) + CLD + + RET // void tstart(M *newm); TEXT runtime·tstart(SB),7,$0 MOVL newm+4(SP), CX // m MOVL m_g0(CX), DX // g - MOVL SP, DI // remember stack + // Set up SEH frame + PUSHL $runtime·sigtramp(SB) + PUSHL 0(FS) + MOVL SP, 0(FS) // Layout new m scheduler stack on os stack. MOVL SP, AX - SUBL $256, AX // just some space for ourselves MOVL AX, g_stackbase(DX) - SUBL $8192, AX // stack size + SUBL $(64*1024), AX // stack size MOVL AX, g_stackguard(DX) // Set up tls. @@ -68,20 +163,17 @@ TEXT runtime·tstart(SB),7,$0 MOVL CX, m(SI) MOVL DX, g(SI) - // Use scheduler stack now. - MOVL g_stackbase(DX), SP - // Someday the convention will be D is always cleared. CLD - PUSHL DI // original stack - - CALL runtime·stackcheck(SB) // clobbers AX,CX + CALL runtime·stackcheck(SB) // clobbers AX,CX CALL runtime·mstart(SB) - POPL DI // original stack - MOVL DI, SP + // Pop SEH frame + MOVL 0(FS), SP + POPL 0(FS) + POPL CX RET @@ -107,12 +199,3 @@ TEXT runtime·setldt(SB),7,$0 MOVL address+4(FP), CX MOVL CX, 0x2c(FS) RET - -// for now, return 0,0. only used for internal performance monitoring. -TEXT runtime·gettime(SB),7,$0 - MOVL sec+0(FP), DI - MOVL $0, (DI) - MOVL $0, 4(DI) // zero extend 32 -> 64 bits - MOVL usec+4(FP), DI - MOVL $0, (DI) - RET diff --git a/src/pkg/runtime/windows/defs.c b/src/pkg/runtime/windows/defs.c index db5f1400e..5aac03c81 100644 --- a/src/pkg/runtime/windows/defs.c +++ b/src/pkg/runtime/windows/defs.c @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <stdarg.h> +#include <windef.h> +#include <winbase.h> + enum { $PROT_NONE = 0, $PROT_READ = 1, @@ -10,4 +14,18 @@ enum { $MAP_ANON = 1, $MAP_PRIVATE = 2, + + $EXCEPTION_ACCESS_VIOLATION = STATUS_ACCESS_VIOLATION, + $EXCEPTION_BREAKPOINT = STATUS_BREAKPOINT, + $EXCEPTION_FLT_DENORMAL_OPERAND = STATUS_FLOAT_DENORMAL_OPERAND, + $EXCEPTION_FLT_DIVIDE_BY_ZERO = STATUS_FLOAT_DIVIDE_BY_ZERO, + $EXCEPTION_FLT_INEXACT_RESULT = STATUS_FLOAT_INEXACT_RESULT, + $EXCEPTION_FLT_OVERFLOW = STATUS_FLOAT_OVERFLOW, + $EXCEPTION_FLT_UNDERFLOW = STATUS_FLOAT_UNDERFLOW, + $EXCEPTION_INT_DIVIDE_BY_ZERO = STATUS_INTEGER_DIVIDE_BY_ZERO, + $EXCEPTION_INT_OVERFLOW = STATUS_INTEGER_OVERFLOW, }; + +typedef EXCEPTION_RECORD $ExceptionRecord; +typedef FLOATING_SAVE_AREA $FloatingSaveArea; +typedef CONTEXT $Context; diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c index ba89887ea..19d11ce8d 100644 --- a/src/pkg/runtime/windows/mem.c +++ b/src/pkg/runtime/windows/mem.c @@ -15,16 +15,6 @@ enum { PAGE_EXECUTE_READWRITE = 0x40, }; -static void -abort(int8 *name) -{ - uintptr errno; - - errno = (uintptr)runtime·stdcall(runtime·GetLastError, 0); - runtime·printf("%s failed with errno=%d\n", name, errno); - runtime·throw(name); -} - #pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll" #pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll" extern void *runtime·VirtualAlloc; @@ -33,12 +23,8 @@ extern void *runtime·VirtualFree; void* runtime·SysAlloc(uintptr n) { - void *v; - - v = runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if(v == 0) - abort("VirtualAlloc"); - return v; + mstats.sys += n; + return runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); } void @@ -53,12 +39,25 @@ runtime·SysFree(void *v, uintptr n) { uintptr r; + mstats.sys -= n; r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, 0, MEM_RELEASE); if(r == 0) - abort("VirtualFree"); + runtime·throw("runtime: failed to release pages"); +} + +void* +runtime·SysReserve(void *v, uintptr n) +{ + return runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_RESERVE, 0); } void -runtime·SysMemInit(void) +runtime·SysMap(void *v, uintptr n) { + void *p; + + mstats.sys += n; + p = runtime·stdcall(runtime·VirtualAlloc, 4, v, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(p != v) + runtime·throw("runtime: cannot map pages in arena address space"); } diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h index 77d0d32a0..391eace5a 100644 --- a/src/pkg/runtime/windows/os.h +++ b/src/pkg/runtime/windows/os.h @@ -4,33 +4,23 @@ extern void *runtime·LoadLibraryEx; extern void *runtime·GetProcAddress; -extern void *runtime·GetLastError; - -// Get start address of symbol data in memory. -void *runtime·get_symdat_addr(void); // Call a Windows function with stdcall conventions, // and switch to os stack during the call. -void *runtime·stdcall_raw(void *fn, int32 count, uintptr *args); +void *runtime·stdcall_raw(void *fn, uintptr nargs, void *args); void *runtime·stdcall(void *fn, int32 count, ...); +uintptr runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err); + +uintptr runtime·getlasterror(void); +void runtime·setlasterror(uintptr err); -// Function to be called by windows CreateTread +// Function to be called by windows CreateThread // to start new os thread. uint32 runtime·tstart_stdcall(M *newm); -// Call stdcall Windows function StdcallParams.fn -// with params StdcallParams.args, -// followed immediately by GetLastError call. -// Both return values are returned in StdcallParams.r and -// StdcallParams.err. Will use os stack during the call. -typedef struct StdcallParams StdcallParams; -struct StdcallParams -{ - void *fn; - uintptr args[12]; - int32 n; - uintptr r; - uintptr err; -}; +uint32 runtime·issigpanic(uint32); +void runtime·sigpanic(void); -void runtime·syscall(StdcallParams *p); +// Windows dll function to go callback entry. +byte *runtime·compilecallback(Eface fn, bool cleanstack); +void *runtime·callbackasm(void); diff --git a/src/pkg/runtime/windows/runtime_defs.go b/src/pkg/runtime/windows/runtime_defs.go deleted file mode 100644 index 34a9b3259..000000000 --- a/src/pkg/runtime/windows/runtime_defs.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2010 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. - -// Go definitions of internal structures. Master is runtime.h - -package runtime - -import "unsafe" - -const ( - Windows = 1 -) - -// const ( Structrnd = sizeof(uintptr) ) - -type lock struct { - key uint32 - event unsafe.Pointer -} - -type note lock diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc index d3057c540..85071e051 100644 --- a/src/pkg/runtime/windows/syscall.goc +++ b/src/pkg/runtime/windows/syscall.goc @@ -6,106 +6,62 @@ package syscall #include "runtime.h" #include "os.h" -func loadlibraryex(filename uintptr) (handle uint32) { - StdcallParams p; - p.fn = (void*)runtime·LoadLibraryEx; - p.args[0] = filename; - p.args[1] = 0; - p.args[2] = 0; - p.n = 3; - runtime·syscall(&p); - handle = p.r; +func loadlibraryex(filename uintptr) (handle uintptr) { + uintptr args[3] = { filename }; + handle = runtime·syscall(runtime·LoadLibraryEx, 3, args, nil); } -func getprocaddress(handle uint32, procname uintptr) (proc uintptr) { - StdcallParams p; - p.fn = (void*)runtime·GetProcAddress; - p.args[0] = handle; - p.args[1] = procname; - p.n = 2; - runtime·syscall(&p); - proc = p.r; +func getprocaddress(handle uintptr, procname uintptr) (proc uintptr) { + USED(procname); + proc = runtime·syscall(runtime·GetProcAddress, 2, &handle, nil); } -func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { - StdcallParams p; - p.fn = (void*)trap; - p.args[0] = a1; - p.args[1] = a2; - p.args[2] = a3; - p.n = 3; - runtime·syscall(&p); - r1 = p.r; - r2 = 0; - err = p.err; +func NewCallback(fn Eface) (code uintptr) { + code = (uintptr)runtime·compilecallback(fn, true); } -func Syscall6(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { - StdcallParams p; - p.fn = (void*)trap; - p.args[0] = a1; - p.args[1] = a2; - p.args[2] = a3; - p.args[3] = a4; - p.args[4] = a5; - p.args[5] = a6; - p.n = 6; - runtime·syscall(&p); - r1 = p.r; +func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + USED(a2); + USED(a3); + r1 = runtime·syscall((void*)fn, nargs, &a1, &err); r2 = 0; - err = p.err; } -func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, lasterr uintptr) { - StdcallParams p; - p.fn = (void*)trap; - p.args[0] = a1; - p.args[1] = a2; - p.args[2] = a3; - p.args[3] = a4; - p.args[4] = a5; - p.args[5] = a6; - p.args[6] = a7; - p.args[7] = a8; - p.args[8] = a9; - p.n = 9; - runtime·syscall(&p); - r1 = p.r; +func Syscall6(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + USED(a2); + USED(a3); + USED(a4); + USED(a5); + USED(a6); + r1 = runtime·syscall((void*)fn, nargs, &a1, &err); r2 = 0; - lasterr = p.err; } -func Syscall12(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, lasterr uintptr) { - StdcallParams p; - p.fn = (void*)trap; - p.args[0] = a1; - p.args[1] = a2; - p.args[2] = a3; - p.args[3] = a4; - p.args[4] = a5; - p.args[5] = a6; - p.args[6] = a7; - p.args[7] = a8; - p.args[8] = a9; - p.args[9] = a10; - p.args[10] = a11; - p.args[11] = a12; - p.n = 12; - runtime·syscall(&p); - r1 = p.r; +func Syscall9(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + USED(a2); + USED(a3); + USED(a4); + USED(a5); + USED(a6); + USED(a7); + USED(a8); + USED(a9); + r1 = runtime·syscall((void*)fn, nargs, &a1, &err); r2 = 0; - lasterr = p.err; } -func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { - StdcallParams p; - p.fn = (void*)trap; - p.args[0] = a1; - p.args[1] = a2; - p.args[2] = a3; - p.n = 3; - runtime·syscall(&p); - r1 = p.r; +func Syscall12(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr, a6 uintptr, a7 uintptr, a8 uintptr, a9 uintptr, a10 uintptr, a11 uintptr, a12 uintptr) (r1 uintptr, r2 uintptr, err uintptr) { + USED(a2); + USED(a3); + USED(a4); + USED(a5); + USED(a6); + USED(a7); + USED(a8); + USED(a9); + USED(a10); + USED(a11); + USED(a12); + r1 = runtime·syscall((void*)fn, nargs, &a1, &err); r2 = 0; - err = p.err; } diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c index 9b5181337..278a5da69 100644 --- a/src/pkg/runtime/windows/thread.c +++ b/src/pkg/runtime/windows/thread.c @@ -3,48 +3,48 @@ // license that can be found in the LICENSE file. #include "runtime.h" +#include "type.h" +#include "defs.h" #include "os.h" -#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll" -#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll" +#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" +#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" #pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll" +#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" +#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" +#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll" #pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll" +#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll" +#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll" +#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll" #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll" +#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" #pragma dynimport runtime·WriteFile WriteFile "kernel32.dll" -#pragma dynimport runtime·GetLastError GetLastError "kernel32.dll" -#pragma dynimport runtime·SetLastError SetLastError "kernel32.dll" -// Also referenced by external packages extern void *runtime·CloseHandle; +extern void *runtime·CreateEvent; +extern void *runtime·CreateThread; extern void *runtime·ExitProcess; +extern void *runtime·FreeEnvironmentStringsW; +extern void *runtime·GetEnvironmentStringsW; +extern void *runtime·GetProcAddress; extern void *runtime·GetStdHandle; +extern void *runtime·LoadLibraryEx; +extern void *runtime·QueryPerformanceCounter; +extern void *runtime·QueryPerformanceFrequency; extern void *runtime·SetEvent; +extern void *runtime·WaitForSingleObject; extern void *runtime·WriteFile; -extern void *runtime·LoadLibraryEx; -extern void *runtime·GetProcAddress; -extern void *runtime·GetLastError; -extern void *runtime·SetLastError; - -#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll" -#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll" -#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll" -extern void *runtime·CreateEvent; -extern void *runtime·CreateThread; -extern void *runtime·WaitForSingleObject; +static int64 timerfreq; void runtime·osinit(void) { + runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq); } -#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll" -#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll" - -extern void *runtime·GetEnvironmentStringsW; -extern void *runtime·FreeEnvironmentStringsW; - void runtime·goenvs(void) { @@ -193,6 +193,17 @@ runtime·minit(void) { } +void +runtime·gettime(int64 *sec, int32 *usec) +{ + int64 count; + + runtime·stdcall(runtime·QueryPerformanceCounter, 1, &count); + *sec = count / timerfreq; + count %= timerfreq; + *usec = count*1000000 / timerfreq; +} + // Calling stdcall on os stack. #pragma textflag 7 void * @@ -201,17 +212,124 @@ runtime·stdcall(void *fn, int32 count, ...) return runtime·stdcall_raw(fn, count, (uintptr*)(&count + 1)); } -void -runtime·syscall(StdcallParams *p) +uintptr +runtime·syscall(void *fn, uintptr nargs, void *args, uintptr *err) { - uintptr a; + G *oldlock; + uintptr ret; + + /* + * Lock g to m to ensure we stay on the same stack if we do a callback. + */ + oldlock = m->lockedg; + m->lockedg = g; + g->lockedm = m; runtime·entersyscall(); - // TODO(brainman): Move calls to SetLastError and GetLastError - // to stdcall_raw to speed up syscall. - a = 0; - runtime·stdcall_raw(runtime·SetLastError, 1, &a); - p->r = (uintptr)runtime·stdcall_raw((void*)p->fn, p->n, p->args); - p->err = (uintptr)runtime·stdcall_raw(runtime·GetLastError, 0, &a); + runtime·setlasterror(0); + ret = (uintptr)runtime·stdcall_raw(fn, nargs, args); + if(err) + *err = runtime·getlasterror(); runtime·exitsyscall(); + + m->lockedg = oldlock; + if(oldlock == nil) + g->lockedm = nil; + + return ret; +} + +uint32 +runtime·issigpanic(uint32 code) +{ + switch(code) { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + return 1; + } + return 0; +} + +void +runtime·sigpanic(void) +{ + switch(g->sig) { + case EXCEPTION_ACCESS_VIOLATION: + if(g->sigcode1 < 0x1000) + runtime·panicstring("invalid memory address or nil pointer dereference"); + runtime·printf("unexpected fault address %p\n", g->sigcode1); + runtime·throw("fault"); + case EXCEPTION_INT_DIVIDE_BY_ZERO: + runtime·panicstring("integer divide by zero"); + case EXCEPTION_INT_OVERFLOW: + runtime·panicstring("integer overflow"); + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + runtime·panicstring("floating point error"); + } + runtime·throw("fault"); +} + +// Call back from windows dll into go. +byte * +runtime·compilecallback(Eface fn, bool cleanstack) +{ + Func *f; + int32 argsize, n; + byte *ret, *p; + + if(fn.type->kind != KindFunc) + runtime·panicstring("not a function"); + if((f = runtime·findfunc((uintptr)fn.data)) == nil) + runtime·throw("cannot find function"); + argsize = (f->args-2) * 4; + + // compute size of new fn. + // must match code laid out below. + n = 1+4; // MOVL fn, AX + n += 1+4; // MOVL argsize, DX + n += 1+4; // MOVL callbackasm, CX + n += 2; // CALL CX + n += 1; // RET + if(cleanstack) + n += 2; // ... argsize + + ret = p = runtime·mal(n); + + // MOVL fn, AX + *p++ = 0xb8; + *(uint32*)p = (uint32)fn.data; + p += 4; + + // MOVL argsize, DX + *p++ = 0xba; + *(uint32*)p = argsize; + p += 4; + + // MOVL callbackasm, CX + *p++ = 0xb9; + *(uint32*)p = (uint32)runtime·callbackasm; + p += 4; + + // CALL CX + *p++ = 0xff; + *p++ = 0xd1; + + // RET argsize? + if(cleanstack) { + *p++ = 0xc2; + *(uint16*)p = argsize; + } else + *p = 0xc3; + + return ret; } diff --git a/src/pkg/scanner/scanner.go b/src/pkg/scanner/scanner.go index 11aa9f43f..2396cdd9a 100644 --- a/src/pkg/scanner/scanner.go +++ b/src/pkg/scanner/scanner.go @@ -34,13 +34,15 @@ import ( ) +// TODO(gri): Consider changing this to use the new (token) Position package. + // A source position is represented by a Position value. // A position is valid if Line > 0. type Position struct { Filename string // filename, if any Offset int // byte offset, starting at 0 Line int // line number, starting at 1 - Column int // column number, starting at 0 (character count per line) + Column int // column number, starting at 1 (character count per line) } @@ -136,15 +138,17 @@ type Scanner struct { // Source position srcBufOffset int // byte offset of srcBuf[0] in source - line int // newline count + 1 - column int // character count on line + line int // line count + column int // character count + lastLineLen int // length of last line in characters (for correct column reporting) + lastCharLen int // length of last character in bytes // Token text buffer // Typically, token text is stored completely in srcBuf, but in general // the token text's head may be buffered in tokBuf while the token text's // tail is stored in srcBuf. tokBuf bytes.Buffer // token text head that is not in srcBuf anymore - tokPos int // token text tail position (srcBuf index) + tokPos int // token text tail position (srcBuf index); valid if >= 0 tokEnd int // token text tail end (srcBuf index) // One character look-ahead @@ -175,13 +179,14 @@ type Scanner struct { } -// Init initializes a Scanner with a new source and returns itself. +// Init initializes a Scanner with a new source and returns s. // Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens, // and Whitespace is set to GoWhitespace. func (s *Scanner) Init(src io.Reader) *Scanner { s.src = src // initialize source buffer + // (the first call to next() will fill it by calling src.Read) s.srcBuf[0] = utf8.RuneSelf // sentinel s.srcPos = 0 s.srcEnd = 0 @@ -190,12 +195,15 @@ func (s *Scanner) Init(src io.Reader) *Scanner { s.srcBufOffset = 0 s.line = 1 s.column = 0 + s.lastLineLen = 0 + s.lastCharLen = 0 // initialize token text buffer + // (required for first call to next()). s.tokPos = -1 // initialize one character look-ahead - s.ch = s.next() + s.ch = -1 // no char read yet // initialize public fields s.Error = nil @@ -207,12 +215,17 @@ func (s *Scanner) Init(src io.Reader) *Scanner { } +// TODO(gri): The code for next() and the internal scanner state could benefit +// from a rethink. While next() is optimized for the common ASCII +// case, the "corrections" needed for proper position tracking undo +// some of the attempts for fast-path optimization. + // next reads and returns the next Unicode character. It is designed such // that only a minimal amount of work needs to be done in the common ASCII // case (one test to check for both ASCII and end-of-buffer, and one test // to check for newlines). func (s *Scanner) next() int { - ch := int(s.srcBuf[s.srcPos]) + ch, width := int(s.srcBuf[s.srcPos]), 1 if ch >= utf8.RuneSelf { // uncommon case: not ASCII or not enough bytes @@ -222,47 +235,64 @@ func (s *Scanner) next() int { if s.tokPos >= 0 { s.tokBuf.Write(s.srcBuf[s.tokPos:s.srcPos]) s.tokPos = 0 + // s.tokEnd is set by Scan() } // move unread bytes to beginning of buffer copy(s.srcBuf[0:], s.srcBuf[s.srcPos:s.srcEnd]) s.srcBufOffset += s.srcPos // read more bytes + // (an io.Reader must return os.EOF when it reaches + // the end of what it is reading - simply returning + // n == 0 will make this loop retry forever; but the + // error is in the reader implementation in that case) i := s.srcEnd - s.srcPos n, err := s.src.Read(s.srcBuf[i:bufLen]) - s.srcEnd = i + n s.srcPos = 0 + s.srcEnd = i + n s.srcBuf[s.srcEnd] = utf8.RuneSelf // sentinel if err != nil { if s.srcEnd == 0 { + if s.lastCharLen > 0 { + // previous character was not EOF + s.column++ + } + s.lastCharLen = 0 return EOF } if err != os.EOF { s.error(err.String()) - break } + // If err == EOF, we won't be getting more + // bytes; break to avoid infinite loop. If + // err is something else, we don't know if + // we can get more bytes; thus also break. + break } } // at least one byte ch = int(s.srcBuf[s.srcPos]) if ch >= utf8.RuneSelf { // uncommon case: not ASCII - var width int ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd]) if ch == utf8.RuneError && width == 1 { s.error("illegal UTF-8 encoding") } - s.srcPos += width - 1 } } - s.srcPos++ + // advance + s.srcPos += width + s.lastCharLen = width s.column++ + + // special situations switch ch { case 0: // implementation restriction for compatibility with other tools s.error("illegal character NUL") case '\n': s.line++ + s.lastLineLen = s.column s.column = 0 } @@ -272,13 +302,13 @@ func (s *Scanner) next() int { // Next reads and returns the next Unicode character. // It returns EOF at the end of the source. It reports -// a read error by calling s.Error, if set, or else -// prints an error message to os.Stderr. Next does not +// a read error by calling s.Error, if not nil; otherwise +// it prints an error message to os.Stderr. Next does not // update the Scanner's Position field; use Pos() to // get the current position. func (s *Scanner) Next() int { s.tokPos = -1 // don't collect token text - ch := s.ch + ch := s.Peek() s.ch = s.next() return ch } @@ -288,6 +318,9 @@ func (s *Scanner) Next() int { // the scanner. It returns EOF if the scanner's position is at the last // character of the source. func (s *Scanner) Peek() int { + if s.ch < 0 { + s.ch = s.next() + } return s.ch } @@ -511,10 +544,10 @@ func (s *Scanner) scanComment(ch int) { // Scan reads the next token or Unicode character from source and returns it. // It only recognizes tokens t for which the respective Mode bit (1<<-t) is set. // It returns EOF at the end of the source. It reports scanner errors (read and -// token errors) by calling s.Error, if set; otherwise it prints an error message -// to os.Stderr. +// token errors) by calling s.Error, if not nil; otherwise it prints an error +// message to os.Stderr. func (s *Scanner) Scan() int { - ch := s.ch + ch := s.Peek() // reset token text position s.tokPos = -1 @@ -527,12 +560,22 @@ redo: // start collecting token text s.tokBuf.Reset() - s.tokPos = s.srcPos - 1 + s.tokPos = s.srcPos - s.lastCharLen // set token position + // (this is a slightly optimized version of the code in Pos()) s.Offset = s.srcBufOffset + s.tokPos - s.Line = s.line - s.Column = s.column + if s.column > 0 { + // common case: last character was not a '\n' + s.Line = s.line + s.Column = s.column + } else { + // last character was a '\n' + // (we cannot be at the beginning of the source + // since we have called next() at least once) + s.Line = s.line - 1 + s.Column = s.lastLineLen + } // determine token value tok := ch @@ -596,25 +639,33 @@ redo: } // end of token text - s.tokEnd = s.srcPos - 1 + s.tokEnd = s.srcPos - s.lastCharLen s.ch = ch return tok } -// Position returns the current source position. If called before Next() -// or Scan(), it returns the position of the next Unicode character or token -// returned by these functions. If called afterwards, it returns the position -// immediately after the last character of the most recent token or character -// scanned. -func (s *Scanner) Pos() Position { - return Position{ - s.Filename, - s.srcBufOffset + s.srcPos - 1, - s.line, - s.column, +// Pos returns the position of the character immediately after +// the character or token returned by the last call to Next or Scan. +func (s *Scanner) Pos() (pos Position) { + pos.Filename = s.Filename + pos.Offset = s.srcBufOffset + s.srcPos - s.lastCharLen + switch { + case s.column > 0: + // common case: last character was not a '\n' + pos.Line = s.line + pos.Column = s.column + case s.lastLineLen > 0: + // last character was a '\n' + pos.Line = s.line - 1 + pos.Column = s.lastLineLen + default: + // at the beginning of the source + pos.Line = 1 + pos.Column = 1 } + return } diff --git a/src/pkg/scanner/scanner_test.go b/src/pkg/scanner/scanner_test.go index 506f434fe..002252de8 100644 --- a/src/pkg/scanner/scanner_test.go +++ b/src/pkg/scanner/scanner_test.go @@ -10,6 +10,7 @@ import ( "os" "strings" "testing" + "utf8" ) @@ -408,7 +409,7 @@ func TestScanWhitespace(t *testing.T) { func testError(t *testing.T, src, msg string, tok int) { s := new(Scanner).Init(bytes.NewBufferString(src)) errorCalled := false - s.Error = func(s *Scanner, m string) { + s.Error = func(_ *Scanner, m string) { if !errorCalled { // only look at first error if m != msg { @@ -431,6 +432,8 @@ func testError(t *testing.T, src, msg string, tok int) { func TestError(t *testing.T) { + testError(t, "\x00", "illegal character NUL", 0) + testError(t, "\xff", "illegal UTF-8 encoding", utf8.RuneError) testError(t, `01238`, "illegal octal number", Int) testError(t, `'\"'`, "illegal char escape", Char) testError(t, `'aa'`, "illegal char literal", Char) @@ -445,38 +448,99 @@ func TestError(t *testing.T) { } -func checkPos(t *testing.T, s *Scanner, offset, line, column, char int) { - pos := s.Pos() - if pos.Offset != offset { - t.Errorf("offset = %d, want %d", pos.Offset, offset) +func checkPos(t *testing.T, got, want Position) { + if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column { + t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d", + got.Offset, got.Line, got.Column, want.Offset, want.Line, want.Column) } - if pos.Line != line { - t.Errorf("line = %d, want %d", pos.Line, line) - } - if pos.Column != column { - t.Errorf("column = %d, want %d", pos.Column, column) +} + + +func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) { + if ch := s.Next(); ch != char { + t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char)) } - ch := s.Scan() - if ch != char { + want := Position{Offset: offset, Line: line, Column: column} + checkPos(t, s.Pos(), want) +} + + +func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) { + want := Position{Offset: offset, Line: line, Column: column} + checkPos(t, s.Pos(), want) + if ch := s.Scan(); ch != char { t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char)) + if string(ch) != s.TokenText() { + t.Errorf("tok = %q, want %q", s.TokenText(), string(ch)) + } } + checkPos(t, s.Position, want) } func TestPos(t *testing.T) { - s := new(Scanner).Init(bytes.NewBufferString("abc\n012\n\nx")) + // corner case: empty source + s := new(Scanner).Init(bytes.NewBufferString("")) + checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1}) + s.Peek() // peek doesn't affect the position + checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1}) + + // corner case: source with only a newline + s = new(Scanner).Init(bytes.NewBufferString("\n")) + checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1}) + checkNextPos(t, s, 1, 2, 1, '\n') + // after EOF position doesn't change + for i := 10; i > 0; i-- { + checkScanPos(t, s, 1, 2, 1, EOF) + } + + // corner case: source with only a single character + s = new(Scanner).Init(bytes.NewBufferString("本")) + checkPos(t, s.Pos(), Position{Offset: 0, Line: 1, Column: 1}) + checkNextPos(t, s, 3, 1, 2, '本') + // after EOF position doesn't change + for i := 10; i > 0; i-- { + checkScanPos(t, s, 3, 1, 2, EOF) + } + + // positions after calling Next + s = new(Scanner).Init(bytes.NewBufferString(" foo६४ \n\n本語\n")) + checkNextPos(t, s, 1, 1, 2, ' ') + s.Peek() // peek doesn't affect the position + checkNextPos(t, s, 2, 1, 3, ' ') + checkNextPos(t, s, 3, 1, 4, 'f') + checkNextPos(t, s, 4, 1, 5, 'o') + checkNextPos(t, s, 5, 1, 6, 'o') + checkNextPos(t, s, 8, 1, 7, '६') + checkNextPos(t, s, 11, 1, 8, '४') + checkNextPos(t, s, 12, 1, 9, ' ') + checkNextPos(t, s, 13, 1, 10, ' ') + checkNextPos(t, s, 14, 2, 1, '\n') + checkNextPos(t, s, 15, 3, 1, '\n') + checkNextPos(t, s, 18, 3, 2, '本') + checkNextPos(t, s, 21, 3, 3, '語') + checkNextPos(t, s, 22, 4, 1, '\n') + // after EOF position doesn't change + for i := 10; i > 0; i-- { + checkScanPos(t, s, 22, 4, 1, EOF) + } + + // positions after calling Scan + s = new(Scanner).Init(bytes.NewBufferString("abc\n本語\n\nx")) s.Mode = 0 s.Whitespace = 0 - checkPos(t, s, 0, 1, 1, 'a') - checkPos(t, s, 1, 1, 2, 'b') - checkPos(t, s, 2, 1, 3, 'c') - checkPos(t, s, 3, 2, 0, '\n') - checkPos(t, s, 4, 2, 1, '0') - checkPos(t, s, 5, 2, 2, '1') - checkPos(t, s, 6, 2, 3, '2') - checkPos(t, s, 7, 3, 0, '\n') - checkPos(t, s, 8, 4, 0, '\n') - checkPos(t, s, 9, 4, 1, 'x') - checkPos(t, s, 9, 4, 1, EOF) - checkPos(t, s, 9, 4, 1, EOF) // after EOF, position doesn't change + checkScanPos(t, s, 0, 1, 1, 'a') + s.Peek() // peek doesn't affect the position + checkScanPos(t, s, 1, 1, 2, 'b') + checkScanPos(t, s, 2, 1, 3, 'c') + checkScanPos(t, s, 3, 1, 4, '\n') + checkScanPos(t, s, 4, 2, 1, '本') + checkScanPos(t, s, 7, 2, 2, '語') + checkScanPos(t, s, 10, 2, 3, '\n') + checkScanPos(t, s, 11, 3, 1, '\n') + checkScanPos(t, s, 12, 4, 1, 'x') + // after EOF position doesn't change + for i := 10; i > 0; i-- { + checkScanPos(t, s, 13, 4, 2, EOF) + } } diff --git a/src/pkg/sort/search.go b/src/pkg/sort/search.go index b3ddd2dfa..6828e19b6 100644 --- a/src/pkg/sort/search.go +++ b/src/pkg/sort/search.go @@ -74,7 +74,7 @@ func Search(n int, f func(int) bool) int { // Convenience wrappers for common cases. -// SearchInts searches x in a sorted slice of ints and returns the index +// SearchInts searches for x in a sorted slice of ints and returns the index // as specified by Search. The array must be sorted in ascending order. // func SearchInts(a []int, x int) int { @@ -82,15 +82,15 @@ func SearchInts(a []int, x int) int { } -// SearchFloats searches x in a sorted slice of floats and returns the index +// SearchFloat64s searches for x in a sorted slice of float64s and returns the index // as specified by Search. The array must be sorted in ascending order. // -func SearchFloats(a []float, x float) int { +func SearchFloat64s(a []float64, x float64) int { return Search(len(a), func(i int) bool { return a[i] >= x }) } -// SearchStrings searches x in a sorted slice of strings and returns the index +// SearchStrings searches for x in a sorted slice of strings and returns the index // as specified by Search. The array must be sorted in ascending order. // func SearchStrings(a []string, x string) int { @@ -102,8 +102,8 @@ func SearchStrings(a []string, x string) int { func (p IntArray) Search(x int) int { return SearchInts(p, x) } -// Search returns the result of applying SearchFloats to the receiver and x. -func (p FloatArray) Search(x float) int { return SearchFloats(p, x) } +// Search returns the result of applying SearchFloat64s to the receiver and x. +func (p Float64Array) Search(x float64) int { return SearchFloat64s(p, x) } // Search returns the result of applying SearchStrings to the receiver and x. diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go index e16e2c93f..939f66af3 100644 --- a/src/pkg/sort/search_test.go +++ b/src/pkg/sort/search_test.go @@ -96,7 +96,7 @@ func TestSearchEfficiency(t *testing.T) { // Smoke tests for convenience wrappers - not comprehensive. -var fdata = []float{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7} +var fdata = []float64{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7} var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"} var wrappertests = []struct { @@ -105,10 +105,10 @@ var wrappertests = []struct { i int }{ {"SearchInts", SearchInts(data, 11), 8}, - {"SearchFloats", SearchFloats(fdata, 2.1), 4}, + {"SearchFloat64s", SearchFloat64s(fdata, 2.1), 4}, {"SearchStrings", SearchStrings(sdata, ""), 0}, {"IntArray.Search", IntArray(data).Search(0), 2}, - {"FloatArray.Search", FloatArray(fdata).Search(2.0), 3}, + {"Float64Array.Search", Float64Array(fdata).Search(2.0), 3}, {"StringArray.Search", StringArray(sdata).Search("x"), 3}, } diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go index 02e647fca..c7945d21b 100644 --- a/src/pkg/sort/sort.go +++ b/src/pkg/sort/sort.go @@ -166,15 +166,15 @@ func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p IntArray) Sort() { Sort(p) } -// FloatArray attaches the methods of Interface to []float, sorting in increasing order. -type FloatArray []float +// Float64Array attaches the methods of Interface to []float64, sorting in increasing order. +type Float64Array []float64 -func (p FloatArray) Len() int { return len(p) } -func (p FloatArray) Less(i, j int) bool { return p[i] < p[j] } -func (p FloatArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p Float64Array) Len() int { return len(p) } +func (p Float64Array) Less(i, j int) bool { return p[i] < p[j] } +func (p Float64Array) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // Sort is a convenience method. -func (p FloatArray) Sort() { Sort(p) } +func (p Float64Array) Sort() { Sort(p) } // StringArray attaches the methods of Interface to []string, sorting in increasing order. @@ -192,15 +192,15 @@ func (p StringArray) Sort() { Sort(p) } // SortInts sorts an array of ints in increasing order. func SortInts(a []int) { Sort(IntArray(a)) } -// SortFloats sorts an array of floats in increasing order. -func SortFloats(a []float) { Sort(FloatArray(a)) } +// SortFloat64s sorts an array of float64s in increasing order. +func SortFloat64s(a []float64) { Sort(Float64Array(a)) } // SortStrings sorts an array of strings in increasing order. func SortStrings(a []string) { Sort(StringArray(a)) } // IntsAreSorted tests whether an array of ints is sorted in increasing order. func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) } -// FloatsAreSorted tests whether an array of floats is sorted in increasing order. -func FloatsAreSorted(a []float) bool { return IsSorted(FloatArray(a)) } +// Float64sAreSorted tests whether an array of float64s is sorted in increasing order. +func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Array(a)) } // StringsAreSorted tests whether an array of strings is sorted in increasing order. func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) } diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go index 2085a67c8..1bea8f032 100644 --- a/src/pkg/sort/sort_test.go +++ b/src/pkg/sort/sort_test.go @@ -13,7 +13,7 @@ import ( var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} -var floats = [...]float{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} +var float64s = [...]float64{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8} var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} func TestSortIntArray(t *testing.T) { @@ -26,12 +26,12 @@ func TestSortIntArray(t *testing.T) { } } -func TestSortFloatArray(t *testing.T) { - data := floats - a := FloatArray(data[0:]) +func TestSortFloat64Array(t *testing.T) { + data := float64s + a := Float64Array(data[0:]) Sort(a) if !IsSorted(a) { - t.Errorf("sorted %v", floats) + t.Errorf("sorted %v", float64s) t.Errorf(" got %v", data) } } @@ -55,11 +55,11 @@ func TestSortInts(t *testing.T) { } } -func TestSortFloats(t *testing.T) { - data := floats - SortFloats(data[0:]) - if !FloatsAreSorted(data[0:]) { - t.Errorf("sorted %v", floats) +func TestSortFloat64s(t *testing.T) { + data := float64s + SortFloat64s(data[0:]) + if !Float64sAreSorted(data[0:]) { + t.Errorf("sorted %v", float64s) t.Errorf(" got %v", data) } } diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go index bcb138f7a..72f162c51 100644 --- a/src/pkg/strconv/atof.go +++ b/src/pkg/strconv/atof.go @@ -243,7 +243,7 @@ out: // Compute exact floating-point integer from d's digits. // Caller is responsible for avoiding overflow. func decimalAtof64Int(neg bool, d *decimal) float64 { - f := float64(0) + f := 0.0 for i := 0; i < d.nd; i++ { f = f*10 + float64(d.d[i]-'0') } @@ -400,17 +400,6 @@ func Atof64(s string) (f float64, err os.Error) { return f, err } -// Atof is like Atof32 or Atof64, depending on the size of float. -func Atof(s string) (f float, err os.Error) { - if FloatSize == 32 { - f1, err1 := Atof32(s) - return float(f1), err1 - } - f1, err1 := Atof64(s) - return float(f1), err1 -} - - // AtofN converts the string s to a 64-bit floating-point number, // but it rounds the result assuming that it will be stored in a value // of n bits (32 or 64). diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go index 68c50bfbe..6d8396ee7 100644 --- a/src/pkg/strconv/atof_test.go +++ b/src/pkg/strconv/atof_test.go @@ -103,6 +103,11 @@ var atoftests = []atofTest{ {"1e", "0", os.EINVAL}, {"1e-", "0", os.EINVAL}, {".e-1", "0", os.EINVAL}, + + // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + {"2.2250738585072012e-308", "2.2250738585072014e-308", nil}, + // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + {"2.2250738585072011e-308", "2.225073858507201e-308", nil}, } func init() { @@ -150,15 +155,6 @@ func testAtof(t *testing.T, opt bool) { test.in, out32, err, test.out, test.err, out) } } - - if FloatSize == 64 || float64(float32(out)) == out { - outf, err := Atof(test.in) - outs := Ftoa(outf, 'g', -1) - if outs != test.out || !reflect.DeepEqual(err, test.err) { - t.Errorf("Ftoa(%v) = %v, %v want %v, %v # %v", - test.in, outf, err, test.out, test.err, out) - } - } } SetOptimize(oldopt) } @@ -167,26 +163,26 @@ func TestAtof(t *testing.T) { testAtof(t, true) } func TestAtofSlow(t *testing.T) { testAtof(t, false) } -func BenchmarkAtofDecimal(b *testing.B) { +func BenchmarkAtof64Decimal(b *testing.B) { for i := 0; i < b.N; i++ { - Atof("33909") + Atof64("33909") } } -func BenchmarkAtofFloat(b *testing.B) { +func BenchmarkAtof64Float(b *testing.B) { for i := 0; i < b.N; i++ { - Atof("339.7784") + Atof64("339.7784") } } -func BenchmarkAtofFloatExp(b *testing.B) { +func BenchmarkAtof64FloatExp(b *testing.B) { for i := 0; i < b.N; i++ { - Atof("-5.09e75") + Atof64("-5.09e75") } } -func BenchmarkAtofBig(b *testing.B) { +func BenchmarkAtof64Big(b *testing.B) { for i := 0; i < b.N; i++ { - Atof("123456789123456789123456789") + Atof64("123456789123456789123456789") } } diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go index a6091fc6c..4ec3cdbb9 100644 --- a/src/pkg/strconv/ftoa.go +++ b/src/pkg/strconv/ftoa.go @@ -22,20 +22,6 @@ type floatInfo struct { var float32info = floatInfo{23, 8, -127} var float64info = floatInfo{52, 11, -1023} -func floatsize() int { - // Figure out whether float is float32 or float64. - // 1e-35 is representable in both, but 1e-70 - // is too small for a float32. - var f float = 1e-35 - if f*f == 0 { - return 32 - } - return 64 -} - -// Floatsize gives the size of the float type, either 32 or 64. -var FloatSize = floatsize() - // Ftoa32 converts the 32-bit floating-point number f to a string, // according to the format fmt and precision prec. // @@ -77,14 +63,6 @@ func FtoaN(f float64, fmt byte, prec int, n int) string { return Ftoa64(f, fmt, prec) } -// Ftoa behaves as Ftoa32 or Ftoa64, depending on the size of the float type. -func Ftoa(f float, fmt byte, prec int) string { - if FloatSize == 32 { - return Ftoa32(float32(f), fmt, prec) - } - return Ftoa64(float64(f), fmt, prec) -} - func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string { neg := bits>>flt.expbits>>flt.mantbits != 0 exp := int(bits>>flt.mantbits) & (1<<flt.expbits - 1) diff --git a/src/pkg/strconv/ftoa_test.go b/src/pkg/strconv/ftoa_test.go index 6044afdae..bc327600e 100644 --- a/src/pkg/strconv/ftoa_test.go +++ b/src/pkg/strconv/ftoa_test.go @@ -118,13 +118,15 @@ var ftoatests = []ftoaTest{ {0.5, 'f', 1, "0.5"}, {0.5, 'f', 0, "0"}, {1.5, 'f', 0, "2"}, + + // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, + // TODO: uncomment after fixing issue 1463. + // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, } func TestFtoa(t *testing.T) { - if FloatSize != 32 { - println("floatsize: ", FloatSize) - panic("floatsize") - } for i := 0; i < len(ftoatests); i++ { test := &ftoatests[i] s := Ftoa64(test.f, test.fmt, test.prec) diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go index 9a2bb2bb4..c4d82af00 100644 --- a/src/pkg/sync/mutex.go +++ b/src/pkg/sync/mutex.go @@ -5,7 +5,7 @@ // The sync package provides basic synchronization primitives // such as mutual exclusion locks. Other than the Once type, // most are intended for use by low-level library routines. -// Higher-level synchronization is better done via channels +// Higher-level synchronization is better done via channels // and communication. package sync diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go index 8c877cdec..b6f5f5a87 100644 --- a/src/pkg/sync/once.go +++ b/src/pkg/sync/once.go @@ -13,7 +13,7 @@ type Once struct { // Do calls the function f if and only if the method is being called for the // first time with this receiver. In other words, given // var once Once -// if Do(f) is called multiple times, only the first call will invoke f, +// if once.Do(f) is called multiple times, only the first call will invoke f, // even if f has a different value in each invocation. A new instance of // Once is required for each function to execute. // diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh index 3605b57b2..41acf95ec 100755 --- a/src/pkg/syscall/mkerrors.sh +++ b/src/pkg/syscall/mkerrors.sh @@ -35,16 +35,29 @@ includes_Linux=' ' includes_Darwin=' -#define __DARWIN_UNIX03 0 +#define _DARWIN_C_SOURCE #define KERNEL #define _DARWIN_USE_64_BIT_INODE +#include <sys/cdefs.h> #include <sys/wait.h> #include <sys/event.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> ' includes_FreeBSD=' #include <sys/wait.h> #include <sys/event.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/route.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_mroute.h> ' includes=' diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh index f5d4914cf..af95edd00 100755 --- a/src/pkg/syscall/mkerrors_windows.sh +++ b/src/pkg/syscall/mkerrors_windows.sh @@ -152,7 +152,7 @@ struct { int main(void) { - int i, j, e, iota = 1; + int i, e, iota = 1; char buf[1024]; printf("\n// Go names for Windows errors.\n"); @@ -169,11 +169,6 @@ main(void) printf("\n// Invented values to support what package os and others expects.\n"); printf("const (\n"); for(i=0; i<nelem(errors); i++) { - e = errors[i].value; - strcpy(buf, strerror(e)); - // lowercase first letter: Bad -> bad, but STREAM -> STREAM. - if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) - buf[0] += a - A; printf("\t%s", errors[i].name); if(iota) { printf(" = APPLICATION_ERROR + iota"); @@ -189,9 +184,6 @@ main(void) printf("var errors = [...]string {\n"); for(i=0; i<nelem(errors); i++) { e = errors[i].value; - for(j=0; j<i; j++) - if(errors[j].value == e) // duplicate value - goto next; strcpy(buf, strerror(e)); // lowercase first letter: Bad -> bad, but STREAM -> STREAM. if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) diff --git a/src/pkg/syscall/mksyscall_windows.sh b/src/pkg/syscall/mksyscall_windows.sh index 9695d3f22..3b1c9df85 100755 --- a/src/pkg/syscall/mksyscall_windows.sh +++ b/src/pkg/syscall/mksyscall_windows.sh @@ -105,7 +105,7 @@ while(<>) { # Returned value when failed if($failcond eq "") { - $failcond = "==0"; + $failcond = "== 0"; } # Decide which version of api is used: ascii or unicode. @@ -135,8 +135,8 @@ while(<>) { # Convert slice into pointer, length. # Have to be careful not to take address of &a[0] if len == 0: # pass nil in that case. - $text .= "\tvar _p$n *$1;\n"; - $text .= "\tif len($name) > 0 { _p$n = \&${name}[0]; }\n"; + $text .= "\tvar _p$n *$1\n"; + $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; $n++; } elsif($type eq "int64" && $_32bit ne "") { @@ -146,14 +146,15 @@ while(<>) { push @args, "uintptr($name)", "uintptr($name >> 32)"; } } elsif($type eq "bool") { - $text .= "\tvar _p$n uint32;\n"; - $text .= "\tif $name { _p$n = 1; } else { _p$n = 0;}\n"; + $text .= "\tvar _p$n uint32\n"; + $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; push @args, "uintptr(_p$n)"; } else { push @args, "uintptr($name)"; } push @pin, sprintf "\"%s=\", %s, ", $name, $name; } + my $nargs = @args; # Determine which form to use; pad args with zeros. my $asm = "Syscall"; @@ -182,7 +183,7 @@ while(<>) { # Actual call. my $args = join(', ', @args); - my $call = "$asm($sysvarname, $args)"; + my $call = "$asm($sysvarname, $nargs, $args)"; # Assign return values. my $body = ""; @@ -235,29 +236,29 @@ while(<>) { # Set errno to "last error" only if returned value indicate failure $body .= "\tif $failexpr {\n"; $body .= "\t\tif $reg != 0 {\n"; - $body .= "\t\t\t$name = $type($reg);\n"; + $body .= "\t\t\t$name = $type($reg)\n"; $body .= "\t\t} else {\n"; - $body .= "\t\t\t$name = EINVAL;\n"; + $body .= "\t\t\t$name = EINVAL\n"; $body .= "\t\t}\n"; $body .= "\t} else {\n"; - $body .= "\t\t$name = 0;\n"; + $body .= "\t\t$name = 0\n"; $body .= "\t}\n"; } else { - $body .= "\t$name = $rettype($reg);\n"; + $body .= "\t$name = $rettype($reg)\n"; } push @pout, sprintf "\"%s=\", %s, ", $name, $name; } if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { - $text .= "\t$call;\n"; + $text .= "\t$call\n"; } else { - $text .= "\t$ret[0], $ret[1], $ret[2] := $call;\n"; + $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; } $text .= $body; if(0) { $text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n"; } - $text .= "\treturn;\n"; + $text .= "\treturn\n"; $text .= "}\n\n"; } diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go index b7761a699..1647d69e5 100644 --- a/src/pkg/syscall/syscall.go +++ b/src/pkg/syscall/syscall.go @@ -13,10 +13,6 @@ // errno is an operating system error number describing the failure. package syscall -func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) -func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) -func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) - // StringByteSlice returns a NUL-terminated slice of bytes // containing the text of s. func StringByteSlice(s string) []byte { diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go index ff99fd9e6..3c4ac51dc 100644 --- a/src/pkg/syscall/syscall_bsd.go +++ b/src/pkg/syscall/syscall_bsd.go @@ -485,8 +485,8 @@ func Futimes(fd int, tv []Timeval) (errno int) { //sys fcntl(fd int, cmd int, arg int) (val int, errno int) -func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recvflags int, errno int) { - return 0, 0, 0, EAFNOSUPPORT +func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) { + return 0, 0, 0, nil, EAFNOSUPPORT } func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) { diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go index a65e41dc6..d20c035b5 100644 --- a/src/pkg/syscall/syscall_linux.go +++ b/src/pkg/syscall/syscall_linux.go @@ -253,12 +253,15 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) { for i := 0; i < n; i++ { sa.raw.Path[i] = int8(name[i]) } + // length is family (uint16), name, NUL. + sl := 2 + _Socklen(n) + 1 if sa.raw.Path[0] == '@' { sa.raw.Path[0] = 0 + // Don't count trailing NUL for abstract address. + sl-- } - // length is family, name, NUL. - return uintptr(unsafe.Pointer(&sa.raw)), 1 + _Socklen(n) + 1, 0 + return uintptr(unsafe.Pointer(&sa.raw)), sl, 0 } type SockaddrLinklayer struct { @@ -447,7 +450,7 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) { return sendto(fd, p, flags, ptr, n) } -func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recvflags int, errno int) { +func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) { var msg Msghdr var rsa RawSockaddrAny msg.Name = (*byte)(unsafe.Pointer(&rsa)) @@ -474,6 +477,10 @@ func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recv } oobn = int(msg.Controllen) recvflags = int(msg.Flags) + // source address is only specified if the socket is unconnected + if rsa.Addr.Family != 0 { + from, errno = anyToSockaddr(&rsa) + } return } diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go index c547ba5c5..c01eca17a 100644 --- a/src/pkg/syscall/syscall_unix.go +++ b/src/pkg/syscall/syscall_unix.go @@ -10,6 +10,10 @@ var ( Stderr = 2 ) +func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) +func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) +func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) + func Errstr(errno int) string { if errno < 0 || errno >= int(len(errors)) { return "error " + str(errno) diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go index 33a86ce25..762ed53db 100644 --- a/src/pkg/syscall/syscall_windows.go +++ b/src/pkg/syscall/syscall_windows.go @@ -44,7 +44,7 @@ func main() { if err != 0 { abort("GetProcAddress", err) } - r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0) + r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0) print_version(uint32(r)) } @@ -72,9 +72,11 @@ func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } // dll helpers -// implemented in ../pkg/runtime/windows/syscall.cgo -func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, lasterr uintptr) -func Syscall12(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, lasterr uintptr) +// implemented in ../runtime/windows/syscall.cgo +func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) +func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) +func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) +func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) func loadlibraryex(filename uintptr) (handle uint32) func getprocaddress(handle uint32, procname uintptr) (proc uintptr) @@ -94,6 +96,12 @@ func getSysProcAddr(m uint32, pname string) uintptr { return p } +// Converts a Go function to a function pointer conforming +// to the stdcall calling convention. This is useful when +// interoperating with Windows code requiring callbacks. +// Implemented in ../runtime/windows/syscall.cgo +func NewCallback(fn interface{}) uintptr + // windows api calls //sys GetLastError() (lasterrno int) @@ -126,6 +134,7 @@ func getSysProcAddr(m uint32, pname string) uintptr { //sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff] //sys CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int) //sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int) +//sys CancelIo(s uint32) (ok bool, errno int) //sys CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) = CreateProcessW //sys GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) = GetStartupInfoW //sys GetCurrentProcess() (pseudoHandle int32, errno int) @@ -708,6 +717,7 @@ const ( PTRACE_TRACEME = 1 + iota WNOHANG WSTOPPED + WUNTRACED SYS_CLOSE SYS_WRITE SYS_EXIT diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go index 16a24924d..8f5f69b5b 100644 --- a/src/pkg/syscall/zerrors_darwin_386.go +++ b/src/pkg/syscall/zerrors_darwin_386.go @@ -194,6 +194,7 @@ const ( F_GETLK = 0x7 F_GETOWN = 0x5 F_GETPATH = 0x32 + F_GETPROTECTIONCLASS = 0x3e F_GLOBAL_NOCACHE = 0x37 F_LOG2PHYS = 0x31 F_MARKDEPENDENCY = 0x3c @@ -210,12 +211,47 @@ const ( F_SETLK = 0x8 F_SETLKW = 0x9 F_SETOWN = 0x6 + F_SETPROTECTIONCLASS = 0x3f F_SETSIZE = 0x2b F_THAW_FS = 0x36 F_UNLCK = 0x2 F_VOLPOSMODE = 0x4 F_WRITEBOOTSTRAP = 0x2f F_WRLCK = 0x3 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LINKLOCALNETNUM = 0xa9fe0000 + IN_LOOPBACKNET = 0x7f IPPROTO_3PC = 0x22 IPPROTO_ADFS = 0x44 IPPROTO_AH = 0x33 @@ -423,6 +459,22 @@ const ( IP_TOS = 0x3 IP_TRAFFIC_MGT_BACKGROUND = 0x41 IP_TTL = 0x4 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_FLUSH = 0x400 + MSG_HAVEMORE = 0x2000 + MSG_HOLD = 0x800 + MSG_NEEDSA = 0x10000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_RCVMORE = 0x4000 + MSG_SEND = 0x1000 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITSTREAM = 0x200 O_ACCMODE = 0x3 O_ALERT = 0x20000000 O_APPEND = 0x8 @@ -446,6 +498,9 @@ const ( O_SYNC = 0x80 O_TRUNC = 0x400 O_WRONLY = 0x1 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 SHUT_RD = 0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -481,6 +536,76 @@ const ( SIGWINCH = 0x1c SIGXCPU = 0x18 SIGXFSZ = 0x19 + SIOCADDMULTI = 0x80206931 + SIOCAIFADDR = 0x8040691a + SIOCALIFADDR = 0x8118691d + SIOCARPIPLL = 0xc0206928 + SIOCATMARK = 0x40047307 + SIOCAUTOADDR = 0xc0206926 + SIOCAUTONETMASK = 0x80206927 + SIOCDELMULTI = 0x80206932 + SIOCDIFADDR = 0x80206919 + SIOCDIFPHYADDR = 0x80206941 + SIOCDLIFADDR = 0x8118691f + SIOCGDRVSPEC = 0xc01c697b + SIOCGETSGCNT = 0xc014721c + SIOCGETVIFCNT = 0xc014721b + SIOCGETVLAN = 0xc020697f + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0206921 + SIOCGIFALTMTU = 0xc0206948 + SIOCGIFASYNCMAP = 0xc020697c + SIOCGIFBOND = 0xc0206947 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCONF = 0xc0086924 + SIOCGIFDEVMTU = 0xc0206944 + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFKPI = 0xc0206987 + SIOCGIFMAC = 0xc0206982 + SIOCGIFMEDIA = 0xc0286938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206940 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc020693f + SIOCGIFSTATUS = 0xc331693d + SIOCGIFVLAN = 0xc020697f + SIOCGIFWAKEFLAGS = 0xc0206988 + SIOCGLIFADDR = 0xc118691e + SIOCGLIFPHYADDR = 0xc1186943 + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCIFCREATE = 0xc0206978 + SIOCIFCREATE2 = 0xc020697a + SIOCIFDESTROY = 0x80206979 + SIOCRSLVMULTI = 0xc008693b + SIOCSDRVSPEC = 0x801c697b + SIOCSETVLAN = 0x8020697e + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFALTMTU = 0x80206945 + SIOCSIFASYNCMAP = 0x8020697d + SIOCSIFBOND = 0x80206946 + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFKPI = 0x80206986 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206983 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x8040693e + SIOCSIFPHYS = 0x80206936 + SIOCSIFVLAN = 0x8020697e + SIOCSLIFPHYADDR = 0x81186942 + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 SOCK_DGRAM = 0x2 SOCK_MAXADDRLEN = 0xff SOCK_RAW = 0x3 @@ -577,7 +702,7 @@ const ( WNOHANG = 0x1 WNOWAIT = 0x20 WORDSIZE = 0x20 - WSTOPPED = 0x7f + WSTOPPED = 0x8 WUNTRACED = 0x2 ) diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go index 869c002d7..75174a0d2 100644 --- a/src/pkg/syscall/zerrors_darwin_amd64.go +++ b/src/pkg/syscall/zerrors_darwin_amd64.go @@ -194,6 +194,7 @@ const ( F_GETLK = 0x7 F_GETOWN = 0x5 F_GETPATH = 0x32 + F_GETPROTECTIONCLASS = 0x3e F_GLOBAL_NOCACHE = 0x37 F_LOG2PHYS = 0x31 F_MARKDEPENDENCY = 0x3c @@ -210,12 +211,47 @@ const ( F_SETLK = 0x8 F_SETLKW = 0x9 F_SETOWN = 0x6 + F_SETPROTECTIONCLASS = 0x3f F_SETSIZE = 0x2b F_THAW_FS = 0x36 F_UNLCK = 0x2 F_VOLPOSMODE = 0x4 F_WRITEBOOTSTRAP = 0x2f F_WRLCK = 0x3 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LINKLOCALNETNUM = 0xa9fe0000 + IN_LOOPBACKNET = 0x7f IPPROTO_3PC = 0x22 IPPROTO_ADFS = 0x44 IPPROTO_AH = 0x33 @@ -423,6 +459,22 @@ const ( IP_TOS = 0x3 IP_TRAFFIC_MGT_BACKGROUND = 0x41 IP_TTL = 0x4 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_FLUSH = 0x400 + MSG_HAVEMORE = 0x2000 + MSG_HOLD = 0x800 + MSG_NEEDSA = 0x10000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_RCVMORE = 0x4000 + MSG_SEND = 0x1000 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITSTREAM = 0x200 O_ACCMODE = 0x3 O_ALERT = 0x20000000 O_APPEND = 0x8 @@ -446,6 +498,9 @@ const ( O_SYNC = 0x80 O_TRUNC = 0x400 O_WRONLY = 0x1 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 SHUT_RD = 0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -481,6 +536,76 @@ const ( SIGWINCH = 0x1c SIGXCPU = 0x18 SIGXFSZ = 0x19 + SIOCADDMULTI = 0x80206931 + SIOCAIFADDR = 0x8040691a + SIOCALIFADDR = 0x8118691d + SIOCARPIPLL = 0xc0206928 + SIOCATMARK = 0x40047307 + SIOCAUTOADDR = 0xc0206926 + SIOCAUTONETMASK = 0x80206927 + SIOCDELMULTI = 0x80206932 + SIOCDIFADDR = 0x80206919 + SIOCDIFPHYADDR = 0x80206941 + SIOCDLIFADDR = 0x8118691f + SIOCGDRVSPEC = 0xc028697b + SIOCGETSGCNT = 0xc014721c + SIOCGETVIFCNT = 0xc014721b + SIOCGETVLAN = 0xc020697f + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0206921 + SIOCGIFALTMTU = 0xc0206948 + SIOCGIFASYNCMAP = 0xc020697c + SIOCGIFBOND = 0xc0206947 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCONF = 0xc00c6924 + SIOCGIFDEVMTU = 0xc0206944 + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFKPI = 0xc0206987 + SIOCGIFMAC = 0xc0206982 + SIOCGIFMEDIA = 0xc02c6938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206940 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc020693f + SIOCGIFSTATUS = 0xc331693d + SIOCGIFVLAN = 0xc020697f + SIOCGIFWAKEFLAGS = 0xc0206988 + SIOCGLIFADDR = 0xc118691e + SIOCGLIFPHYADDR = 0xc1186943 + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCIFCREATE = 0xc0206978 + SIOCIFCREATE2 = 0xc020697a + SIOCIFDESTROY = 0x80206979 + SIOCRSLVMULTI = 0xc010693b + SIOCSDRVSPEC = 0x8028697b + SIOCSETVLAN = 0x8020697e + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFALTMTU = 0x80206945 + SIOCSIFASYNCMAP = 0x8020697d + SIOCSIFBOND = 0x80206946 + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFKPI = 0x80206986 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206983 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x8040693e + SIOCSIFPHYS = 0x80206936 + SIOCSIFVLAN = 0x8020697e + SIOCSLIFPHYADDR = 0x81186942 + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 SOCK_DGRAM = 0x2 SOCK_MAXADDRLEN = 0xff SOCK_RAW = 0x3 @@ -577,7 +702,7 @@ const ( WNOHANG = 0x1 WNOWAIT = 0x20 WORDSIZE = 0x40 - WSTOPPED = 0x7f + WSTOPPED = 0x8 WUNTRACED = 0x2 ) diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go index 830fe7471..5af1d4a1a 100644 --- a/src/pkg/syscall/zerrors_freebsd_386.go +++ b/src/pkg/syscall/zerrors_freebsd_386.go @@ -130,7 +130,7 @@ const ( EIO = 0x5 EISCONN = 0x38 EISDIR = 0x15 - ELAST = 0x5c + ELAST = 0x5d ELOOP = 0x3e EMFILE = 0x18 EMLINK = 0x1f @@ -155,6 +155,7 @@ const ( ENOSPC = 0x1c ENOSYS = 0x4e ENOTBLK = 0xf + ENOTCAPABLE = 0x5d ENOTCONN = 0x39 ENOTDIR = 0x14 ENOTEMPTY = 0x42 @@ -190,23 +191,25 @@ const ( EVFILT_AIO = -0x3 EVFILT_FS = -0x9 EVFILT_LIO = -0xa - EVFILT_NETDEV = -0x8 EVFILT_PROC = -0x5 EVFILT_READ = -0x1 EVFILT_SIGNAL = -0x6 - EVFILT_SYSCOUNT = 0xa + EVFILT_SYSCOUNT = 0xb EVFILT_TIMER = -0x7 + EVFILT_USER = -0xb EVFILT_VNODE = -0x4 EVFILT_WRITE = -0x2 EV_ADD = 0x1 EV_CLEAR = 0x20 EV_DELETE = 0x2 EV_DISABLE = 0x8 + EV_DISPATCH = 0x80 EV_ENABLE = 0x4 EV_EOF = 0x8000 EV_ERROR = 0x4000 EV_FLAG1 = 0x2000 EV_ONESHOT = 0x10 + EV_RECEIPT = 0x40 EV_SYSFLAGS = 0xf000 EWOULDBLOCK = 0x23 EXDEV = 0x12 @@ -222,7 +225,9 @@ const ( F_OGETLK = 0x7 F_OSETLK = 0x8 F_OSETLKW = 0x9 + F_RDAHEAD = 0x10 F_RDLCK = 0x1 + F_READAHEAD = 0xf F_SETFD = 0x2 F_SETFL = 0x4 F_SETLK = 0xc @@ -232,6 +237,47 @@ const ( F_UNLCK = 0x2 F_UNLCKSYS = 0x4 F_WRLCK = 0x3 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x208f72 + IFF_DEBUG = 0x4 + IFF_DRV_OACTIVE = 0x400 + IFF_DRV_RUNNING = 0x40 + IFF_DYING = 0x200000 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MONITOR = 0x40000 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PPROMISC = 0x20000 + IFF_PROMISC = 0x100 + IFF_RENAMING = 0x400000 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_SMART = 0x20 + IFF_STATICARP = 0x80000 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f IPPROTO_3PC = 0x22 IPPROTO_ADFS = 0x44 IPPROTO_AH = 0x33 @@ -348,6 +394,7 @@ const ( IPPROTO_XNET = 0xf IPPROTO_XTP = 0x24 IPV6_AUTOFLOWLABEL = 0x3b + IPV6_BINDANY = 0x40 IPV6_BINDV6ONLY = 0x1b IPV6_CHECKSUM = 0x1a IPV6_DEFAULT_MULTICAST_HOPS = 0x1 @@ -373,6 +420,10 @@ const ( IPV6_MAXHLIM = 0xff IPV6_MAXOPTHDR = 0x800 IPV6_MAXPACKET = 0xffff + IPV6_MAX_GROUP_SRC_FILTER = 0x200 + IPV6_MAX_MEMBERSHIPS = 0xfff + IPV6_MAX_SOCK_SRC_FILTER = 0x80 + IPV6_MIN_MEMBERSHIPS = 0x1f IPV6_MMTU = 0x500 IPV6_MSFILTER = 0x4a IPV6_MULTICAST_HOPS = 0xa @@ -407,6 +458,7 @@ const ( IPV6_VERSION_MASK = 0xf0 IP_ADD_MEMBERSHIP = 0xc IP_ADD_SOURCE_MEMBERSHIP = 0x46 + IP_BINDANY = 0x18 IP_BLOCK_SOURCE = 0x48 IP_DEFAULT_MULTICAST_LOOP = 0x1 IP_DEFAULT_MULTICAST_TTL = 0x1 @@ -439,7 +491,10 @@ const ( IP_HDRINCL = 0x2 IP_IPSEC_POLICY = 0x15 IP_MAXPACKET = 0xffff + IP_MAX_GROUP_SRC_FILTER = 0x200 IP_MAX_MEMBERSHIPS = 0xfff + IP_MAX_SOCK_MUTE_FILTER = 0x80 + IP_MAX_SOCK_SRC_FILTER = 0x80 IP_MAX_SOURCE_FILTER = 0x400 IP_MF = 0x2000 IP_MINTTL = 0x42 @@ -472,12 +527,27 @@ const ( IP_TOS = 0x3 IP_TTL = 0x4 IP_UNBLOCK_SOURCE = 0x49 + MSG_COMPAT = 0x8000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_NBIO = 0x4000 + MSG_NOSIGNAL = 0x20000 + MSG_NOTIFICATION = 0x2000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x40 O_CREAT = 0x200 O_DIRECT = 0x10000 + O_DIRECTORY = 0x20000 O_EXCL = 0x800 + O_EXEC = 0x40000 O_EXLOCK = 0x20 O_FSYNC = 0x80 O_NDELAY = 0x4 @@ -489,7 +559,12 @@ const ( O_SHLOCK = 0x10 O_SYNC = 0x80 O_TRUNC = 0x400 + O_TTY_INIT = 0x80000 O_WRONLY = 0x1 + SCM_BINTIME = 0x4 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 SHUT_RD = 0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -527,6 +602,75 @@ const ( SIGWINCH = 0x1c SIGXCPU = 0x18 SIGXFSZ = 0x19 + SIOCADDMULTI = 0x80206931 + SIOCADDRT = 0x8030720a + SIOCAIFADDR = 0x8040691a + SIOCAIFGROUP = 0x80246987 + SIOCALIFADDR = 0x8118691b + SIOCATMARK = 0x40047307 + SIOCDELMULTI = 0x80206932 + SIOCDELRT = 0x8030720b + SIOCDIFADDR = 0x80206919 + SIOCDIFGROUP = 0x80246989 + SIOCDIFPHYADDR = 0x80206949 + SIOCDLIFADDR = 0x8118691d + SIOCGDRVSPEC = 0xc01c697b + SIOCGETSGCNT = 0xc0147210 + SIOCGETVIFCNT = 0xc014720f + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0206921 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCAP = 0xc020691f + SIOCGIFCONF = 0xc0086924 + SIOCGIFDESCR = 0xc020692a + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFGMEMB = 0xc024698a + SIOCGIFGROUP = 0xc0246988 + SIOCGIFINDEX = 0xc0206920 + SIOCGIFMAC = 0xc0206926 + SIOCGIFMEDIA = 0xc0286938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206948 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc0206947 + SIOCGIFSTATUS = 0xc331693b + SIOCGLIFADDR = 0xc118691c + SIOCGLIFPHYADDR = 0xc118694b + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCGPRIVATE_0 = 0xc0206950 + SIOCGPRIVATE_1 = 0xc0206951 + SIOCIFCREATE = 0xc020697a + SIOCIFCREATE2 = 0xc020697c + SIOCIFDESTROY = 0x80206979 + SIOCIFGCLONERS = 0xc00c6978 + SIOCSDRVSPEC = 0x801c697b + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFCAP = 0x8020691e + SIOCSIFDESCR = 0x80206929 + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206927 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNAME = 0x80206928 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x80406946 + SIOCSIFPHYS = 0x80206936 + SIOCSIFRVNET = 0xc020695b + SIOCSIFVNET = 0xc020695a + SIOCSLIFPHYADDR = 0x8118694a + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 SOCK_DGRAM = 0x2 SOCK_MAXADDRLEN = 0xff SOCK_RAW = 0x3 @@ -687,4 +831,5 @@ var errors = [...]string{ 90: "multihop attempted", 91: "link has been severed", 92: "protocol error", + 93: "capabilities insufficient", } diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go index 1ccafae30..7e9d85754 100644 --- a/src/pkg/syscall/zerrors_freebsd_amd64.go +++ b/src/pkg/syscall/zerrors_freebsd_amd64.go @@ -130,7 +130,7 @@ const ( EIO = 0x5 EISCONN = 0x38 EISDIR = 0x15 - ELAST = 0x5c + ELAST = 0x5d ELOOP = 0x3e EMFILE = 0x18 EMLINK = 0x1f @@ -155,6 +155,7 @@ const ( ENOSPC = 0x1c ENOSYS = 0x4e ENOTBLK = 0xf + ENOTCAPABLE = 0x5d ENOTCONN = 0x39 ENOTDIR = 0x14 ENOTEMPTY = 0x42 @@ -190,23 +191,25 @@ const ( EVFILT_AIO = -0x3 EVFILT_FS = -0x9 EVFILT_LIO = -0xa - EVFILT_NETDEV = -0x8 EVFILT_PROC = -0x5 EVFILT_READ = -0x1 EVFILT_SIGNAL = -0x6 - EVFILT_SYSCOUNT = 0xa + EVFILT_SYSCOUNT = 0xb EVFILT_TIMER = -0x7 + EVFILT_USER = -0xb EVFILT_VNODE = -0x4 EVFILT_WRITE = -0x2 EV_ADD = 0x1 EV_CLEAR = 0x20 EV_DELETE = 0x2 EV_DISABLE = 0x8 + EV_DISPATCH = 0x80 EV_ENABLE = 0x4 EV_EOF = 0x8000 EV_ERROR = 0x4000 EV_FLAG1 = 0x2000 EV_ONESHOT = 0x10 + EV_RECEIPT = 0x40 EV_SYSFLAGS = 0xf000 EWOULDBLOCK = 0x23 EXDEV = 0x12 @@ -222,7 +225,9 @@ const ( F_OGETLK = 0x7 F_OSETLK = 0x8 F_OSETLKW = 0x9 + F_RDAHEAD = 0x10 F_RDLCK = 0x1 + F_READAHEAD = 0xf F_SETFD = 0x2 F_SETFL = 0x4 F_SETLK = 0xc @@ -232,6 +237,47 @@ const ( F_UNLCK = 0x2 F_UNLCKSYS = 0x4 F_WRLCK = 0x3 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_CANTCHANGE = 0x208f72 + IFF_DEBUG = 0x4 + IFF_DRV_OACTIVE = 0x400 + IFF_DRV_RUNNING = 0x40 + IFF_DYING = 0x200000 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MONITOR = 0x40000 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PPROMISC = 0x20000 + IFF_PROMISC = 0x100 + IFF_RENAMING = 0x400000 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_SMART = 0x20 + IFF_STATICARP = 0x80000 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LOOPBACKNET = 0x7f IPPROTO_3PC = 0x22 IPPROTO_ADFS = 0x44 IPPROTO_AH = 0x33 @@ -420,11 +466,13 @@ const ( IP_DONTFRAG = 0x43 IP_DROP_MEMBERSHIP = 0xd IP_DROP_SOURCE_MEMBERSHIP = 0x47 + IP_DUMMYNET3 = 0x31 IP_DUMMYNET_CONFIGURE = 0x3c IP_DUMMYNET_DEL = 0x3d IP_DUMMYNET_FLUSH = 0x3e IP_DUMMYNET_GET = 0x40 IP_FAITH = 0x16 + IP_FW3 = 0x30 IP_FW_ADD = 0x32 IP_FW_DEL = 0x33 IP_FW_FLUSH = 0x34 @@ -479,6 +527,19 @@ const ( IP_TOS = 0x3 IP_TTL = 0x4 IP_UNBLOCK_SOURCE = 0x49 + MSG_COMPAT = 0x8000 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_NBIO = 0x4000 + MSG_NOSIGNAL = 0x20000 + MSG_NOTIFICATION = 0x2000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 O_ACCMODE = 0x3 O_APPEND = 0x8 O_ASYNC = 0x40 @@ -500,6 +561,10 @@ const ( O_TRUNC = 0x400 O_TTY_INIT = 0x80000 O_WRONLY = 0x1 + SCM_BINTIME = 0x4 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 SHUT_RD = 0 SHUT_RDWR = 0x2 SHUT_WR = 0x1 @@ -537,6 +602,76 @@ const ( SIGWINCH = 0x1c SIGXCPU = 0x18 SIGXFSZ = 0x19 + SIOCADDMULTI = 0x80206931 + SIOCADDRT = 0x8040720a + SIOCAIFADDR = 0x8040691a + SIOCAIFGROUP = 0x80286987 + SIOCALIFADDR = 0x8118691b + SIOCATMARK = 0x40047307 + SIOCDELMULTI = 0x80206932 + SIOCDELRT = 0x8040720b + SIOCDIFADDR = 0x80206919 + SIOCDIFGROUP = 0x80286989 + SIOCDIFPHYADDR = 0x80206949 + SIOCDLIFADDR = 0x8118691d + SIOCGDRVSPEC = 0xc028697b + SIOCGETSGCNT = 0xc0207210 + SIOCGETVIFCNT = 0xc028720f + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0206921 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCAP = 0xc020691f + SIOCGIFCONF = 0xc0106924 + SIOCGIFCONF32 = 0xc0086924 + SIOCGIFDESCR = 0xc020692a + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFGMEMB = 0xc028698a + SIOCGIFGROUP = 0xc0286988 + SIOCGIFINDEX = 0xc0206920 + SIOCGIFMAC = 0xc0206926 + SIOCGIFMEDIA = 0xc0306938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206948 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc0206947 + SIOCGIFSTATUS = 0xc331693b + SIOCGLIFADDR = 0xc118691c + SIOCGLIFPHYADDR = 0xc118694b + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCGPRIVATE_0 = 0xc0206950 + SIOCGPRIVATE_1 = 0xc0206951 + SIOCIFCREATE = 0xc020697a + SIOCIFCREATE2 = 0xc020697c + SIOCIFDESTROY = 0x80206979 + SIOCIFGCLONERS = 0xc0106978 + SIOCSDRVSPEC = 0x8028697b + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFCAP = 0x8020691e + SIOCSIFDESCR = 0x80206929 + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206927 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNAME = 0x80206928 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x80406946 + SIOCSIFPHYS = 0x80206936 + SIOCSIFRVNET = 0xc020695b + SIOCSIFVNET = 0xc020695a + SIOCSLIFPHYADDR = 0x8118694a + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 SOCK_DGRAM = 0x2 SOCK_MAXADDRLEN = 0xff SOCK_RAW = 0x3 @@ -697,4 +832,5 @@ var errors = [...]string{ 90: "multihop attempted", 91: "link has been severed", 92: "protocol error", + 93: "capabilities insufficient", } diff --git a/src/pkg/syscall/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows_386.go index a6bed6ea6..ae4506fac 100644 --- a/src/pkg/syscall/zerrors_windows_386.go +++ b/src/pkg/syscall/zerrors_windows_386.go @@ -174,6 +174,7 @@ var errors = [...]string{ ECONNREFUSED - APPLICATION_ERROR: "connection refused", ECONNRESET - APPLICATION_ERROR: "connection reset by peer", EDEADLK - APPLICATION_ERROR: "resource deadlock avoided", + EDEADLOCK - APPLICATION_ERROR: "resource deadlock avoided", EDESTADDRREQ - APPLICATION_ERROR: "destination address required", EDOM - APPLICATION_ERROR: "numerical argument out of domain", EDOTDOT - APPLICATION_ERROR: "RFS specific error", @@ -246,6 +247,7 @@ var errors = [...]string{ ENOTTY - APPLICATION_ERROR: "inappropriate ioctl for device", ENOTUNIQ - APPLICATION_ERROR: "name not unique on network", ENXIO - APPLICATION_ERROR: "no such device or address", + EOPNOTSUPP - APPLICATION_ERROR: "operation not supported", EOVERFLOW - APPLICATION_ERROR: "value too large for defined data type", EOWNERDEAD - APPLICATION_ERROR: "owner died", EPERM - APPLICATION_ERROR: "operation not permitted", @@ -274,6 +276,7 @@ var errors = [...]string{ EUCLEAN - APPLICATION_ERROR: "structure needs cleaning", EUNATCH - APPLICATION_ERROR: "protocol driver not attached", EUSERS - APPLICATION_ERROR: "too many users", + EWOULDBLOCK - APPLICATION_ERROR: "resource temporarily unavailable", EXDEV - APPLICATION_ERROR: "invalid cross-device link", EXFULL - APPLICATION_ERROR: "exchange full", EWINDOWS - APPLICATION_ERROR: "not supported by windows", diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go index 29880f2b2..b71177e42 100644 --- a/src/pkg/syscall/zsyscall_windows_386.go +++ b/src/pkg/syscall/zsyscall_windows_386.go @@ -43,6 +43,7 @@ var ( procGetTimeZoneInformation = getSysProcAddr(modkernel32, "GetTimeZoneInformation") procCreateIoCompletionPort = getSysProcAddr(modkernel32, "CreateIoCompletionPort") procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus") + procCancelIo = getSysProcAddr(modkernel32, "CancelIo") procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW") procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW") procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess") @@ -90,13 +91,13 @@ var ( ) func GetLastError() (lasterrno int) { - r0, _, _ := Syscall(procGetLastError, 0, 0, 0) + r0, _, _ := Syscall(procGetLastError, 0, 0, 0, 0) lasterrno = int(r0) return } func LoadLibrary(libname string) (handle uint32, errno int) { - r0, _, e1 := Syscall(procLoadLibraryW, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0) + r0, _, e1 := Syscall(procLoadLibraryW, 1, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0) handle = uint32(r0) if handle == 0 { if e1 != 0 { @@ -111,7 +112,7 @@ func LoadLibrary(libname string) (handle uint32, errno int) { } func FreeLibrary(handle uint32) (ok bool, errno int) { - r0, _, e1 := Syscall(procFreeLibrary, uintptr(handle), 0, 0) + r0, _, e1 := Syscall(procFreeLibrary, 1, uintptr(handle), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -126,7 +127,7 @@ func FreeLibrary(handle uint32) (ok bool, errno int) { } func GetProcAddress(module uint32, procname string) (proc uint32, errno int) { - r0, _, e1 := Syscall(procGetProcAddress, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0) + r0, _, e1 := Syscall(procGetProcAddress, 2, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0) proc = uint32(r0) if proc == 0 { if e1 != 0 { @@ -141,7 +142,7 @@ func GetProcAddress(module uint32, procname string) (proc uint32, errno int) { } func GetVersion() (ver uint32, errno int) { - r0, _, e1 := Syscall(procGetVersion, 0, 0, 0) + r0, _, e1 := Syscall(procGetVersion, 0, 0, 0, 0) ver = uint32(r0) if ver == 0 { if e1 != 0 { @@ -160,7 +161,7 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf if len(buf) > 0 { _p0 = &buf[0] } - r0, _, e1 := Syscall9(procFormatMessageW, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) + r0, _, e1 := Syscall9(procFormatMessageW, 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0) n = uint32(r0) if n == 0 { if e1 != 0 { @@ -175,12 +176,12 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf } func ExitProcess(exitcode uint32) { - Syscall(procExitProcess, uintptr(exitcode), 0, 0) + Syscall(procExitProcess, 1, uintptr(exitcode), 0, 0) return } func CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) { - r0, _, e1 := Syscall9(procCreateFileW, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) + r0, _, e1 := Syscall9(procCreateFileW, 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0) handle = int32(r0) if handle == -1 { if e1 != 0 { @@ -199,7 +200,7 @@ func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (o if len(buf) > 0 { _p0 = &buf[0] } - r0, _, e1 := Syscall6(procReadFile, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + r0, _, e1 := Syscall6(procReadFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -218,7 +219,7 @@ func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) ( if len(buf) > 0 { _p0 = &buf[0] } - r0, _, e1 := Syscall6(procWriteFile, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) + r0, _, e1 := Syscall6(procWriteFile, 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -233,7 +234,7 @@ func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) ( } func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) { - r0, _, e1 := Syscall6(procSetFilePointer, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) + r0, _, e1 := Syscall6(procSetFilePointer, 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0) newlowoffset = uint32(r0) if newlowoffset == 0xffffffff { if e1 != 0 { @@ -248,7 +249,7 @@ func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence } func CloseHandle(handle int32) (ok bool, errno int) { - r0, _, e1 := Syscall(procCloseHandle, uintptr(handle), 0, 0) + r0, _, e1 := Syscall(procCloseHandle, 1, uintptr(handle), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -263,7 +264,7 @@ func CloseHandle(handle int32) (ok bool, errno int) { } func GetStdHandle(stdhandle int32) (handle int32, errno int) { - r0, _, e1 := Syscall(procGetStdHandle, uintptr(stdhandle), 0, 0) + r0, _, e1 := Syscall(procGetStdHandle, 1, uintptr(stdhandle), 0, 0) handle = int32(r0) if handle == -1 { if e1 != 0 { @@ -278,7 +279,7 @@ func GetStdHandle(stdhandle int32) (handle int32, errno int) { } func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) { - r0, _, e1 := Syscall(procFindFirstFileW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) + r0, _, e1 := Syscall(procFindFirstFileW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0) handle = int32(r0) if handle == -1 { if e1 != 0 { @@ -293,7 +294,7 @@ func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) } func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) { - r0, _, e1 := Syscall(procFindNextFileW, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + r0, _, e1 := Syscall(procFindNextFileW, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -308,7 +309,7 @@ func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) { } func FindClose(handle int32) (ok bool, errno int) { - r0, _, e1 := Syscall(procFindClose, uintptr(handle), 0, 0) + r0, _, e1 := Syscall(procFindClose, 1, uintptr(handle), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -323,7 +324,7 @@ func FindClose(handle int32) (ok bool, errno int) { } func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok bool, errno int) { - r0, _, e1 := Syscall(procGetFileInformationByHandle, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) + r0, _, e1 := Syscall(procGetFileInformationByHandle, 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -338,7 +339,7 @@ func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok } func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) { - r0, _, e1 := Syscall(procGetCurrentDirectoryW, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + r0, _, e1 := Syscall(procGetCurrentDirectoryW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) n = uint32(r0) if n == 0 { if e1 != 0 { @@ -353,7 +354,7 @@ func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) { } func SetCurrentDirectory(path *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procSetCurrentDirectoryW, uintptr(unsafe.Pointer(path)), 0, 0) + r0, _, e1 := Syscall(procSetCurrentDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -368,7 +369,7 @@ func SetCurrentDirectory(path *uint16) (ok bool, errno int) { } func CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) { - r0, _, e1 := Syscall(procCreateDirectoryW, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) + r0, _, e1 := Syscall(procCreateDirectoryW, 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -383,7 +384,7 @@ func CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) { } func RemoveDirectory(path *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procRemoveDirectoryW, uintptr(unsafe.Pointer(path)), 0, 0) + r0, _, e1 := Syscall(procRemoveDirectoryW, 1, uintptr(unsafe.Pointer(path)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -398,7 +399,7 @@ func RemoveDirectory(path *uint16) (ok bool, errno int) { } func DeleteFile(path *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procDeleteFileW, uintptr(unsafe.Pointer(path)), 0, 0) + r0, _, e1 := Syscall(procDeleteFileW, 1, uintptr(unsafe.Pointer(path)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -413,7 +414,7 @@ func DeleteFile(path *uint16) (ok bool, errno int) { } func MoveFile(from *uint16, to *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procMoveFileW, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) + r0, _, e1 := Syscall(procMoveFileW, 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -428,7 +429,7 @@ func MoveFile(from *uint16, to *uint16) (ok bool, errno int) { } func GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) { - r0, _, e1 := Syscall(procGetComputerNameW, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) + r0, _, e1 := Syscall(procGetComputerNameW, 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -443,7 +444,7 @@ func GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) { } func SetEndOfFile(handle int32) (ok bool, errno int) { - r0, _, e1 := Syscall(procSetEndOfFile, uintptr(handle), 0, 0) + r0, _, e1 := Syscall(procSetEndOfFile, 1, uintptr(handle), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -458,17 +459,17 @@ func SetEndOfFile(handle int32) (ok bool, errno int) { } func GetSystemTimeAsFileTime(time *Filetime) { - Syscall(procGetSystemTimeAsFileTime, uintptr(unsafe.Pointer(time)), 0, 0) + Syscall(procGetSystemTimeAsFileTime, 1, uintptr(unsafe.Pointer(time)), 0, 0) return } func sleep(msec uint32) { - Syscall(procSleep, uintptr(msec), 0, 0) + Syscall(procSleep, 1, uintptr(msec), 0, 0) return } func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) { - r0, _, e1 := Syscall(procGetTimeZoneInformation, uintptr(unsafe.Pointer(tzi)), 0, 0) + r0, _, e1 := Syscall(procGetTimeZoneInformation, 1, uintptr(unsafe.Pointer(tzi)), 0, 0) rc = uint32(r0) if rc == 0xffffffff { if e1 != 0 { @@ -483,7 +484,7 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) { } func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int) { - r0, _, e1 := Syscall6(procCreateIoCompletionPort, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) + r0, _, e1 := Syscall6(procCreateIoCompletionPort, 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) handle = int32(r0) if handle == 0 { if e1 != 0 { @@ -498,7 +499,22 @@ func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, thread } func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int) { - r0, _, e1 := Syscall6(procGetQueuedCompletionStatus, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + r0, _, e1 := Syscall6(procGetQueuedCompletionStatus, 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0) + ok = bool(r0 != 0) + if !ok { + if e1 != 0 { + errno = int(e1) + } else { + errno = EINVAL + } + } else { + errno = 0 + } + return +} + +func CancelIo(s uint32) (ok bool, errno int) { + r0, _, e1 := Syscall(procCancelIo, 1, uintptr(s), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -519,7 +535,7 @@ func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, thr } else { _p0 = 0 } - r0, _, e1 := Syscall12(procCreateProcessW, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) + r0, _, e1 := Syscall12(procCreateProcessW, 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -534,7 +550,7 @@ func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, thr } func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) { - r0, _, e1 := Syscall(procGetStartupInfoW, uintptr(unsafe.Pointer(startupInfo)), 0, 0) + r0, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -549,7 +565,7 @@ func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) { } func GetCurrentProcess() (pseudoHandle int32, errno int) { - r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0) + r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0, 0) pseudoHandle = int32(r0) if pseudoHandle == 0 { if e1 != 0 { @@ -570,7 +586,7 @@ func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetPro } else { _p0 = 0 } - r0, _, e1 := Syscall9(procDuplicateHandle, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) + r0, _, e1 := Syscall9(procDuplicateHandle, 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -585,7 +601,7 @@ func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetPro } func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) { - r0, _, e1 := Syscall(procWaitForSingleObject, uintptr(handle), uintptr(waitMilliseconds), 0) + r0, _, e1 := Syscall(procWaitForSingleObject, 2, uintptr(handle), uintptr(waitMilliseconds), 0) event = uint32(r0) if event == 0xffffffff { if e1 != 0 { @@ -600,7 +616,7 @@ func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, e } func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) { - r0, _, e1 := Syscall(procGetTempPathW, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + r0, _, e1 := Syscall(procGetTempPathW, 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) n = uint32(r0) if n == 0 { if e1 != 0 { @@ -615,7 +631,7 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) { } func CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32) (ok bool, errno int) { - r0, _, e1 := Syscall6(procCreatePipe, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(lpsa)), uintptr(size), 0, 0) + r0, _, e1 := Syscall6(procCreatePipe, 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(lpsa)), uintptr(size), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -630,7 +646,7 @@ func CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32 } func GetFileType(filehandle uint32) (n uint32, errno int) { - r0, _, e1 := Syscall(procGetFileType, uintptr(filehandle), 0, 0) + r0, _, e1 := Syscall(procGetFileType, 1, uintptr(filehandle), 0, 0) n = uint32(r0) if n == 0 { if e1 != 0 { @@ -645,7 +661,7 @@ func GetFileType(filehandle uint32) (n uint32, errno int) { } func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) { - r0, _, e1 := Syscall6(procCryptAcquireContextW, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) + r0, _, e1 := Syscall6(procCryptAcquireContextW, 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -660,7 +676,7 @@ func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16 } func CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) { - r0, _, e1 := Syscall(procCryptReleaseContext, uintptr(provhandle), uintptr(flags), 0) + r0, _, e1 := Syscall(procCryptReleaseContext, 2, uintptr(provhandle), uintptr(flags), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -675,7 +691,7 @@ func CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) { } func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) { - r0, _, e1 := Syscall(procCryptGenRandom, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) + r0, _, e1 := Syscall(procCryptGenRandom, 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf))) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -690,7 +706,7 @@ func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno } func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) { - r0, _, e1 := Syscall(procOpenProcess, uintptr(da), uintptr(b), uintptr(pid)) + r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(b), uintptr(pid)) handle = uint32(r0) if handle == 0 { if e1 != 0 { @@ -705,7 +721,7 @@ func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) { } func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) { - r0, _, e1 := Syscall(procGetExitCodeProcess, uintptr(h), uintptr(unsafe.Pointer(c)), 0) + r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(h), uintptr(unsafe.Pointer(c)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -720,7 +736,7 @@ func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) { } func GetEnvironmentStrings() (envs *uint16, errno int) { - r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0) + r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0, 0) envs = (*uint16)(unsafe.Pointer(r0)) if envs == nil { if e1 != 0 { @@ -735,7 +751,7 @@ func GetEnvironmentStrings() (envs *uint16, errno int) { } func FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procFreeEnvironmentStringsW, uintptr(unsafe.Pointer(envs)), 0, 0) + r0, _, e1 := Syscall(procFreeEnvironmentStringsW, 1, uintptr(unsafe.Pointer(envs)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -750,7 +766,7 @@ func FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) { } func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) { - r0, _, e1 := Syscall(procGetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) + r0, _, e1 := Syscall(procGetEnvironmentVariableW, 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size)) n = uint32(r0) if n == 0 { if e1 != 0 { @@ -765,7 +781,7 @@ func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32 } func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) { - r0, _, e1 := Syscall(procSetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) + r0, _, e1 := Syscall(procSetEnvironmentVariableW, 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -780,7 +796,7 @@ func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) { } func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (ok bool, errno int) { - r0, _, e1 := Syscall6(procSetFileTime, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) + r0, _, e1 := Syscall6(procSetFileTime, 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -795,7 +811,7 @@ func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime } func GetFileAttributes(name *uint16) (attrs uint32, errno int) { - r0, _, e1 := Syscall(procGetFileAttributesW, uintptr(unsafe.Pointer(name)), 0, 0) + r0, _, e1 := Syscall(procGetFileAttributesW, 1, uintptr(unsafe.Pointer(name)), 0, 0) attrs = uint32(r0) if attrs == INVALID_FILE_ATTRIBUTES { if e1 != 0 { @@ -810,13 +826,13 @@ func GetFileAttributes(name *uint16) (attrs uint32, errno int) { } func GetCommandLine() (cmd *uint16) { - r0, _, _ := Syscall(procGetCommandLineW, 0, 0, 0) + r0, _, _ := Syscall(procGetCommandLineW, 0, 0, 0, 0) cmd = (*uint16)(unsafe.Pointer(r0)) return } func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) { - r0, _, e1 := Syscall(procCommandLineToArgvW, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) + r0, _, e1 := Syscall(procCommandLineToArgvW, 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) if argv == nil { if e1 != 0 { @@ -831,7 +847,7 @@ func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err } func LocalFree(hmem uint32) (handle uint32, errno int) { - r0, _, e1 := Syscall(procLocalFree, uintptr(hmem), 0, 0) + r0, _, e1 := Syscall(procLocalFree, 1, uintptr(hmem), 0, 0) handle = uint32(r0) if handle != 0 { if e1 != 0 { @@ -846,13 +862,13 @@ func LocalFree(hmem uint32) (handle uint32, errno int) { } func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) { - r0, _, _ := Syscall(procWSAStartup, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) + r0, _, _ := Syscall(procWSAStartup, 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0) sockerrno = int(r0) return } func WSACleanup() (errno int) { - r1, _, e1 := Syscall(procWSACleanup, 0, 0, 0) + r1, _, e1 := Syscall(procWSACleanup, 0, 0, 0, 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -866,7 +882,7 @@ func WSACleanup() (errno int) { } func socket(af int32, typ int32, protocol int32) (handle int32, errno int) { - r0, _, e1 := Syscall(procsocket, uintptr(af), uintptr(typ), uintptr(protocol)) + r0, _, e1 := Syscall(procsocket, 3, uintptr(af), uintptr(typ), uintptr(protocol)) handle = int32(r0) if handle == -1 { if e1 != 0 { @@ -881,7 +897,7 @@ func socket(af int32, typ int32, protocol int32) (handle int32, errno int) { } func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) { - r1, _, e1 := Syscall6(procsetsockopt, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) + r1, _, e1 := Syscall6(procsetsockopt, 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -895,7 +911,7 @@ func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) } func bind(s int32, name uintptr, namelen int32) (errno int) { - r1, _, e1 := Syscall(procbind, uintptr(s), uintptr(name), uintptr(namelen)) + r1, _, e1 := Syscall(procbind, 3, uintptr(s), uintptr(name), uintptr(namelen)) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -909,7 +925,7 @@ func bind(s int32, name uintptr, namelen int32) (errno int) { } func connect(s int32, name uintptr, namelen int32) (errno int) { - r1, _, e1 := Syscall(procconnect, uintptr(s), uintptr(name), uintptr(namelen)) + r1, _, e1 := Syscall(procconnect, 3, uintptr(s), uintptr(name), uintptr(namelen)) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -923,7 +939,7 @@ func connect(s int32, name uintptr, namelen int32) (errno int) { } func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) { - r1, _, e1 := Syscall(procgetsockname, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r1, _, e1 := Syscall(procgetsockname, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -937,7 +953,7 @@ func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) { } func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) { - r1, _, e1 := Syscall(procgetpeername, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) + r1, _, e1 := Syscall(procgetpeername, 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -951,7 +967,7 @@ func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) { } func listen(s int32, backlog int32) (errno int) { - r1, _, e1 := Syscall(proclisten, uintptr(s), uintptr(backlog), 0) + r1, _, e1 := Syscall(proclisten, 2, uintptr(s), uintptr(backlog), 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -965,7 +981,7 @@ func listen(s int32, backlog int32) (errno int) { } func shutdown(s int32, how int32) (errno int) { - r1, _, e1 := Syscall(procshutdown, uintptr(s), uintptr(how), 0) + r1, _, e1 := Syscall(procshutdown, 2, uintptr(s), uintptr(how), 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -979,7 +995,7 @@ func shutdown(s int32, how int32) (errno int) { } func Closesocket(s int32) (errno int) { - r1, _, e1 := Syscall(procclosesocket, uintptr(s), 0, 0) + r1, _, e1 := Syscall(procclosesocket, 1, uintptr(s), 0, 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -993,7 +1009,7 @@ func Closesocket(s int32) (errno int) { } func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, errno int) { - r0, _, e1 := Syscall9(procAcceptEx, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) + r0, _, e1 := Syscall9(procAcceptEx, 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0) ok = bool(r0 != 0) if !ok { if e1 != 0 { @@ -1008,12 +1024,12 @@ func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32 } func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) { - Syscall9(procGetAcceptExSockaddrs, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) + Syscall9(procGetAcceptExSockaddrs, 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0) return } func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) { - r1, _, e1 := Syscall9(procWSARecv, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + r1, _, e1 := Syscall9(procWSARecv, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -1027,7 +1043,7 @@ func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32 } func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) { - r1, _, e1 := Syscall9(procWSASend, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) + r1, _, e1 := Syscall9(procWSASend, 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -1041,7 +1057,7 @@ func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, } func WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) { - r1, _, e1 := Syscall9(procWSARecvFrom, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + r1, _, e1 := Syscall9(procWSARecvFrom, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -1055,7 +1071,7 @@ func WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *ui } func WSASendTo(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) { - r1, _, e1 := Syscall9(procWSASendTo, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) + r1, _, e1 := Syscall9(procWSASendTo, 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) if int(r1) == -1 { if e1 != 0 { errno = int(e1) @@ -1069,7 +1085,7 @@ func WSASendTo(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32 } func GetHostByName(name string) (h *Hostent, errno int) { - r0, _, e1 := Syscall(procgethostbyname, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0) + r0, _, e1 := Syscall(procgethostbyname, 1, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0) h = (*Hostent)(unsafe.Pointer(r0)) if h == nil { if e1 != 0 { @@ -1084,7 +1100,7 @@ func GetHostByName(name string) (h *Hostent, errno int) { } func GetServByName(name string, proto string) (s *Servent, errno int) { - r0, _, e1 := Syscall(procgetservbyname, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0) + r0, _, e1 := Syscall(procgetservbyname, 2, uintptr(unsafe.Pointer(StringBytePtr(name))), uintptr(unsafe.Pointer(StringBytePtr(proto))), 0) s = (*Servent)(unsafe.Pointer(r0)) if s == nil { if e1 != 0 { @@ -1099,18 +1115,18 @@ func GetServByName(name string, proto string) (s *Servent, errno int) { } func Ntohs(netshort uint16) (u uint16) { - r0, _, _ := Syscall(procntohs, uintptr(netshort), 0, 0) + r0, _, _ := Syscall(procntohs, 1, uintptr(netshort), 0, 0) u = uint16(r0) return } func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) { - r0, _, _ := Syscall6(procDnsQuery_W, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) + r0, _, _ := Syscall6(procDnsQuery_W, 6, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr))) status = uint32(r0) return } func DnsRecordListFree(rl *DNSRecord, freetype uint32) { - Syscall(procDnsRecordListFree, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) + Syscall(procDnsRecordListFree, 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0) return } diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go index e67165f23..b1271aff1 100644 --- a/src/pkg/syscall/ztypes_windows_386.go +++ b/src/pkg/syscall/ztypes_windows_386.go @@ -295,9 +295,10 @@ const ( AF_INET6 = 23 AF_NETBIOS = 17 - SOCK_STREAM = 1 - SOCK_DGRAM = 2 - SOCK_RAW = 3 + SOCK_STREAM = 1 + SOCK_DGRAM = 2 + SOCK_RAW = 3 + SOCK_SEQPACKET = 5 IPPROTO_IP = 0 IPPROTO_TCP = 6 diff --git a/src/pkg/syslog/syslog_test.go b/src/pkg/syslog/syslog_test.go index 063ab71b4..2958bcb1f 100644 --- a/src/pkg/syslog/syslog_test.go +++ b/src/pkg/syslog/syslog_test.go @@ -28,7 +28,7 @@ func runSyslog(c net.PacketConn, done chan<- string) { func startServer(done chan<- string) { c, e := net.ListenPacket("udp", "127.0.0.1:0") if e != nil { - log.Exitf("net.ListenPacket failed udp :0 %v", e) + log.Fatalf("net.ListenPacket failed udp :0 %v", e) } serverAddr = c.LocalAddr().String() c.SetReadTimeout(100e6) // 100ms diff --git a/src/pkg/template/template.go b/src/pkg/template/template.go index a67dbf8ad..078463aaf 100644 --- a/src/pkg/template/template.go +++ b/src/pkg/template/template.go @@ -622,7 +622,10 @@ func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value } return av.FieldByName(name) case *reflect.MapValue: - return av.Elem(reflect.NewValue(name)) + if v := av.Elem(reflect.NewValue(name)); v != nil { + return v + } + return reflect.MakeZero(typ.(*reflect.MapType).Elem()) default: return nil } diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go index 57f297e8f..3842b6d6b 100644 --- a/src/pkg/template/template_test.go +++ b/src/pkg/template/template_test.go @@ -522,9 +522,27 @@ func TestMapDriverType(t *testing.T) { t.Error("unexpected execute error:", err) } s := b.String() - expected := "template: Ahoy!" - if s != expected { - t.Errorf("failed passing string as data: expected %q got %q", "template: Ahoy!", s) + expect := "template: Ahoy!" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) + } +} + +func TestMapNoEntry(t *testing.T) { + mp := make(map[string]int) + tmpl, err := Parse("template: {notthere}!", nil) + if err != nil { + t.Error("unexpected parse error:", err) + } + var b bytes.Buffer + err = tmpl.Execute(mp, &b) + if err != nil { + t.Error("unexpected execute error:", err) + } + s := b.String() + expect := "template: 0!" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) } } @@ -539,8 +557,9 @@ func TestStringDriverType(t *testing.T) { t.Error("unexpected execute error:", err) } s := b.String() - if s != "template: hello" { - t.Errorf("failed passing string as data: expected %q got %q", "template: hello", s) + expect := "template: hello" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) } } @@ -555,18 +574,18 @@ func TestTwice(t *testing.T) { t.Error("unexpected parse error:", err) } s := b.String() - text := "template: hello" - if s != text { - t.Errorf("failed passing string as data: expected %q got %q", text, s) + expect := "template: hello" + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) } err = tmpl.Execute("hello", &b) if err != nil { t.Error("unexpected parse error:", err) } s = b.String() - text += text - if s != text { - t.Errorf("failed passing string as data: expected %q got %q", text, s) + expect += expect + if s != expect { + t.Errorf("failed passing string as data: expected %q got %q", expect, s) } } diff --git a/src/pkg/testing/quick/quick.go b/src/pkg/testing/quick/quick.go index 0b1659725..a5568b048 100644 --- a/src/pkg/testing/quick/quick.go +++ b/src/pkg/testing/quick/quick.go @@ -60,18 +60,16 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { switch concrete := t.(type) { case *reflect.BoolType: return reflect.NewValue(rand.Int()&1 == 0), true - case *reflect.FloatType, *reflect.IntType, *reflect.UintType: + case *reflect.FloatType, *reflect.IntType, *reflect.UintType, *reflect.ComplexType: switch t.Kind() { case reflect.Float32: return reflect.NewValue(randFloat32(rand)), true case reflect.Float64: return reflect.NewValue(randFloat64(rand)), true - case reflect.Float: - if t.Size() == 4 { - return reflect.NewValue(float(randFloat32(rand))), true - } else { - return reflect.NewValue(float(randFloat64(rand))), true - } + case reflect.Complex64: + return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true + case reflect.Complex128: + return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true case reflect.Int16: return reflect.NewValue(int16(randInt64(rand))), true case reflect.Int32: @@ -157,7 +155,7 @@ type Config struct { MaxCount int // MaxCountScale is a non-negative scale factor applied to the default // maximum. If zero, the default is unchanged. - MaxCountScale float + MaxCountScale float64 // If non-nil, rand is a source of random numbers. Otherwise a default // pseudo-random source will be used. Rand *rand.Rand @@ -183,7 +181,7 @@ func (c *Config) getMaxCount() (maxCount int) { maxCount = c.MaxCount if maxCount == 0 { if c.MaxCountScale != 0 { - maxCount = int(c.MaxCountScale * float(*defaultMaxCount)) + maxCount = int(c.MaxCountScale * float64(*defaultMaxCount)) } else { maxCount = *defaultMaxCount } diff --git a/src/pkg/testing/quick/quick_test.go b/src/pkg/testing/quick/quick_test.go index c7bff962b..b126e4a16 100644 --- a/src/pkg/testing/quick/quick_test.go +++ b/src/pkg/testing/quick/quick_test.go @@ -17,7 +17,9 @@ func fFloat32(a float32) float32 { return a } func fFloat64(a float64) float64 { return a } -func fFloat(a float) float { return a } +func fComplex64(a complex64) complex64 { return a } + +func fComplex128(a complex128) complex128 { return a } func fInt16(a int16) int16 { return a } @@ -71,7 +73,8 @@ func TestCheckEqual(t *testing.T) { reportError("fBool", CheckEqual(fBool, fBool, nil), t) reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t) reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t) - reportError("fFloat", CheckEqual(fFloat, fFloat, nil), t) + reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t) + reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t) reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t) reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t) reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t) diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go index 3538775ad..833552d68 100644 --- a/src/pkg/time/sleep.go +++ b/src/pkg/time/sleep.go @@ -11,20 +11,40 @@ import ( "container/heap" ) -// The event type represents a single After or AfterFunc event. -type event struct { - t int64 // The absolute time that the event should fire. - f func(int64) // The function to call when the event fires. - sleeping bool // A sleeper is sleeping for this event. +// The Timer type represents a single event. +// When the Timer expires, the current time will be sent on C +// unless the Timer represents an AfterFunc event. +type Timer struct { + C <-chan int64 + t int64 // The absolute time that the event should fire. + f func(int64) // The function to call when the event fires. + i int // The event's index inside eventHeap. } -type eventHeap []*event +type timerHeap []*Timer -var events eventHeap -var eventMutex sync.Mutex +// forever is the absolute time (in ns) of an event that is forever away. +const forever = 1 << 62 + +// maxSleepTime is the maximum length of time that a sleeper +// sleeps for before checking if it is defunct. +const maxSleepTime = 1e9 + +var ( + // timerMutex guards the variables inside this var group. + timerMutex sync.Mutex + + // timers holds a binary heap of pending events, terminated with a sentinel. + timers timerHeap + + // currentSleeper is an ever-incrementing counter which represents + // the current sleeper. It allows older sleepers to detect that they are + // defunct and exit. + currentSleeper int64 +) func init() { - events.Push(&event{1 << 62, nil, true}) // sentinel + timers.Push(&Timer{t: forever}) // sentinel } // Sleep pauses the current goroutine for at least ns nanoseconds. @@ -51,101 +71,133 @@ func sleep(t, ns int64) (int64, os.Error) { return t, nil } +// NewTimer creates a new Timer that will send +// the current time on its channel after at least ns nanoseconds. +func NewTimer(ns int64) *Timer { + c := make(chan int64, 1) + e := after(ns, func(t int64) { c <- t }) + e.C = c + return e +} + // After waits at least ns nanoseconds before sending the current time // on the returned channel. +// It is equivalent to NewTimer(ns).C. func After(ns int64) <-chan int64 { - c := make(chan int64, 1) - after(ns, func(t int64) { c <- t }) - return c + return NewTimer(ns).C } // AfterFunc waits at least ns nanoseconds before calling f -// in its own goroutine. -func AfterFunc(ns int64, f func()) { - after(ns, func(_ int64) { +// in its own goroutine. It returns a Timer that can +// be used to cancel the call using its Stop method. +func AfterFunc(ns int64, f func()) *Timer { + return after(ns, func(_ int64) { go f() }) } +// Stop prevents the Timer from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or stopped. +func (e *Timer) Stop() (ok bool) { + timerMutex.Lock() + // Avoid removing the first event in the queue so that + // we don't start a new sleeper unnecessarily. + if e.i > 0 { + heap.Remove(timers, e.i) + } + ok = e.f != nil + e.f = nil + timerMutex.Unlock() + return +} + // after is the implementation of After and AfterFunc. // When the current time is after ns, it calls f with the current time. // It assumes that f will not block. -func after(ns int64, f func(int64)) { +func after(ns int64, f func(int64)) (e *Timer) { + now := Nanoseconds() t := Nanoseconds() + ns - eventMutex.Lock() - t0 := events[0].t - heap.Push(events, &event{t, f, false}) - if t < t0 { - go sleeper() + if ns > 0 && t < now { + panic("time: time overflow") } - eventMutex.Unlock() + timerMutex.Lock() + t0 := timers[0].t + e = &Timer{nil, t, f, -1} + heap.Push(timers, e) + // Start a new sleeper if the new event is before + // the first event in the queue. If the length of time + // until the new event is at least maxSleepTime, + // then we're guaranteed that the sleeper will wake up + // in time to service it, so no new sleeper is needed. + if t0 > t && (t0 == forever || ns < maxSleepTime) { + currentSleeper++ + go sleeper(currentSleeper) + } + timerMutex.Unlock() + return } -// sleeper continually looks at the earliest event in the queue, marks it -// as sleeping, waits until it happens, then removes any events -// in the queue that are due. It stops when it finds an event that is -// already marked as sleeping. When an event is inserted before the first item, -// a new sleeper is started. -// -// Scheduling vagaries mean that sleepers may not wake up in -// exactly the order of the events that they are waiting for, -// but this does not matter as long as there are at least as -// many sleepers as events marked sleeping (invariant). This ensures that -// there is always a sleeper to service the remaining events. -// -// A sleeper will remove at least the event it has been waiting for -// unless the event has already been removed by another sleeper. Both -// cases preserve the invariant described above. -func sleeper() { - eventMutex.Lock() - e := events[0] - for !e.sleeping { - t := Nanoseconds() +// sleeper continually looks at the earliest event in the queue, waits until it happens, +// then removes any events in the queue that are due. It stops when the queue +// is empty or when another sleeper has been started. +func sleeper(sleeperId int64) { + timerMutex.Lock() + e := timers[0] + t := Nanoseconds() + for e.t != forever { if dt := e.t - t; dt > 0 { - e.sleeping = true - eventMutex.Unlock() - if nt, err := sleep(t, dt); err != nil { - // If sleep has encountered an error, - // there's not much we can do. We pretend - // that time really has advanced by the required - // amount and lie to the rest of the system. - t = e.t - } else { - t = nt + if dt > maxSleepTime { + dt = maxSleepTime + } + timerMutex.Unlock() + syscall.Sleep(dt) + timerMutex.Lock() + if currentSleeper != sleeperId { + // Another sleeper has been started, making this one redundant. + break } - eventMutex.Lock() - e = events[0] } + e = timers[0] + t = Nanoseconds() for t >= e.t { - e.f(t) - heap.Pop(events) - e = events[0] + if e.f != nil { + e.f(t) + e.f = nil + } + heap.Pop(timers) + e = timers[0] } } - eventMutex.Unlock() + timerMutex.Unlock() } -func (eventHeap) Len() int { - return len(events) +func (timerHeap) Len() int { + return len(timers) } -func (eventHeap) Less(i, j int) bool { - return events[i].t < events[j].t +func (timerHeap) Less(i, j int) bool { + return timers[i].t < timers[j].t } -func (eventHeap) Swap(i, j int) { - events[i], events[j] = events[j], events[i] +func (timerHeap) Swap(i, j int) { + timers[i], timers[j] = timers[j], timers[i] + timers[i].i = i + timers[j].i = j } -func (eventHeap) Push(x interface{}) { - events = append(events, x.(*event)) +func (timerHeap) Push(x interface{}) { + e := x.(*Timer) + e.i = len(timers) + timers = append(timers, e) } -func (eventHeap) Pop() interface{} { +func (timerHeap) Pop() interface{} { // TODO: possibly shrink array. - n := len(events) - 1 - e := events[n] - events[n] = nil - events = events[0:n] + n := len(timers) - 1 + e := timers[n] + timers[n] = nil + timers = timers[0:n] + e.i = -1 return e } diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go index 9e36288f8..8bf599c3e 100644 --- a/src/pkg/time/sleep_test.go +++ b/src/pkg/time/sleep_test.go @@ -64,6 +64,18 @@ func BenchmarkAfterFunc(b *testing.B) { <-c } +func BenchmarkAfter(b *testing.B) { + for i := 0; i < b.N; i++ { + <-After(1) + } +} + +func BenchmarkStop(b *testing.B) { + for i := 0; i < b.N; i++ { + NewTimer(1e9).Stop() + } +} + func TestAfter(t *testing.T) { const delay = int64(100e6) start := Nanoseconds() @@ -94,6 +106,32 @@ func TestAfterTick(t *testing.T) { } } +func TestAfterStop(t *testing.T) { + const msec = 1e6 + AfterFunc(100*msec, func() {}) + t0 := NewTimer(50 * msec) + c1 := make(chan bool, 1) + t1 := AfterFunc(150*msec, func() { c1 <- true }) + c2 := After(200 * msec) + if !t0.Stop() { + t.Fatalf("failed to stop event 0") + } + if !t1.Stop() { + t.Fatalf("failed to stop event 1") + } + <-c2 + select { + case <-t0.C: + t.Fatalf("event 0 was not stopped") + case <-c1: + t.Fatalf("event 1 was not stopped") + default: + } + if t1.Stop() { + t.Fatalf("Stop returned true twice") + } +} + var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0} type afterResult struct { diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go index ddd727270..6c21bf19b 100644 --- a/src/pkg/time/tick.go +++ b/src/pkg/time/tick.go @@ -22,8 +22,12 @@ type Ticker struct { // Stop turns off a ticker. After Stop, no more ticks will be sent. func (t *Ticker) Stop() { - // Make it non-blocking so multiple Stops don't block. - _ = t.shutdown <- true + select { + case t.shutdown <- true: + // ok + default: + // Stop in progress already + } } // Tick is a convenience wrapper for NewTicker providing access to the ticking @@ -106,7 +110,8 @@ func tickerLoop() { // that need it and determining the next wake time. // TODO(r): list should be sorted in time order. for t := tickers; t != nil; t = t.next { - if _, ok := <-t.shutdown; ok { + select { + case <-t.shutdown: // Ticker is done; remove it from list. if prev == nil { tickers = t.next @@ -114,6 +119,7 @@ func tickerLoop() { prev.next = t.next } continue + default: } if t.nextTick <= now { if len(t.c) == 0 { diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go index 2a63a0f2b..4dcb63956 100644 --- a/src/pkg/time/tick_test.go +++ b/src/pkg/time/tick_test.go @@ -29,9 +29,11 @@ func TestTicker(t *testing.T) { } // Now test that the ticker stopped Sleep(2 * Delta) - _, received := <-ticker.C - if received { + select { + case <-ticker.C: t.Fatal("Ticker did not shut down") + default: + // ok } } @@ -43,3 +45,14 @@ func TestTeardown(t *testing.T) { ticker.Stop() } } + +func BenchmarkTicker(b *testing.B) { + ticker := NewTicker(1) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + <-ticker.C + } + b.StopTimer() + ticker.Stop() +} diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go index 26c86ab03..6685da747 100644 --- a/src/pkg/time/zoneinfo_unix.go +++ b/src/pkg/time/zoneinfo_unix.go @@ -18,6 +18,7 @@ import ( const ( headerSize = 4 + 16 + 4*7 zoneDir = "/usr/share/zoneinfo/" + zoneDir2 = "/usr/share/lib/zoneinfo/" ) // Simple I/O interface to binary blob of data. @@ -216,7 +217,11 @@ func setupZone() { case err == os.ENOENV: zones, _ = readinfofile("/etc/localtime") case len(tz) > 0: - zones, _ = readinfofile(zoneDir + tz) + var ok bool + zones, ok = readinfofile(zoneDir + tz) + if !ok { + zones, _ = readinfofile(zoneDir2 + tz) + } case len(tz) == 0: // do nothing: use UTC } diff --git a/src/pkg/unicode/Makefile b/src/pkg/unicode/Makefile index df0b4a642..53f7229e7 100644 --- a/src/pkg/unicode/Makefile +++ b/src/pkg/unicode/Makefile @@ -13,18 +13,22 @@ GOFILES=\ include ../../Make.pkg +CLEANFILES+=maketables + maketables: maketables.go $(GC) maketables.go $(LD) -o maketables maketables.$O tables: maketables - $(GC) maketables.go - $(LD) -o maketables maketables.$O ./maketables --tables=all > tables.go gofmt -w tables.go - rm -f maketables +# Build (but do not run) maketables during testing, +# just to make sure it still compiles. +test: maketables + +# Downloads from www.unicode.org, so not part +# of standard test scripts. testtables: maketables - echo '***' Be sure to make tables and make install first + @echo '***' Be sure to make tables and make install first ./maketables -test - rm -f maketables diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go index b8ef64827..432ffb671 100644 --- a/src/pkg/unicode/letter_test.go +++ b/src/pkg/unicode/letter_test.go @@ -56,6 +56,7 @@ var letterTest = []int{ 0xf9, 0x2ec, 0x535, + 0x620, 0x6e6, 0x93d, 0xa15, @@ -85,7 +86,7 @@ var notletterTest = []int{ 0x20, 0x35, 0x375, - 0x620, + 0x619, 0x700, 0xfffe, 0x1ffff, diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go index 081e1a119..0c367673e 100644 --- a/src/pkg/unicode/maketables.go +++ b/src/pkg/unicode/maketables.go @@ -32,7 +32,7 @@ func main() { var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt") var url = flag.String("url", - "http://www.unicode.org/Public/5.2.0/ucd/", + "http://www.unicode.org/Public/6.0.0/ucd/", "URL of Unicode database directory") var tablelist = flag.String("tables", "all", @@ -50,8 +50,8 @@ var test = flag.Bool("test", false, "test existing tables; can be used to compare web data with package data") -var scriptRe = regexp.MustCompile(`([0-9A-F]+)(\.\.[0-9A-F]+)? *; ([A-Za-z_]+)`) -var die = log.New(os.Stderr, nil, "", log.Lexit|log.Lshortfile) +var scriptRe = regexp.MustCompile(`^([0-9A-F]+)(\.\.[0-9A-F]+)? *; ([A-Za-z_]+)$`) +var logger = log.New(os.Stderr, "", log.Lshortfile) var category = map[string]bool{"letter": true} // Nd Lu etc. letter is a special case @@ -141,11 +141,11 @@ const ( func parseCategory(line string) (state State) { field := strings.Split(line, ";", -1) if len(field) != NumField { - die.Logf("%5s: %d fields (expected %d)\n", line, len(field), NumField) + logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField) } point, err := strconv.Btoui64(field[FCodePoint], 16) if err != nil { - die.Log("%.5s...:", err) + logger.Fatalf("%.5s...: %s", line, err) } lastChar = uint32(point) if point == 0 { @@ -157,7 +157,7 @@ func parseCategory(line string) (state State) { char := &chars[point] char.field = field if char.codePoint != 0 { - die.Logf("point %U reused\n") + logger.Fatalf("point %U reused", point) } char.codePoint = lastChar char.category = field[FGeneralCategory] @@ -167,7 +167,7 @@ func parseCategory(line string) (state State) { // Decimal digit _, err := strconv.Atoi(field[FNumericValue]) if err != nil { - die.Log("%U: bad numeric field: %s", point, err) + logger.Fatalf("%U: bad numeric field: %s", point, err) } case "Lu": char.letter(field[FCodePoint], field[FSimpleLowercaseMapping], field[FSimpleTitlecaseMapping]) @@ -208,7 +208,7 @@ func (char *Char) letterValue(s string, cas string) int { v, err := strconv.Btoui64(s, 16) if err != nil { char.dump(cas) - die.Logf("%U: bad letter(%s): %s", char.codePoint, s, err) + logger.Fatalf("%U: bad letter(%s): %s", char.codePoint, s, err) } return int(v) } @@ -242,7 +242,7 @@ func version() string { return f } } - die.Log("unknown version") + logger.Fatal("unknown version") return "Unknown" } @@ -260,10 +260,10 @@ func loadChars() { } resp, _, err := http.Get(*dataURL) if err != nil { - die.Log(err) + logger.Fatal(err) } if resp.StatusCode != 200 { - die.Log("bad GET status for UnicodeData.txt", resp.Status) + logger.Fatal("bad GET status for UnicodeData.txt", resp.Status) } input := bufio.NewReader(resp.Body) var first uint32 = 0 @@ -273,21 +273,21 @@ func loadChars() { if err == os.EOF { break } - die.Log(err) + logger.Fatal(err) } switch parseCategory(line[0 : len(line)-1]) { case SNormal: if first != 0 { - die.Logf("bad state normal at U+%04X", lastChar) + logger.Fatalf("bad state normal at U+%04X", lastChar) } case SFirst: if first != 0 { - die.Logf("bad state first at U+%04X", lastChar) + logger.Fatalf("bad state first at U+%04X", lastChar) } first = lastChar case SLast: if first == 0 { - die.Logf("bad state last at U+%04X", lastChar) + logger.Fatalf("bad state last at U+%04X", lastChar) } for i := first + 1; i <= lastChar; i++ { chars[i] = chars[first] @@ -336,7 +336,7 @@ func printCategories() { ndecl := 0 for _, name := range list { if _, ok := category[name]; !ok { - die.Log("unknown category", name) + logger.Fatal("unknown category", name) } // We generate an UpperCase name to serve as concise documentation and an _UnderScored // name to store the data. This stops godoc dumping all the tables but keeps them @@ -382,7 +382,7 @@ func printCategories() { type Op func(code int) bool -const format = "\tRange{0x%04x, 0x%04x, %d},\n" +const format = "\t{0x%04x, 0x%04x, %d},\n" func dumpRange(header string, inCategory Op) { fmt.Print(header) @@ -437,11 +437,11 @@ func dumpRange(header string, inCategory Op) { func fullCategoryTest(list []string) { for _, name := range list { if _, ok := category[name]; !ok { - die.Log("unknown category", name) + logger.Fatal("unknown category", name) } r, ok := unicode.Categories[name] if !ok { - die.Log("unknown table", name) + logger.Fatal("unknown table", name) } if name == "letter" { verifyRange(name, letterOp, r) @@ -475,21 +475,21 @@ func parseScript(line string, scripts map[string][]Script) { } field := strings.Split(line, ";", -1) if len(field) != 2 { - die.Logf("%s: %d fields (expected 2)\n", line, len(field)) + logger.Fatalf("%s: %d fields (expected 2)\n", line, len(field)) } - matches := scriptRe.MatchStrings(line) + matches := scriptRe.FindStringSubmatch(line) if len(matches) != 4 { - die.Logf("%s: %d matches (expected 3)\n", line, len(matches)) + logger.Fatalf("%s: %d matches (expected 3)\n", line, len(matches)) } lo, err := strconv.Btoui64(matches[1], 16) if err != nil { - die.Log("%.5s...:", err) + logger.Fatalf("%.5s...: %s", line, err) } hi := lo if len(matches[2]) > 2 { // ignore leading .. hi, err = strconv.Btoui64(matches[2][2:], 16) if err != nil { - die.Log("%.5s...:", err) + logger.Fatalf("%.5s...: %s", line, err) } } name := matches[3] @@ -515,11 +515,11 @@ func foldAdjacent(r []Script) []unicode.Range { func fullScriptTest(list []string, installed map[string][]unicode.Range, scripts map[string][]Script) { for _, name := range list { if _, ok := scripts[name]; !ok { - die.Log("unknown script", name) + logger.Fatal("unknown script", name) } _, ok := installed[name] if !ok { - die.Log("unknown table", name) + logger.Fatal("unknown table", name) } for _, script := range scripts[name] { for r := script.lo; r <= script.hi; r++ { @@ -551,10 +551,10 @@ func printScriptOrProperty(doProps bool) { var err os.Error resp, _, err := http.Get(*url + file) if err != nil { - die.Log(err) + logger.Fatal(err) } if resp.StatusCode != 200 { - die.Log("bad GET status for ", file, ":", resp.Status) + logger.Fatal("bad GET status for ", file, ":", resp.Status) } input := bufio.NewReader(resp.Body) for { @@ -563,7 +563,7 @@ func printScriptOrProperty(doProps bool) { if err == os.EOF { break } - die.Log(err) + logger.Fatal(err) } parseScript(line[0:len(line)-1], table) } @@ -805,14 +805,14 @@ func printCaseRange(lo, hi *caseState) { } switch { case hi.point > lo.point && lo.isUpperLower(): - fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{UpperLower, UpperLower, UpperLower}},\n", + fmt.Printf("\t{0x%04X, 0x%04X, d{UpperLower, UpperLower, UpperLower}},\n", lo.point, hi.point) case hi.point > lo.point && lo.isLowerUpper(): - die.Log("LowerUpper sequence: should not happen: U+%04X. If it's real, need to fix To()", lo.point) - fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{LowerUpper, LowerUpper, LowerUpper}},\n", + logger.Fatalf("LowerUpper sequence: should not happen: U+%04X. If it's real, need to fix To()", lo.point) + fmt.Printf("\t{0x%04X, 0x%04X, d{LowerUpper, LowerUpper, LowerUpper}},\n", lo.point, hi.point) default: - fmt.Printf("\tCaseRange{0x%04X, 0x%04X, d{%d, %d, %d}},\n", + fmt.Printf("\t{0x%04X, 0x%04X, d{%d, %d, %d}},\n", lo.point, hi.point, lo.deltaToUpper, lo.deltaToLower, lo.deltaToTitle) } diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go index ffdc40dc0..ff452b75c 100644 --- a/src/pkg/unicode/script_test.go +++ b/src/pkg/unicode/script_test.go @@ -14,7 +14,7 @@ type T struct { script string } -// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new +// Hand-chosen tests from Unicode 5.1.0 & 6.0..0, mostly to discover when new // scripts and categories arise. var inTest = []T{ {0x06e2, "Arabic"}, @@ -22,11 +22,13 @@ var inTest = []T{ {0x10b20, "Avestan"}, {0x1b37, "Balinese"}, {0xa6af, "Bamum"}, + {0x1be1, "Batak"}, {0x09c2, "Bengali"}, {0x3115, "Bopomofo"}, {0x282d, "Braille"}, {0x1a1a, "Buginese"}, {0x1747, "Buhid"}, + {0x11011, "Brahmi"}, {0x156d, "Canadian_Aboriginal"}, {0x102a9, "Carian"}, {0xaa4d, "Cham"}, @@ -72,6 +74,7 @@ var inTest = []T{ {0x10290, "Lycian"}, {0x10930, "Lydian"}, {0x0d42, "Malayalam"}, + {0x0843, "Mandaic"}, {0xabd0, "Meetei_Mayek"}, {0x1822, "Mongolian"}, {0x104c, "Myanmar"}, @@ -204,7 +207,7 @@ func TestScripts(t *testing.T) { } } for k := range notTested { - t.Error("not tested:", k) + t.Error("script not tested:", k) } } @@ -223,7 +226,7 @@ func TestCategories(t *testing.T) { notTested[test.script] = false, false } for k := range notTested { - t.Error("not tested:", k) + t.Error("category not tested:", k) } } @@ -242,6 +245,6 @@ func TestProperties(t *testing.T) { notTested[test.script] = false, false } for k := range notTested { - t.Error("not tested:", k) + t.Error("property not tested:", k) } } diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go index b56c9bd03..89fd99411 100644 --- a/src/pkg/unicode/tables.go +++ b/src/pkg/unicode/tables.go @@ -1,11 +1,11 @@ // Generated by running -// maketables --tables=all --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt +// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt // DO NOT EDIT package unicode // Version is the Unicode edition from which the tables are derived. -const Version = "5.2.0" +const Version = "6.0.0" // Categories is the set of Unicode data tables. var Categories = map[string][]Range{ @@ -61,7 +61,7 @@ var _Lm = []Range{ {0x1d78, 0x1d9b, 35}, {0x1d9c, 0x1dbf, 1}, {0x2071, 0x207f, 14}, - {0x2090, 0x2094, 1}, + {0x2090, 0x209c, 1}, {0x2c7d, 0x2d6f, 242}, {0x2e2f, 0x3005, 470}, {0x3031, 0x3035, 1}, @@ -129,7 +129,7 @@ var _Ll = []Range{ {0x0461, 0x0481, 2}, {0x048b, 0x04bf, 2}, {0x04c2, 0x04ce, 2}, - {0x04cf, 0x0525, 2}, + {0x04cf, 0x0527, 2}, {0x0561, 0x0587, 1}, {0x1d00, 0x1d2b, 1}, {0x1d62, 0x1d77, 1}, @@ -174,8 +174,7 @@ var _Ll = []Range{ {0x2ce4, 0x2cec, 8}, {0x2cee, 0x2d00, 18}, {0x2d01, 0x2d25, 1}, - {0xa641, 0xa65f, 2}, - {0xa663, 0xa66d, 2}, + {0xa641, 0xa66d, 2}, {0xa681, 0xa697, 2}, {0xa723, 0xa72f, 2}, {0xa730, 0xa731, 1}, @@ -183,7 +182,10 @@ var _Ll = []Range{ {0xa772, 0xa778, 1}, {0xa77a, 0xa77c, 2}, {0xa77f, 0xa787, 2}, - {0xa78c, 0xfb00, 21364}, + {0xa78c, 0xa78e, 2}, + {0xa791, 0xa7a1, 16}, + {0xa7a3, 0xa7a9, 2}, + {0xa7fa, 0xfb00, 21254}, {0xfb01, 0xfb06, 1}, {0xfb13, 0xfb17, 1}, {0xff41, 0xff5a, 1}, @@ -220,19 +222,18 @@ var _Ll = []Range{ var _Me = []Range{ {0x0488, 0x0489, 1}, - {0x06de, 0x20dd, 6655}, - {0x20de, 0x20e0, 1}, + {0x20dd, 0x20e0, 1}, {0x20e2, 0x20e4, 1}, {0xa670, 0xa672, 1}, } var _Mc = []Range{ - {0x0903, 0x093e, 59}, - {0x093f, 0x0940, 1}, + {0x0903, 0x093b, 56}, + {0x093e, 0x0940, 1}, {0x0949, 0x094c, 1}, - {0x094e, 0x0982, 52}, - {0x0983, 0x09be, 59}, - {0x09bf, 0x09c0, 1}, + {0x094e, 0x094f, 1}, + {0x0982, 0x0983, 1}, + {0x09be, 0x09c0, 1}, {0x09c7, 0x09c8, 1}, {0x09cb, 0x09cc, 1}, {0x09d7, 0x0a03, 44}, @@ -299,7 +300,10 @@ var _Mc = []Range{ {0x1b43, 0x1b44, 1}, {0x1b82, 0x1ba1, 31}, {0x1ba6, 0x1ba7, 1}, - {0x1baa, 0x1c24, 122}, + {0x1baa, 0x1be7, 61}, + {0x1bea, 0x1bec, 1}, + {0x1bee, 0x1bf2, 4}, + {0x1bf3, 0x1c24, 49}, {0x1c25, 0x1c2b, 1}, {0x1c34, 0x1c35, 1}, {0x1ce1, 0x1cf2, 17}, @@ -318,7 +322,8 @@ var _Mc = []Range{ {0xabe3, 0xabe4, 1}, {0xabe6, 0xabe7, 1}, {0xabe9, 0xabea, 1}, - {0xabec, 0x11082, 25750}, + {0xabec, 0x11000, 25620}, + {0x11002, 0x11082, 128}, {0x110b0, 0x110b2, 1}, {0x110b7, 0x110b8, 1}, {0x1d165, 0x1d166, 1}, @@ -333,7 +338,7 @@ var _Mn = []Range{ {0x05c2, 0x05c4, 2}, {0x05c5, 0x05c7, 2}, {0x0610, 0x061a, 1}, - {0x064b, 0x065e, 1}, + {0x064b, 0x065f, 1}, {0x0670, 0x06d6, 102}, {0x06d7, 0x06dc, 1}, {0x06df, 0x06e4, 1}, @@ -347,11 +352,12 @@ var _Mn = []Range{ {0x081b, 0x0823, 1}, {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, + {0x0859, 0x085b, 1}, {0x0900, 0x0902, 1}, - {0x093c, 0x0941, 5}, - {0x0942, 0x0948, 1}, + {0x093a, 0x093c, 2}, + {0x0941, 0x0948, 1}, {0x094d, 0x0951, 4}, - {0x0952, 0x0955, 1}, + {0x0952, 0x0957, 1}, {0x0962, 0x0963, 1}, {0x0981, 0x09bc, 59}, {0x09c1, 0x09c4, 1}, @@ -400,7 +406,7 @@ var _Mn = []Range{ {0x0f71, 0x0f7e, 1}, {0x0f80, 0x0f84, 1}, {0x0f86, 0x0f87, 1}, - {0x0f90, 0x0f97, 1}, + {0x0f8d, 0x0f97, 1}, {0x0f99, 0x0fbc, 1}, {0x0fc6, 0x102d, 103}, {0x102e, 0x1030, 1}, @@ -412,7 +418,8 @@ var _Mn = []Range{ {0x1071, 0x1074, 1}, {0x1082, 0x1085, 3}, {0x1086, 0x108d, 7}, - {0x109d, 0x135f, 706}, + {0x109d, 0x135d, 704}, + {0x135e, 0x135f, 1}, {0x1712, 0x1714, 1}, {0x1732, 0x1734, 1}, {0x1752, 0x1753, 1}, @@ -442,6 +449,9 @@ var _Mn = []Range{ {0x1b80, 0x1b81, 1}, {0x1ba2, 0x1ba5, 1}, {0x1ba8, 0x1ba9, 1}, + {0x1be6, 0x1be8, 2}, + {0x1be9, 0x1bed, 4}, + {0x1bef, 0x1bf1, 1}, {0x1c2c, 0x1c33, 1}, {0x1c36, 0x1c37, 1}, {0x1cd0, 0x1cd2, 1}, @@ -449,12 +459,13 @@ var _Mn = []Range{ {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1dc0, 211}, {0x1dc1, 0x1de6, 1}, - {0x1dfd, 0x1dff, 1}, + {0x1dfc, 0x1dff, 1}, {0x20d0, 0x20dc, 1}, {0x20e1, 0x20e5, 4}, {0x20e6, 0x20f0, 1}, {0x2cef, 0x2cf1, 1}, - {0x2de0, 0x2dff, 1}, + {0x2d7f, 0x2de0, 97}, + {0x2de1, 0x2dff, 1}, {0x302a, 0x302f, 1}, {0x3099, 0x309a, 1}, {0xa66f, 0xa67c, 13}, @@ -488,9 +499,10 @@ var _Mn = []Range{ {0x10a05, 0x10a06, 1}, {0x10a0c, 0x10a0f, 1}, {0x10a38, 0x10a3a, 1}, - {0x10a3f, 0x11080, 1601}, - {0x11081, 0x110b3, 50}, - {0x110b4, 0x110b6, 1}, + {0x10a3f, 0x11001, 1474}, + {0x11038, 0x11046, 1}, + {0x11080, 0x11081, 1}, + {0x110b3, 0x110b6, 1}, {0x110b9, 0x110ba, 1}, {0x1d167, 0x1d169, 1}, {0x1d17b, 0x1d182, 1}, @@ -524,13 +536,13 @@ var letter = []Range{ {0x038f, 0x03a1, 1}, {0x03a3, 0x03f5, 1}, {0x03f7, 0x0481, 1}, - {0x048a, 0x0525, 1}, + {0x048a, 0x0527, 1}, {0x0531, 0x0556, 1}, {0x0559, 0x0561, 8}, {0x0562, 0x0587, 1}, {0x05d0, 0x05ea, 1}, {0x05f0, 0x05f2, 1}, - {0x0621, 0x064a, 1}, + {0x0620, 0x064a, 1}, {0x066e, 0x066f, 1}, {0x0671, 0x06d3, 1}, {0x06d5, 0x06e5, 16}, @@ -546,11 +558,12 @@ var letter = []Range{ {0x07fa, 0x0800, 6}, {0x0801, 0x0815, 1}, {0x081a, 0x0824, 10}, - {0x0828, 0x0904, 220}, - {0x0905, 0x0939, 1}, + {0x0828, 0x0840, 24}, + {0x0841, 0x0858, 1}, + {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, - {0x0971, 0x0972, 1}, + {0x0971, 0x0977, 1}, {0x0979, 0x097f, 1}, {0x0985, 0x098c, 1}, {0x098f, 0x0990, 1}, @@ -615,13 +628,13 @@ var letter = []Range{ {0x0cb5, 0x0cb9, 1}, {0x0cbd, 0x0cde, 33}, {0x0ce0, 0x0ce1, 1}, + {0x0cf1, 0x0cf2, 1}, {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d28, 1}, - {0x0d2a, 0x0d39, 1}, - {0x0d3d, 0x0d60, 35}, - {0x0d61, 0x0d7a, 25}, - {0x0d7b, 0x0d7f, 1}, + {0x0d12, 0x0d3a, 1}, + {0x0d3d, 0x0d4e, 17}, + {0x0d60, 0x0d61, 1}, + {0x0d7a, 0x0d7f, 1}, {0x0d85, 0x0d96, 1}, {0x0d9a, 0x0db1, 1}, {0x0db3, 0x0dbb, 1}, @@ -647,7 +660,7 @@ var letter = []Range{ {0x0edd, 0x0f00, 35}, {0x0f40, 0x0f47, 1}, {0x0f49, 0x0f6c, 1}, - {0x0f88, 0x0f8b, 1}, + {0x0f88, 0x0f8c, 1}, {0x1000, 0x102a, 1}, {0x103f, 0x1050, 17}, {0x1051, 0x1055, 1}, @@ -706,6 +719,7 @@ var letter = []Range{ {0x1b45, 0x1b4b, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, + {0x1bc0, 0x1be5, 1}, {0x1c00, 0x1c23, 1}, {0x1c4d, 0x1c4f, 1}, {0x1c5a, 0x1c7d, 1}, @@ -730,7 +744,7 @@ var letter = []Range{ {0x1ff2, 0x1ff4, 1}, {0x1ff6, 0x1ffc, 1}, {0x2071, 0x207f, 14}, - {0x2090, 0x2094, 1}, + {0x2090, 0x209c, 1}, {0x2102, 0x2107, 5}, {0x210a, 0x2113, 1}, {0x2115, 0x2119, 4}, @@ -768,7 +782,7 @@ var letter = []Range{ {0x30fc, 0x30ff, 1}, {0x3105, 0x312d, 1}, {0x3131, 0x318e, 1}, - {0x31a0, 0x31b7, 1}, + {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, {0x4e00, 0x9fcb, 1}, @@ -777,14 +791,15 @@ var letter = []Range{ {0xa500, 0xa60c, 1}, {0xa610, 0xa61f, 1}, {0xa62a, 0xa62b, 1}, - {0xa640, 0xa65f, 1}, - {0xa662, 0xa66e, 1}, + {0xa640, 0xa66e, 1}, {0xa67f, 0xa697, 1}, {0xa6a0, 0xa6e5, 1}, {0xa717, 0xa71f, 1}, {0xa722, 0xa788, 1}, - {0xa78b, 0xa78c, 1}, - {0xa7fb, 0xa801, 1}, + {0xa78b, 0xa78e, 1}, + {0xa790, 0xa791, 1}, + {0xa7a0, 0xa7a9, 1}, + {0xa7fa, 0xa801, 1}, {0xa803, 0xa805, 1}, {0xa807, 0xa80a, 1}, {0xa80c, 0xa822, 1}, @@ -808,6 +823,11 @@ var letter = []Range{ {0xaaba, 0xaabd, 1}, {0xaac0, 0xaac2, 2}, {0xaadb, 0xaadd, 1}, + {0xab01, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, {0xabc0, 0xabe2, 1}, {0xac00, 0xd7a3, 1}, {0xd7b0, 0xd7c6, 1}, @@ -871,9 +891,12 @@ var letter = []Range{ {0x10b40, 0x10b55, 1}, {0x10b60, 0x10b72, 1}, {0x10c00, 0x10c48, 1}, + {0x11003, 0x11037, 1}, {0x11083, 0x110af, 1}, {0x12000, 0x1236e, 1}, {0x13000, 0x1342e, 1}, + {0x16800, 0x16a38, 1}, + {0x1b000, 0x1b001, 1}, {0x1d400, 0x1d454, 1}, {0x1d456, 0x1d49c, 1}, {0x1d49e, 0x1d49f, 1}, @@ -906,6 +929,7 @@ var letter = []Range{ {0x1d7c4, 0x1d7cb, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, + {0x2b740, 0x2b81d, 1}, {0x2f800, 0x2fa1d, 1}, } @@ -976,13 +1000,14 @@ var _Po = []Range{ {0x0701, 0x070d, 1}, {0x07f7, 0x07f9, 1}, {0x0830, 0x083e, 1}, - {0x0964, 0x0965, 1}, - {0x0970, 0x0df4, 1156}, - {0x0e4f, 0x0e5a, 11}, - {0x0e5b, 0x0f04, 169}, - {0x0f05, 0x0f12, 1}, + {0x085e, 0x0964, 262}, + {0x0965, 0x0970, 11}, + {0x0df4, 0x0e4f, 91}, + {0x0e5a, 0x0e5b, 1}, + {0x0f04, 0x0f12, 1}, {0x0f85, 0x0fd0, 75}, {0x0fd1, 0x0fd4, 1}, + {0x0fd9, 0x0fda, 1}, {0x104a, 0x104f, 1}, {0x10fb, 0x1361, 614}, {0x1362, 0x1368, 1}, @@ -994,11 +1019,11 @@ var _Po = []Range{ {0x1800, 0x1805, 1}, {0x1807, 0x180a, 1}, {0x1944, 0x1945, 1}, - {0x19de, 0x19df, 1}, {0x1a1e, 0x1a1f, 1}, {0x1aa0, 0x1aa6, 1}, {0x1aa8, 0x1aad, 1}, {0x1b5a, 0x1b60, 1}, + {0x1bfc, 0x1bff, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, {0x1cd3, 0x2016, 835}, @@ -1012,8 +1037,9 @@ var _Po = []Range{ {0x2056, 0x205e, 1}, {0x2cf9, 0x2cfc, 1}, {0x2cfe, 0x2cff, 1}, - {0x2e00, 0x2e01, 1}, - {0x2e06, 0x2e08, 1}, + {0x2d70, 0x2e00, 144}, + {0x2e01, 0x2e06, 5}, + {0x2e07, 0x2e08, 1}, {0x2e0b, 0x2e0e, 3}, {0x2e0f, 0x2e16, 1}, {0x2e18, 0x2e19, 1}, @@ -1060,6 +1086,7 @@ var _Po = []Range{ {0x10a50, 0x10a58, 1}, {0x10a7f, 0x10b39, 186}, {0x10b3a, 0x10b3f, 1}, + {0x11047, 0x1104d, 1}, {0x110bb, 0x110bc, 1}, {0x110be, 0x110c1, 1}, {0x12470, 0x12473, 1}, @@ -1174,7 +1201,7 @@ var _Nd = []Range{ {0x17e0, 0x17e9, 1}, {0x1810, 0x1819, 1}, {0x1946, 0x194f, 1}, - {0x19d0, 0x19da, 1}, + {0x19d0, 0x19d9, 1}, {0x1a80, 0x1a89, 1}, {0x1a90, 0x1a99, 1}, {0x1b50, 0x1b59, 1}, @@ -1189,6 +1216,7 @@ var _Nd = []Range{ {0xabf0, 0xabf9, 1}, {0xff10, 0xff19, 1}, {0x104a0, 0x104a9, 1}, + {0x11066, 0x1106f, 1}, {0x1d7ce, 0x1d7ff, 1}, } @@ -1211,14 +1239,15 @@ var _No = []Range{ {0x00b9, 0x00bc, 3}, {0x00bd, 0x00be, 1}, {0x09f4, 0x09f9, 1}, + {0x0b72, 0x0b77, 1}, {0x0bf0, 0x0bf2, 1}, {0x0c78, 0x0c7e, 1}, {0x0d70, 0x0d75, 1}, {0x0f2a, 0x0f33, 1}, {0x1369, 0x137c, 1}, {0x17f0, 0x17f9, 1}, - {0x2070, 0x2074, 4}, - {0x2075, 0x2079, 1}, + {0x19da, 0x2070, 1686}, + {0x2074, 0x2079, 1}, {0x2080, 0x2089, 1}, {0x2150, 0x215f, 1}, {0x2189, 0x2460, 727}, @@ -1243,6 +1272,7 @@ var _No = []Range{ {0x10b58, 0x10b5f, 1}, {0x10b78, 0x10b7f, 1}, {0x10e60, 0x10e7e, 1}, + {0x11052, 0x11065, 1}, {0x1d360, 0x1d371, 1}, {0x1f100, 0x1f10a, 1}, } @@ -1252,13 +1282,12 @@ var _So = []Range{ {0x00a9, 0x00ae, 5}, {0x00b0, 0x00b6, 6}, {0x0482, 0x060e, 396}, - {0x060f, 0x06e9, 218}, - {0x06fd, 0x06fe, 1}, - {0x07f6, 0x09fa, 516}, - {0x0b70, 0x0bf3, 131}, - {0x0bf4, 0x0bf8, 1}, + {0x060f, 0x06de, 207}, + {0x06e9, 0x06fd, 20}, + {0x06fe, 0x07f6, 248}, + {0x09fa, 0x0b70, 374}, + {0x0bf3, 0x0bf8, 1}, {0x0bfa, 0x0c7f, 133}, - {0x0cf1, 0x0cf2, 1}, {0x0d79, 0x0f01, 392}, {0x0f02, 0x0f03, 1}, {0x0f13, 0x0f17, 1}, @@ -1271,16 +1300,16 @@ var _So = []Range{ {0x109e, 0x109f, 1}, {0x1360, 0x1390, 48}, {0x1391, 0x1399, 1}, - {0x1940, 0x19e0, 160}, - {0x19e1, 0x19ff, 1}, + {0x1940, 0x19de, 158}, + {0x19df, 0x19ff, 1}, {0x1b61, 0x1b6a, 1}, {0x1b74, 0x1b7c, 1}, {0x2100, 0x2101, 1}, {0x2103, 0x2106, 1}, {0x2108, 0x2109, 1}, {0x2114, 0x2116, 2}, - {0x2117, 0x2118, 1}, - {0x211e, 0x2123, 1}, + {0x2117, 0x211e, 7}, + {0x211f, 0x2123, 1}, {0x2125, 0x2129, 2}, {0x212e, 0x213a, 12}, {0x213b, 0x214a, 15}, @@ -1301,7 +1330,7 @@ var _So = []Range{ {0x232b, 0x237b, 1}, {0x237d, 0x239a, 1}, {0x23b4, 0x23db, 1}, - {0x23e2, 0x23e8, 1}, + {0x23e2, 0x23f3, 1}, {0x2400, 0x2426, 1}, {0x2440, 0x244a, 1}, {0x249c, 0x24e9, 1}, @@ -1309,21 +1338,9 @@ var _So = []Range{ {0x25b8, 0x25c0, 1}, {0x25c2, 0x25f7, 1}, {0x2600, 0x266e, 1}, - {0x2670, 0x26cd, 1}, - {0x26cf, 0x26e1, 1}, - {0x26e3, 0x26e8, 5}, - {0x26e9, 0x26ff, 1}, - {0x2701, 0x2704, 1}, - {0x2706, 0x2709, 1}, - {0x270c, 0x2727, 1}, - {0x2729, 0x274b, 1}, - {0x274d, 0x274f, 2}, - {0x2750, 0x2752, 1}, - {0x2756, 0x275e, 1}, - {0x2761, 0x2767, 1}, - {0x2794, 0x2798, 4}, - {0x2799, 0x27af, 1}, - {0x27b1, 0x27be, 1}, + {0x2670, 0x26ff, 1}, + {0x2701, 0x2767, 1}, + {0x2794, 0x27bf, 1}, {0x2800, 0x28ff, 1}, {0x2b00, 0x2b2f, 1}, {0x2b45, 0x2b46, 1}, @@ -1372,18 +1389,43 @@ var _So = []Range{ {0x1d301, 0x1d356, 1}, {0x1f000, 0x1f02b, 1}, {0x1f030, 0x1f093, 1}, + {0x1f0a0, 0x1f0ae, 1}, + {0x1f0b1, 0x1f0be, 1}, + {0x1f0c1, 0x1f0cf, 1}, + {0x1f0d1, 0x1f0df, 1}, {0x1f110, 0x1f12e, 1}, - {0x1f131, 0x1f13d, 12}, - {0x1f13f, 0x1f142, 3}, - {0x1f146, 0x1f14a, 4}, - {0x1f14b, 0x1f14e, 1}, - {0x1f157, 0x1f15f, 8}, - {0x1f179, 0x1f17b, 2}, - {0x1f17c, 0x1f17f, 3}, - {0x1f18a, 0x1f18d, 1}, - {0x1f190, 0x1f200, 112}, - {0x1f210, 0x1f231, 1}, + {0x1f130, 0x1f169, 1}, + {0x1f170, 0x1f19a, 1}, + {0x1f1e6, 0x1f202, 1}, + {0x1f210, 0x1f23a, 1}, {0x1f240, 0x1f248, 1}, + {0x1f250, 0x1f251, 1}, + {0x1f300, 0x1f320, 1}, + {0x1f330, 0x1f335, 1}, + {0x1f337, 0x1f37c, 1}, + {0x1f380, 0x1f393, 1}, + {0x1f3a0, 0x1f3c4, 1}, + {0x1f3c6, 0x1f3ca, 1}, + {0x1f3e0, 0x1f3f0, 1}, + {0x1f400, 0x1f43e, 1}, + {0x1f440, 0x1f442, 2}, + {0x1f443, 0x1f4f7, 1}, + {0x1f4f9, 0x1f4fc, 1}, + {0x1f500, 0x1f53d, 1}, + {0x1f550, 0x1f567, 1}, + {0x1f5fb, 0x1f5ff, 1}, + {0x1f601, 0x1f610, 1}, + {0x1f612, 0x1f614, 1}, + {0x1f616, 0x1f61c, 2}, + {0x1f61d, 0x1f61e, 1}, + {0x1f620, 0x1f625, 1}, + {0x1f628, 0x1f62b, 1}, + {0x1f62d, 0x1f630, 3}, + {0x1f631, 0x1f633, 1}, + {0x1f635, 0x1f640, 1}, + {0x1f645, 0x1f64f, 1}, + {0x1f680, 0x1f6c5, 1}, + {0x1f700, 0x1f773, 1}, } var _Sm = []Range{ @@ -1397,7 +1439,8 @@ var _Sm = []Range{ {0x2044, 0x2052, 14}, {0x207a, 0x207c, 1}, {0x208a, 0x208c, 1}, - {0x2140, 0x2144, 1}, + {0x2118, 0x2140, 40}, + {0x2141, 0x2144, 1}, {0x214b, 0x2190, 69}, {0x2191, 0x2194, 1}, {0x219a, 0x219b, 1}, @@ -1416,8 +1459,8 @@ var _Sm = []Range{ {0x266f, 0x27c0, 337}, {0x27c1, 0x27c4, 1}, {0x27c7, 0x27ca, 1}, - {0x27cc, 0x27d0, 4}, - {0x27d1, 0x27e5, 1}, + {0x27cc, 0x27ce, 2}, + {0x27cf, 0x27e5, 1}, {0x27f0, 0x27ff, 1}, {0x2900, 0x2982, 1}, {0x2999, 0x29d7, 1}, @@ -1459,6 +1502,7 @@ var _Sk = []Range{ {0xa700, 0xa716, 1}, {0xa720, 0xa721, 1}, {0xa789, 0xa78a, 1}, + {0xfbb2, 0xfbc1, 1}, {0xff3e, 0xff40, 2}, {0xffe3, 0xffe3, 1}, } @@ -1470,7 +1514,7 @@ var _Sc = []Range{ {0x09f3, 0x09fb, 8}, {0x0af1, 0x0bf9, 264}, {0x0e3f, 0x17db, 2460}, - {0x20a0, 0x20b8, 1}, + {0x20a0, 0x20b9, 1}, {0xa838, 0xfdfc, 21956}, {0xfe69, 0xff04, 155}, {0xffe0, 0xffe1, 1}, @@ -1528,7 +1572,7 @@ var _Lu = []Range{ {0x0460, 0x0480, 2}, {0x048a, 0x04c0, 2}, {0x04c1, 0x04cd, 2}, - {0x04d0, 0x0524, 2}, + {0x04d0, 0x0526, 2}, {0x0531, 0x0556, 1}, {0x10a0, 0x10c5, 1}, {0x1e00, 0x1e94, 2}, @@ -1564,15 +1608,16 @@ var _Lu = []Range{ {0x2c7e, 0x2c80, 1}, {0x2c82, 0x2ce2, 2}, {0x2ceb, 0x2ced, 2}, - {0xa640, 0xa65e, 2}, - {0xa662, 0xa66c, 2}, + {0xa640, 0xa66c, 2}, {0xa680, 0xa696, 2}, {0xa722, 0xa72e, 2}, {0xa732, 0xa76e, 2}, {0xa779, 0xa77d, 2}, {0xa77e, 0xa786, 2}, - {0xa78b, 0xff21, 22422}, - {0xff22, 0xff3a, 1}, + {0xa78b, 0xa78d, 2}, + {0xa790, 0xa7a0, 16}, + {0xa7a2, 0xa7a8, 2}, + {0xff21, 0xff3a, 1}, {0x10400, 0x10427, 1}, {0x1d400, 0x1d419, 1}, {0x1d434, 0x1d44d, 1}, @@ -1622,7 +1667,7 @@ var _Lo = []Range{ {0x0294, 0x05d0, 828}, {0x05d1, 0x05ea, 1}, {0x05f0, 0x05f2, 1}, - {0x0621, 0x063f, 1}, + {0x0620, 0x063f, 1}, {0x0641, 0x064a, 1}, {0x066e, 0x066f, 1}, {0x0671, 0x06d3, 1}, @@ -1635,11 +1680,12 @@ var _Lo = []Range{ {0x07b1, 0x07ca, 25}, {0x07cb, 0x07ea, 1}, {0x0800, 0x0815, 1}, + {0x0840, 0x0858, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, - {0x0972, 0x0979, 7}, - {0x097a, 0x097f, 1}, + {0x0972, 0x0977, 1}, + {0x0979, 0x097f, 1}, {0x0985, 0x098c, 1}, {0x098f, 0x0990, 1}, {0x0993, 0x09a8, 1}, @@ -1703,13 +1749,13 @@ var _Lo = []Range{ {0x0cb5, 0x0cb9, 1}, {0x0cbd, 0x0cde, 33}, {0x0ce0, 0x0ce1, 1}, + {0x0cf1, 0x0cf2, 1}, {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d28, 1}, - {0x0d2a, 0x0d39, 1}, - {0x0d3d, 0x0d60, 35}, - {0x0d61, 0x0d7a, 25}, - {0x0d7b, 0x0d7f, 1}, + {0x0d12, 0x0d3a, 1}, + {0x0d3d, 0x0d4e, 17}, + {0x0d60, 0x0d61, 1}, + {0x0d7a, 0x0d7f, 1}, {0x0d85, 0x0d96, 1}, {0x0d9a, 0x0db1, 1}, {0x0db3, 0x0dbb, 1}, @@ -1735,7 +1781,7 @@ var _Lo = []Range{ {0x0f00, 0x0f40, 64}, {0x0f41, 0x0f47, 1}, {0x0f49, 0x0f6c, 1}, - {0x0f88, 0x0f8b, 1}, + {0x0f88, 0x0f8c, 1}, {0x1000, 0x102a, 1}, {0x103f, 0x1050, 17}, {0x1051, 0x1055, 1}, @@ -1792,6 +1838,7 @@ var _Lo = []Range{ {0x1b45, 0x1b4b, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, + {0x1bc0, 0x1be5, 1}, {0x1c00, 0x1c23, 1}, {0x1c4d, 0x1c4f, 1}, {0x1c5a, 0x1c77, 1}, @@ -1815,7 +1862,7 @@ var _Lo = []Range{ {0x30ff, 0x3105, 6}, {0x3106, 0x312d, 1}, {0x3131, 0x318e, 1}, - {0x31a0, 0x31b7, 1}, + {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, {0x4e00, 0x9fcb, 1}, @@ -1851,6 +1898,11 @@ var _Lo = []Range{ {0xaaba, 0xaabd, 1}, {0xaac0, 0xaac2, 2}, {0xaadb, 0xaadc, 1}, + {0xab01, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, {0xabc0, 0xabe2, 1}, {0xac00, 0xd7a3, 1}, {0xd7b0, 0xd7c6, 1}, @@ -1912,11 +1964,15 @@ var _Lo = []Range{ {0x10b40, 0x10b55, 1}, {0x10b60, 0x10b72, 1}, {0x10c00, 0x10c48, 1}, + {0x11003, 0x11037, 1}, {0x11083, 0x110af, 1}, {0x12000, 0x1236e, 1}, {0x13000, 0x1342e, 1}, + {0x16800, 0x16a38, 1}, + {0x1b000, 0x1b001, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, + {0x2b740, 0x2b81d, 1}, {0x2f800, 0x2fa1d, 1}, } @@ -1958,7 +2014,7 @@ var ( ) // Generated by running -// maketables --scripts=all --url=http://www.unicode.org/Public/5.2.0/ucd/ +// maketables --scripts=all --url=http://www.unicode.org/Public/6.0.0/ucd/ // DO NOT EDIT // Scripts is the set of Unicode script tables. @@ -1977,6 +2033,7 @@ var Scripts = map[string][]Range{ "Bopomofo": Bopomofo, "Imperial_Aramaic": Imperial_Aramaic, "Kaithi": Kaithi, + "Mandaic": Mandaic, "Old_South_Arabian": Old_South_Arabian, "Kayah_Li": Kayah_Li, "New_Tai_Lue": New_Tai_Lue, @@ -1987,6 +2044,7 @@ var Scripts = map[string][]Range{ "Old_Turkic": Old_Turkic, "Tamil": Tamil, "Tagalog": Tagalog, + "Brahmi": Brahmi, "Arabic": Arabic, "Tagbanwa": Tagbanwa, "Canadian_Aboriginal": Canadian_Aboriginal, @@ -2019,6 +2077,7 @@ var Scripts = map[string][]Range{ "Vai": Vai, "Cherokee": Cherokee, "Ogham": Ogham, + "Batak": Batak, "Syriac": Syriac, "Gurmukhi": Gurmukhi, "Tai_Tham": Tai_Tham, @@ -2065,17 +2124,17 @@ var _Katakana = []Range{ {0x3300, 0x3357, 1}, {0xff66, 0xff6f, 1}, {0xff71, 0xff9d, 1}, + {0x1b000, 0x1b000, 1}, } var _Malayalam = []Range{ {0x0d02, 0x0d03, 1}, {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, - {0x0d12, 0x0d28, 1}, - {0x0d2a, 0x0d39, 1}, + {0x0d12, 0x0d3a, 1}, {0x0d3d, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, - {0x0d4a, 0x0d4d, 1}, + {0x0d4a, 0x0d4e, 1}, {0x0d57, 0x0d57, 1}, {0x0d60, 0x0d63, 1}, {0x0d66, 0x0d75, 1}, @@ -2108,15 +2167,17 @@ var _Latin = []Range{ {0x1e00, 0x1eff, 1}, {0x2071, 0x2071, 1}, {0x207f, 0x207f, 1}, - {0x2090, 0x2094, 1}, + {0x2090, 0x209c, 1}, {0x212a, 0x212b, 1}, {0x2132, 0x2132, 1}, {0x214e, 0x214e, 1}, {0x2160, 0x2188, 1}, {0x2c60, 0x2c7f, 1}, {0xa722, 0xa787, 1}, - {0xa78b, 0xa78c, 1}, - {0xa7fb, 0xa7ff, 1}, + {0xa78b, 0xa78e, 1}, + {0xa790, 0xa791, 1}, + {0xa7a0, 0xa7a9, 1}, + {0xa7fa, 0xa7ff, 1}, {0xfb00, 0xfb06, 1}, {0xff21, 0xff3a, 1}, {0xff41, 0xff5a, 1}, @@ -2143,6 +2204,7 @@ var _Inherited = []Range{ {0x0300, 0x036f, 1}, {0x0485, 0x0486, 1}, {0x064b, 0x0655, 1}, + {0x065f, 0x065f, 1}, {0x0670, 0x0670, 1}, {0x0951, 0x0952, 1}, {0x1cd0, 0x1cd2, 1}, @@ -2150,10 +2212,10 @@ var _Inherited = []Range{ {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1ced, 1}, {0x1dc0, 0x1de6, 1}, - {0x1dfd, 0x1dff, 1}, + {0x1dfc, 0x1dff, 1}, {0x200c, 0x200d, 1}, {0x20d0, 0x20f0, 1}, - {0x302a, 0x302f, 1}, + {0x302a, 0x302d, 1}, {0x3099, 0x309a, 1}, {0xfe00, 0xfe0f, 1}, {0xfe20, 0xfe26, 1}, @@ -2188,8 +2250,9 @@ var _Samaritan = []Range{ } var _Bopomofo = []Range{ + {0x02ea, 0x02eb, 1}, {0x3105, 0x312d, 1}, - {0x31a0, 0x31b7, 1}, + {0x31a0, 0x31ba, 1}, } var _Imperial_Aramaic = []Range{ @@ -2201,6 +2264,11 @@ var _Kaithi = []Range{ {0x11080, 0x110c1, 1}, } +var _Mandaic = []Range{ + {0x0840, 0x085b, 1}, + {0x085e, 0x085e, 1}, +} + var _Old_South_Arabian = []Range{ {0x10a60, 0x10a7f, 1}, } @@ -2241,13 +2309,13 @@ var _Common = []Range{ {0x00d7, 0x00d7, 1}, {0x00f7, 0x00f7, 1}, {0x02b9, 0x02df, 1}, - {0x02e5, 0x02ff, 1}, + {0x02e5, 0x02e9, 1}, + {0x02ec, 0x02ff, 1}, {0x0374, 0x0374, 1}, {0x037e, 0x037e, 1}, {0x0385, 0x0385, 1}, {0x0387, 0x0387, 1}, {0x0589, 0x0589, 1}, - {0x0600, 0x0603, 1}, {0x060c, 0x060c, 1}, {0x061b, 0x061b, 1}, {0x061f, 0x061f, 1}, @@ -2256,7 +2324,6 @@ var _Common = []Range{ {0x06dd, 0x06dd, 1}, {0x0964, 0x0965, 1}, {0x0970, 0x0970, 1}, - {0x0cf1, 0x0cf2, 1}, {0x0e3f, 0x0e3f, 1}, {0x0fd5, 0x0fd8, 1}, {0x10fb, 0x10fb, 1}, @@ -2273,33 +2340,20 @@ var _Common = []Range{ {0x206a, 0x2070, 1}, {0x2074, 0x207e, 1}, {0x2080, 0x208e, 1}, - {0x20a0, 0x20b8, 1}, + {0x20a0, 0x20b9, 1}, {0x2100, 0x2125, 1}, {0x2127, 0x2129, 1}, {0x212c, 0x2131, 1}, {0x2133, 0x214d, 1}, {0x214f, 0x215f, 1}, {0x2189, 0x2189, 1}, - {0x2190, 0x23e8, 1}, + {0x2190, 0x23f3, 1}, {0x2400, 0x2426, 1}, {0x2440, 0x244a, 1}, - {0x2460, 0x26cd, 1}, - {0x26cf, 0x26e1, 1}, - {0x26e3, 0x26e3, 1}, - {0x26e8, 0x26ff, 1}, - {0x2701, 0x2704, 1}, - {0x2706, 0x2709, 1}, - {0x270c, 0x2727, 1}, - {0x2729, 0x274b, 1}, - {0x274d, 0x274d, 1}, - {0x274f, 0x2752, 1}, - {0x2756, 0x275e, 1}, - {0x2761, 0x2794, 1}, - {0x2798, 0x27af, 1}, - {0x27b1, 0x27be, 1}, - {0x27c0, 0x27ca, 1}, + {0x2460, 0x26ff, 1}, + {0x2701, 0x27ca, 1}, {0x27cc, 0x27cc, 1}, - {0x27d0, 0x27ff, 1}, + {0x27ce, 0x27ff, 1}, {0x2900, 0x2b4c, 1}, {0x2b50, 0x2b59, 1}, {0x2e00, 0x2e31, 1}, @@ -2373,23 +2427,47 @@ var _Common = []Range{ {0x1d7ce, 0x1d7ff, 1}, {0x1f000, 0x1f02b, 1}, {0x1f030, 0x1f093, 1}, + {0x1f0a0, 0x1f0ae, 1}, + {0x1f0b1, 0x1f0be, 1}, + {0x1f0c1, 0x1f0cf, 1}, + {0x1f0d1, 0x1f0df, 1}, {0x1f100, 0x1f10a, 1}, {0x1f110, 0x1f12e, 1}, - {0x1f131, 0x1f131, 1}, - {0x1f13d, 0x1f13d, 1}, - {0x1f13f, 0x1f13f, 1}, - {0x1f142, 0x1f142, 1}, - {0x1f146, 0x1f146, 1}, - {0x1f14a, 0x1f14e, 1}, - {0x1f157, 0x1f157, 1}, - {0x1f15f, 0x1f15f, 1}, - {0x1f179, 0x1f179, 1}, - {0x1f17b, 0x1f17c, 1}, - {0x1f17f, 0x1f17f, 1}, - {0x1f18a, 0x1f18d, 1}, - {0x1f190, 0x1f190, 1}, - {0x1f210, 0x1f231, 1}, + {0x1f130, 0x1f169, 1}, + {0x1f170, 0x1f19a, 1}, + {0x1f1e6, 0x1f1ff, 1}, + {0x1f201, 0x1f202, 1}, + {0x1f210, 0x1f23a, 1}, {0x1f240, 0x1f248, 1}, + {0x1f250, 0x1f251, 1}, + {0x1f300, 0x1f320, 1}, + {0x1f330, 0x1f335, 1}, + {0x1f337, 0x1f37c, 1}, + {0x1f380, 0x1f393, 1}, + {0x1f3a0, 0x1f3c4, 1}, + {0x1f3c6, 0x1f3ca, 1}, + {0x1f3e0, 0x1f3f0, 1}, + {0x1f400, 0x1f43e, 1}, + {0x1f440, 0x1f440, 1}, + {0x1f442, 0x1f4f7, 1}, + {0x1f4f9, 0x1f4fc, 1}, + {0x1f500, 0x1f53d, 1}, + {0x1f550, 0x1f567, 1}, + {0x1f5fb, 0x1f5ff, 1}, + {0x1f601, 0x1f610, 1}, + {0x1f612, 0x1f614, 1}, + {0x1f616, 0x1f616, 1}, + {0x1f618, 0x1f618, 1}, + {0x1f61a, 0x1f61a, 1}, + {0x1f61c, 0x1f61e, 1}, + {0x1f620, 0x1f625, 1}, + {0x1f628, 0x1f62b, 1}, + {0x1f62d, 0x1f62d, 1}, + {0x1f630, 0x1f633, 1}, + {0x1f635, 0x1f640, 1}, + {0x1f645, 0x1f64f, 1}, + {0x1f680, 0x1f6c5, 1}, + {0x1f700, 0x1f773, 1}, {0xe0001, 0xe0001, 1}, {0xe0020, 0xe007f, 1}, } @@ -2408,6 +2486,7 @@ var _Kannada = []Range{ {0x0cde, 0x0cde, 1}, {0x0ce0, 0x0ce3, 1}, {0x0ce6, 0x0cef, 1}, + {0x0cf1, 0x0cf2, 1}, } var _Old_Turkic = []Range{ @@ -2438,18 +2517,24 @@ var _Tagalog = []Range{ {0x170e, 0x1714, 1}, } +var _Brahmi = []Range{ + {0x11000, 0x1104d, 1}, + {0x11052, 0x1106f, 1}, +} + var _Arabic = []Range{ + {0x0600, 0x0603, 1}, {0x0606, 0x060b, 1}, {0x060d, 0x061a, 1}, {0x061e, 0x061e, 1}, - {0x0621, 0x063f, 1}, + {0x0620, 0x063f, 1}, {0x0641, 0x064a, 1}, {0x0656, 0x065e, 1}, {0x066a, 0x066f, 1}, {0x0671, 0x06dc, 1}, {0x06de, 0x06ff, 1}, {0x0750, 0x077f, 1}, - {0xfb50, 0xfbb1, 1}, + {0xfb50, 0xfbc1, 1}, {0xfbd3, 0xfd3d, 1}, {0xfd50, 0xfd8f, 1}, {0xfd92, 0xfdc7, 1}, @@ -2473,11 +2558,11 @@ var _Canadian_Aboriginal = []Range{ var _Tibetan = []Range{ {0x0f00, 0x0f47, 1}, {0x0f49, 0x0f6c, 1}, - {0x0f71, 0x0f8b, 1}, - {0x0f90, 0x0f97, 1}, + {0x0f71, 0x0f97, 1}, {0x0f99, 0x0fbc, 1}, {0x0fbe, 0x0fcc, 1}, {0x0fce, 0x0fd4, 1}, + {0x0fd9, 0x0fda, 1}, } var _Coptic = []Range{ @@ -2489,6 +2574,7 @@ var _Coptic = []Range{ var _Hiragana = []Range{ {0x3041, 0x3096, 1}, {0x309d, 0x309f, 1}, + {0x1b001, 0x1b001, 1}, {0x1f200, 0x1f200, 1}, } @@ -2620,6 +2706,7 @@ var _Saurashtra = []Range{ var _Hangul = []Range{ {0x1100, 0x11ff, 1}, + {0x302e, 0x302f, 1}, {0x3131, 0x318e, 1}, {0x3200, 0x321e, 1}, {0x3260, 0x327e, 1}, @@ -2671,7 +2758,7 @@ var _Oriya = []Range{ {0x0b56, 0x0b57, 1}, {0x0b5c, 0x0b5d, 1}, {0x0b5f, 0x0b63, 1}, - {0x0b66, 0x0b71, 1}, + {0x0b66, 0x0b77, 1}, } var _Buhid = []Range{ @@ -2695,7 +2782,7 @@ var _Ethiopic = []Range{ {0x12d8, 0x1310, 1}, {0x1312, 0x1315, 1}, {0x1318, 0x135a, 1}, - {0x135f, 0x137c, 1}, + {0x135d, 0x137c, 1}, {0x1380, 0x1399, 1}, {0x2d80, 0x2d96, 1}, {0x2da0, 0x2da6, 1}, @@ -2706,6 +2793,11 @@ var _Ethiopic = []Range{ {0x2dc8, 0x2dce, 1}, {0x2dd0, 0x2dd6, 1}, {0x2dd8, 0x2dde, 1}, + {0xab01, 0xab06, 1}, + {0xab09, 0xab0e, 1}, + {0xab11, 0xab16, 1}, + {0xab20, 0xab26, 1}, + {0xab28, 0xab2e, 1}, } var _Javanese = []Range{ @@ -2730,6 +2822,11 @@ var _Ogham = []Range{ {0x1680, 0x169c, 1}, } +var _Batak = []Range{ + {0x1bc0, 0x1bf3, 1}, + {0x1bfc, 0x1bff, 1}, +} + var _Syriac = []Range{ {0x0700, 0x070d, 1}, {0x070f, 0x074a, 1}, @@ -2796,6 +2893,7 @@ var _Buginese = []Range{ var _Bamum = []Range{ {0xa6a0, 0xa6f7, 1}, + {0x16800, 0x16a38, 1}, } var _Lepcha = []Range{ @@ -2890,13 +2988,10 @@ var _Tai_Viet = []Range{ } var _Devanagari = []Range{ - {0x0900, 0x0939, 1}, - {0x093c, 0x094e, 1}, - {0x0950, 0x0950, 1}, - {0x0953, 0x0955, 1}, - {0x0958, 0x0963, 1}, + {0x0900, 0x0950, 1}, + {0x0953, 0x0963, 1}, {0x0966, 0x096f, 1}, - {0x0971, 0x0972, 1}, + {0x0971, 0x0977, 1}, {0x0979, 0x097f, 1}, {0xa8e0, 0xa8fb, 1}, } @@ -2908,7 +3003,8 @@ var _Lydian = []Range{ var _Tifinagh = []Range{ {0x2d30, 0x2d65, 1}, - {0x2d6f, 0x2d6f, 1}, + {0x2d6f, 0x2d70, 1}, + {0x2d7f, 0x2d7f, 1}, } var _Ugaritic = []Range{ @@ -2923,12 +3019,11 @@ var _Thai = []Range{ var _Cyrillic = []Range{ {0x0400, 0x0484, 1}, - {0x0487, 0x0525, 1}, + {0x0487, 0x0527, 1}, {0x1d2b, 0x1d2b, 1}, {0x1d78, 0x1d78, 1}, {0x2de0, 0x2dff, 1}, - {0xa640, 0xa65f, 1}, - {0xa662, 0xa673, 1}, + {0xa640, 0xa673, 1}, {0xa67c, 0xa697, 1}, } @@ -2982,6 +3077,7 @@ var _Han = []Range{ {0xfa70, 0xfad9, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, + {0x2b740, 0x2b81d, 1}, {0x2f800, 0x2fa1d, 1}, } @@ -2995,8 +3091,10 @@ var ( Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan. Balinese = _Balinese // Balinese is the set of Unicode characters in script Balinese. Bamum = _Bamum // Bamum is the set of Unicode characters in script Bamum. + Batak = _Batak // Batak is the set of Unicode characters in script Batak. Bengali = _Bengali // Bengali is the set of Unicode characters in script Bengali. Bopomofo = _Bopomofo // Bopomofo is the set of Unicode characters in script Bopomofo. + Brahmi = _Brahmi // Brahmi is the set of Unicode characters in script Brahmi. Braille = _Braille // Braille is the set of Unicode characters in script Braille. Buginese = _Buginese // Buginese is the set of Unicode characters in script Buginese. Buhid = _Buhid // Buhid is the set of Unicode characters in script Buhid. @@ -3044,6 +3142,7 @@ var ( Lycian = _Lycian // Lycian is the set of Unicode characters in script Lycian. Lydian = _Lydian // Lydian is the set of Unicode characters in script Lydian. Malayalam = _Malayalam // Malayalam is the set of Unicode characters in script Malayalam. + Mandaic = _Mandaic // Mandaic is the set of Unicode characters in script Mandaic. Meetei_Mayek = _Meetei_Mayek // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek. Mongolian = _Mongolian // Mongolian is the set of Unicode characters in script Mongolian. Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar. @@ -3085,7 +3184,7 @@ var ( ) // Generated by running -// maketables --props=all --url=http://www.unicode.org/Public/5.2.0/ucd/ +// maketables --props=all --url=http://www.unicode.org/Public/6.0.0/ucd/ // DO NOT EDIT // Properties is the set of Unicode property tables. @@ -3236,6 +3335,7 @@ var _ASCII_Hex_Digit = []Range{ var _Deprecated = []Range{ {0x0149, 0x0149, 1}, + {0x0673, 0x0673, 1}, {0x0f77, 0x0f77, 1}, {0x0f79, 0x0f79, 1}, {0x17a3, 0x17a4, 1}, @@ -3263,6 +3363,7 @@ var _Terminal_Punctuation = []Range{ {0x070c, 0x070c, 1}, {0x07f8, 0x07f9, 1}, {0x0830, 0x083e, 1}, + {0x085e, 0x085e, 1}, {0x0964, 0x0965, 1}, {0x0e5a, 0x0e5b, 1}, {0x0f08, 0x0f08, 1}, @@ -3309,6 +3410,7 @@ var _Terminal_Punctuation = []Range{ {0x10857, 0x10857, 1}, {0x1091f, 0x1091f, 1}, {0x10b3a, 0x10b3f, 1}, + {0x11047, 0x1104d, 1}, {0x110be, 0x110c1, 1}, {0x12470, 0x12473, 1}, } @@ -3332,6 +3434,7 @@ var _Other_ID_Continue = []Range{ {0x00b7, 0x00b7, 1}, {0x0387, 0x0387, 1}, {0x1369, 0x1371, 1}, + {0x19da, 0x19da, 1}, } var _Bidi_Control = []Range{ @@ -3383,6 +3486,7 @@ var _Other_Math = []Range{ {0x20e5, 0x20e6, 1}, {0x20eb, 0x20ef, 1}, {0x2102, 0x2102, 1}, + {0x2107, 0x2107, 1}, {0x210a, 0x2113, 1}, {0x2115, 0x2115, 1}, {0x2119, 0x211d, 1}, @@ -3480,6 +3584,7 @@ var _Unified_Ideograph = []Range{ {0xfa27, 0xfa29, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, + {0x2b740, 0x2b81d, 1}, } var _Hyphen = []Range{ @@ -3535,9 +3640,11 @@ var _STerm = []Range{ {0x1362, 0x1362, 1}, {0x1367, 0x1368, 1}, {0x166e, 0x166e, 1}, + {0x1735, 0x1736, 1}, {0x1803, 0x1803, 1}, {0x1809, 0x1809, 1}, {0x1944, 0x1945, 1}, + {0x1aa8, 0x1aab, 1}, {0x1b5a, 0x1b5b, 1}, {0x1b5e, 0x1b5f, 1}, {0x1c3b, 0x1c3c, 1}, @@ -3562,6 +3669,8 @@ var _STerm = []Range{ {0xff0e, 0xff0e, 1}, {0xff1f, 0xff1f, 1}, {0xff61, 0xff61, 1}, + {0x10a56, 0x10a57, 1}, + {0x11047, 0x11048, 1}, {0x110be, 0x110c1, 1}, } @@ -3574,7 +3683,7 @@ var _Other_Alphabetic = []Range{ {0x05c7, 0x05c7, 1}, {0x0610, 0x061a, 1}, {0x064b, 0x0657, 1}, - {0x0659, 0x065e, 1}, + {0x0659, 0x065f, 1}, {0x0670, 0x0670, 1}, {0x06d6, 0x06dc, 1}, {0x06e1, 0x06e4, 1}, @@ -3588,9 +3697,10 @@ var _Other_Alphabetic = []Range{ {0x0825, 0x0827, 1}, {0x0829, 0x082c, 1}, {0x0900, 0x0903, 1}, + {0x093a, 0x093b, 1}, {0x093e, 0x094c, 1}, - {0x094e, 0x094e, 1}, - {0x0955, 0x0955, 1}, + {0x094e, 0x094f, 1}, + {0x0955, 0x0957, 1}, {0x0962, 0x0963, 1}, {0x0981, 0x0983, 1}, {0x09be, 0x09c4, 1}, @@ -3652,7 +3762,7 @@ var _Other_Alphabetic = []Range{ {0x0ebb, 0x0ebc, 1}, {0x0ecd, 0x0ecd, 1}, {0x0f71, 0x0f81, 1}, - {0x0f90, 0x0f97, 1}, + {0x0f8d, 0x0f97, 1}, {0x0f99, 0x0fbc, 1}, {0x102b, 0x1036, 1}, {0x1038, 0x1038, 1}, @@ -3682,6 +3792,7 @@ var _Other_Alphabetic = []Range{ {0x1b35, 0x1b43, 1}, {0x1b80, 0x1b82, 1}, {0x1ba1, 0x1ba9, 1}, + {0x1be7, 0x1bf1, 1}, {0x1c24, 0x1c35, 1}, {0x1cf2, 0x1cf2, 1}, {0x24b6, 0x24e9, 1}, @@ -3692,7 +3803,7 @@ var _Other_Alphabetic = []Range{ {0xa926, 0xa92a, 1}, {0xa947, 0xa952, 1}, {0xa980, 0xa983, 1}, - {0xa9b3, 0xa9bf, 1}, + {0xa9b4, 0xa9bf, 1}, {0xaa29, 0xaa36, 1}, {0xaa43, 0xaa43, 1}, {0xaa4c, 0xaa4d, 1}, @@ -3705,6 +3816,8 @@ var _Other_Alphabetic = []Range{ {0x10a01, 0x10a03, 1}, {0x10a05, 0x10a06, 1}, {0x10a0c, 0x10a0f, 1}, + {0x11000, 0x11002, 1}, + {0x11038, 0x11045, 1}, {0x11082, 0x11082, 1}, {0x110b0, 0x110b8, 1}, } @@ -3867,6 +3980,7 @@ var _Ideographic = []Range{ {0xfa70, 0xfad9, 1}, {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, + {0x2b740, 0x2b81d, 1}, {0x2f800, 0x2fa1d, 1}, } @@ -3978,7 +4092,7 @@ var ( ) // Generated by running -// maketables --data=http://www.unicode.org/Public/5.2.0/ucd/UnicodeData.txt +// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt // DO NOT EDIT // CaseRanges is the table describing case mappings for all letters with @@ -4078,6 +4192,7 @@ var _CaseRanges = []CaseRange{ {0x025B, 0x025B, d{-203, 0, -203}}, {0x0260, 0x0260, d{-205, 0, -205}}, {0x0263, 0x0263, d{-207, 0, -207}}, + {0x0265, 0x0265, d{42280, 0, 42280}}, {0x0268, 0x0268, d{-209, 0, -209}}, {0x0269, 0x0269, d{-211, 0, -211}}, {0x026B, 0x026B, d{10743, 0, 10743}}, @@ -4134,7 +4249,7 @@ var _CaseRanges = []CaseRange{ {0x04C0, 0x04C0, d{0, 15, 0}}, {0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}}, {0x04CF, 0x04CF, d{-15, 0, -15}}, - {0x04D0, 0x0525, d{UpperLower, UpperLower, UpperLower}}, + {0x04D0, 0x0527, d{UpperLower, UpperLower, UpperLower}}, {0x0531, 0x0556, d{0, 48, 0}}, {0x0561, 0x0586, d{-48, 0, -48}}, {0x10A0, 0x10C5, d{0, 7264, 0}}, @@ -4222,8 +4337,7 @@ var _CaseRanges = []CaseRange{ {0x2C80, 0x2CE3, d{UpperLower, UpperLower, UpperLower}}, {0x2CEB, 0x2CEE, d{UpperLower, UpperLower, UpperLower}}, {0x2D00, 0x2D25, d{-7264, 0, -7264}}, - {0xA640, 0xA65F, d{UpperLower, UpperLower, UpperLower}}, - {0xA662, 0xA66D, d{UpperLower, UpperLower, UpperLower}}, + {0xA640, 0xA66D, d{UpperLower, UpperLower, UpperLower}}, {0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}}, {0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}}, {0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}}, @@ -4231,6 +4345,9 @@ var _CaseRanges = []CaseRange{ {0xA77D, 0xA77D, d{0, -35332, 0}}, {0xA77E, 0xA787, d{UpperLower, UpperLower, UpperLower}}, {0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}}, + {0xA78D, 0xA78D, d{0, -42280, 0}}, + {0xA790, 0xA791, d{UpperLower, UpperLower, UpperLower}}, + {0xA7A0, 0xA7A9, d{UpperLower, UpperLower, UpperLower}}, {0xFF21, 0xFF3A, d{0, 32, 0}}, {0xFF41, 0xFF5A, d{-32, 0, -32}}, {0x10400, 0x10427, d{0, 40, 0}}, diff --git a/src/pkg/unsafe/unsafe.go b/src/pkg/unsafe/unsafe.go index fc583fe95..3a4e30c00 100644 --- a/src/pkg/unsafe/unsafe.go +++ b/src/pkg/unsafe/unsafe.go @@ -14,8 +14,9 @@ type ArbitraryType int // Pointer represents a pointer to an arbitrary type. There are three special operations // available for type Pointer that are not available for other types. // 1) A pointer value of any type can be converted to a Pointer. -// 2) A uintptr can be converted to a Pointer. -// 3) A Pointer can be converted to a uintptr. +// 2) A Pointer can be converted to a pointer value of any type. +// 3) A uintptr can be converted to a Pointer. +// 4) A Pointer can be converted to a uintptr. // Pointer therefore allows a program to defeat the type system and read and write // arbitrary memory. It should be used with extreme care. type Pointer *ArbitraryType diff --git a/src/pkg/websocket/websocket_test.go b/src/pkg/websocket/websocket_test.go index cc4b9dc18..204a9de1e 100644 --- a/src/pkg/websocket/websocket_test.go +++ b/src/pkg/websocket/websocket_test.go @@ -24,7 +24,7 @@ func echoServer(ws *Conn) { io.Copy(ws, ws) } func startServer() { l, e := net.Listen("tcp", "127.0.0.1:0") // any available address if e != nil { - log.Exitf("net.Listen tcp :0 %v", e) + log.Fatalf("net.Listen tcp :0 %v", e) } serverAddr = l.Addr().String() log.Print("Test WebSocket server listening on ", serverAddr) diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go index 9175659b2..9ae3bb8ee 100644 --- a/src/pkg/xml/read.go +++ b/src/pkg/xml/read.go @@ -6,6 +6,7 @@ package xml import ( "bytes" + "fmt" "io" "os" "reflect" @@ -39,6 +40,7 @@ import ( // Name string // Phone string // Email []Email +// Groups []string "group>value" // } // // result := Result{Name: "name", Phone: "phone", Email: nil} @@ -53,6 +55,10 @@ import ( // <addr>gre@work.com</addr> // </email> // <name>Grace R. Emlin</name> +// <group> +// <value>Friends</value> +// <value>Squash</value> +// </group> // <address>123 Main Street</address> // </result> // @@ -65,10 +71,13 @@ import ( // Email{"home", "gre@example.com"}, // Email{"work", "gre@work.com"}, // }, +// []string{"Friends", "Squash"}, // } // // Note that the field r.Phone has not been modified and -// that the XML <address> element was discarded. +// that the XML <address> element was discarded. Also, the field +// Groups was assigned considering the element path provided in the +// field tag. // // Because Unmarshal uses the reflect package, it can only // assign to upper case fields. Unmarshal uses a case-insensitive @@ -97,6 +106,13 @@ import ( // The struct field may have type []byte or string. // If there is no such field, the character data is discarded. // +// * If the XML element contains a sub-element whose name matches +// the prefix of a struct field tag formatted as "a>b>c", unmarshal +// will descend into the XML structure looking for elements with the +// given names, and will map the innermost elements to that struct field. +// A struct field tag starting with ">" is equivalent to one starting +// with the field name followed by ">". +// // * If the XML element contains a sub-element whose name // matches a struct field whose tag is neither "attr" nor "chardata", // Unmarshal maps the sub-element to that struct field. @@ -104,7 +120,7 @@ import ( // maps the sub-element to that struct field. // // Unmarshal maps an XML element to a string or []byte by saving the -// concatenation of that elements character data in the string or []byte. +// concatenation of that element's character data in the string or []byte. // // Unmarshal maps an XML element to a slice by extending the length // of the slice and mapping the element to the newly created value. @@ -141,6 +157,18 @@ type UnmarshalError string func (e UnmarshalError) String() string { return string(e) } +// A TagPathError represents an error in the unmarshalling process +// caused by the use of field tags with conflicting paths. +type TagPathError struct { + Struct reflect.Type + Field1, Tag1 string + Field2, Tag2 string +} + +func (e *TagPathError) String() string { + return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2) +} + // The Parser's Unmarshal method is like xml.Unmarshal // except that it can be passed a pointer to the initial start element, // useful when a client reads some raw XML tokens itself @@ -211,7 +239,9 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error { saveXMLData []byte sv *reflect.StructValue styp *reflect.StructType + fieldPaths map[string]pathInfo ) + switch v := val.(type) { default: return os.ErrorString("unknown type " + v.Type().String()) @@ -330,6 +360,24 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error { saveXMLIndex = p.savedOffset() } } + + default: + if strings.Contains(f.Tag, ">") { + if fieldPaths == nil { + fieldPaths = make(map[string]pathInfo) + } + path := strings.ToLower(f.Tag) + if strings.HasPrefix(f.Tag, ">") { + path = strings.ToLower(f.Name) + path + } + if strings.HasSuffix(f.Tag, ">") { + path = path[:len(path)-1] + } + err := addFieldPath(sv, fieldPaths, path, f.Index) + if err != nil { + return err + } + } } } } @@ -352,9 +400,19 @@ Loop: // Look up by tag name. if sv != nil { k := fieldName(t.Name.Local) + + if fieldPaths != nil { + if _, found := fieldPaths[k]; found { + if err := p.unmarshalPaths(sv, fieldPaths, k, &t); err != nil { + return err + } + continue Loop + } + } + match := func(s string) bool { // check if the name matches ignoring case - if strings.ToLower(s) != strings.ToLower(k) { + if strings.ToLower(s) != k { return false } // now check that it's public @@ -470,6 +528,75 @@ Loop: return nil } +type pathInfo struct { + fieldIdx []int + complete bool +} + +// addFieldPath takes an element path such as "a>b>c" and fills the +// paths map with all paths leading to it ("a", "a>b", and "a>b>c"). +// It is okay for paths to share a common, shorter prefix but not ok +// for one path to itself be a prefix of another. +func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path string, fieldIdx []int) os.Error { + if info, found := paths[path]; found { + return tagError(sv, info.fieldIdx, fieldIdx) + } + paths[path] = pathInfo{fieldIdx, true} + for { + i := strings.LastIndex(path, ">") + if i < 0 { + break + } + path = path[:i] + if info, found := paths[path]; found { + if info.complete { + return tagError(sv, info.fieldIdx, fieldIdx) + } + } else { + paths[path] = pathInfo{fieldIdx, false} + } + } + return nil + +} + +func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error { + t := sv.Type().(*reflect.StructType) + f1 := t.FieldByIndex(idx1) + f2 := t.FieldByIndex(idx2) + return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag} +} + +// unmarshalPaths walks down an XML structure looking for +// wanted paths, and calls unmarshal on them. +func (p *Parser) unmarshalPaths(sv *reflect.StructValue, paths map[string]pathInfo, path string, start *StartElement) os.Error { + if info, _ := paths[path]; info.complete { + return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start) + } + for { + tok, err := p.Token() + if err != nil { + return err + } + switch t := tok.(type) { + case StartElement: + k := path + ">" + fieldName(t.Name.Local) + if _, found := paths[k]; found { + if err := p.unmarshalPaths(sv, paths, k, &t); err != nil { + return err + } + continue + } + if err := p.Skip(); err != nil { + return err + } + case EndElement: + return nil + } + } + panic("unreachable") +} + // Have already read a start element. // Read tokens until we find the end element. // Token is taking care of making sure the diff --git a/src/pkg/xml/read_test.go b/src/pkg/xml/read_test.go index 9ec1065c2..71ceddce4 100644 --- a/src/pkg/xml/read_test.go +++ b/src/pkg/xml/read_test.go @@ -230,3 +230,100 @@ func TestFieldName(t *testing.T) { } } } + +const pathTestString = ` +<result> + <before>1</before> + <items> + <item1> + <value>A</value> + </item1> + <item2> + <value>B</value> + </item2> + <Item1> + <Value>C</Value> + <Value>D</Value> + </Item1> + </items> + <after>2</after> +</result> +` + +type PathTestItem struct { + Value string +} + +type PathTestA struct { + Items []PathTestItem ">item1" + Before, After string +} + +type PathTestB struct { + Other []PathTestItem "items>Item1" + Before, After string +} + +type PathTestC struct { + Values1 []string "items>item1>value" + Values2 []string "items>item2>value" + Before, After string +} + +type PathTestSet struct { + Item1 []PathTestItem +} + +type PathTestD struct { + Other PathTestSet "items>" + Before, After string +} + +var pathTests = []interface{}{ + &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, + &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, + &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"}, + &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"}, +} + +func TestUnmarshalPaths(t *testing.T) { + for _, pt := range pathTests { + p := reflect.MakeZero(reflect.NewValue(pt).Type()).(*reflect.PtrValue) + p.PointTo(reflect.MakeZero(p.Type().(*reflect.PtrType).Elem())) + v := p.Interface() + if err := Unmarshal(StringReader(pathTestString), v); err != nil { + t.Fatalf("Unmarshal: %s", err) + } + if !reflect.DeepEqual(v, pt) { + t.Fatalf("have %#v\nwant %#v", v, pt) + } + } +} + +type BadPathTestA struct { + First string "items>item1" + Other string "items>item2" + Second string "items>" +} + +type BadPathTestB struct { + Other string "items>item2>value" + First string "items>item1" + Second string "items>item1>value" +} + +var badPathTests = []struct { + v, e interface{} +}{ + {&BadPathTestA{}, &TagPathError{reflect.Typeof(BadPathTestA{}), "First", "items>item1", "Second", "items>"}}, + {&BadPathTestB{}, &TagPathError{reflect.Typeof(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}}, +} + +func TestUnmarshalBadPaths(t *testing.T) { + for _, tt := range badPathTests { + err := Unmarshal(StringReader(pathTestString), tt.v) + if !reflect.DeepEqual(err, tt.e) { + t.Fatalf("Unmarshal with %#v didn't fail properly: %#v", tt.v, err) + } + } +} diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go index 9ab199a30..317ecabd9 100644 --- a/src/pkg/xml/xml_test.go +++ b/src/pkg/xml/xml_test.go @@ -227,7 +227,6 @@ type allScalars struct { Uint32 uint32 Uint64 uint64 Uintptr uintptr - Float float Float32 float32 Float64 float64 String string @@ -249,7 +248,6 @@ var all = allScalars{ Uint32: 9, Uint64: 10, Uintptr: 11, - Float: 12.0, Float32: 13.0, Float64: 14.0, String: "15", diff --git a/src/run.bash b/src/run.bash index 0cd129253..731e07e49 100755 --- a/src/run.bash +++ b/src/run.bash @@ -103,6 +103,12 @@ if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then fi ) || exit $? +(xcd ../doc/codelab/wiki +if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then + gomake test +fi +) || exit $? + for i in ../misc/dashboard/builder ../misc/goplay do (xcd $i diff --git a/test/append.go b/test/append.go index 17c665227..96421c36b 100644 --- a/test/append.go +++ b/test/append.go @@ -193,7 +193,7 @@ func verifyInterface() { case 2: e[i] = fmt.Sprintf("%d", i) case 3: - e[i] = float(i) + e[i] = float64(i) } } diff --git a/test/blank.go b/test/blank.go index 6e69f8aaa..681a5e77c 100644 --- a/test/blank.go +++ b/test/blank.go @@ -28,7 +28,7 @@ const ( c4 ) -var ints = []string { +var ints = []string{ "1", "2", "3", @@ -36,15 +36,15 @@ var ints = []string { func f() (int, int) { call += "f" - return 1,2 + return 1, 2 } -func g() (float, float) { +func g() (float64, float64) { call += "g" - return 3,4 + return 3, 4 } -func h(_ int, _ float) { +func h(_ int, _ float64) { } func i() int { @@ -55,43 +55,64 @@ func i() int { var _ = i() func main() { - if call != "i" {panic("init did not run")} + if call != "i" { + panic("init did not run") + } call = "" _, _ = f() a, _ := f() - if a != 1 {panic(a)} + if a != 1 { + panic(a) + } b, _ := g() - if b != 3 {panic(b)} + if b != 3 { + panic(b) + } _, a = f() - if a != 2 {panic(a)} + if a != 2 { + panic(a) + } _, b = g() - if b != 4 {panic(b)} + if b != 4 { + panic(b) + } _ = i() - if call != "ffgfgi" {panic(call)} - if c4 != 4 {panic(c4)} + if call != "ffgfgi" { + panic(call) + } + if c4 != 4 { + panic(c4) + } out := "" for _, s := range ints { out += s } - if out != "123" {panic(out)} + if out != "123" { + panic(out) + } sum := 0 for s := range ints { sum += s } - if sum != 3 {panic(sum)} + if sum != 3 { + panic(sum) + } - h(a,b) + h(a, b) } // useless but legal var _ int = 1 var _ = 2 var _, _ = 3, 4 + const _ = 3 const _, _ = 4, 5 + type _ int + func _() { panic("oops") } diff --git a/test/chan/doubleselect.go b/test/chan/doubleselect.go index 592d2f54a..3c7412ed6 100644 --- a/test/chan/doubleselect.go +++ b/test/chan/doubleselect.go @@ -21,6 +21,8 @@ var iterations *int = flag.Int("n", 100000, "number of iterations") func sender(n int, c1, c2, c3, c4 chan<- int) { defer close(c1) defer close(c2) + defer close(c3) + defer close(c4) for i := 0; i < n; i++ { select { @@ -35,26 +37,18 @@ func sender(n int, c1, c2, c3, c4 chan<- int) { // mux receives the values from sender and forwards them onto another channel. // It would be simplier to just have sender's four cases all be the same // channel, but this doesn't actually trigger the bug. -func mux(out chan<- int, in <-chan int) { - for { - v := <-in - if closed(in) { - close(out) - break - } +func mux(out chan<- int, in <-chan int, done chan<- bool) { + for v := range in { out <- v } + done <- true } // recver gets a steam of values from the four mux's and checks for duplicates. func recver(in <-chan int) { seen := make(map[int]bool) - for { - v := <-in - if closed(in) { - break - } + for v := range in { if _, ok := seen[v]; ok { println("got duplicate value: ", v) panic("fail") @@ -70,15 +64,23 @@ func main() { c2 := make(chan int) c3 := make(chan int) c4 := make(chan int) + done := make(chan bool) cmux := make(chan int) go sender(*iterations, c1, c2, c3, c4) - go mux(cmux, c1) - go mux(cmux, c2) - go mux(cmux, c3) - go mux(cmux, c4) + go mux(cmux, c1, done) + go mux(cmux, c2, done) + go mux(cmux, c3, done) + go mux(cmux, c4, done) + go func() { + <-done + <-done + <-done + <-done + close(cmux) + }() // We keep the recver because it might catch more bugs in the future. // However, the result of the bug linked to at the top is that we'll - // end up panicing with: "throw: bad g->status in ready". + // end up panicking with: "throw: bad g->status in ready". recver(cmux) print("PASS\n") } diff --git a/test/chan/nonblock.go b/test/chan/nonblock.go index 52f04bfb1..33afb3291 100644 --- a/test/chan/nonblock.go +++ b/test/chan/nonblock.go @@ -76,7 +76,6 @@ func main() { var i64 int64 var b bool var s string - var ok bool var sync = make(chan bool) @@ -86,35 +85,45 @@ func main() { cb := make(chan bool, buffer) cs := make(chan string, buffer) - i32, ok = <-c32 - if ok { + select { + case i32 = <-c32: panic("blocked i32sender") + default: } - i64, ok = <-c64 - if ok { + select { + case i64 = <-c64: panic("blocked i64sender") + default: } - b, ok = <-cb - if ok { + select { + case b = <-cb: panic("blocked bsender") + default: } - s, ok = <-cs - if ok { + select { + case s = <-cs: panic("blocked ssender") + default: } go i32receiver(c32, sync) try := 0 - for !(c32 <- 123) { - try++ - if try > maxTries { - println("i32receiver buffer=", buffer) - panic("fail") + Send32: + for { + select { + case c32 <- 123: + break Send32 + default: + try++ + if try > maxTries { + println("i32receiver buffer=", buffer) + panic("fail") + } + sleep() } - sleep() } <-sync @@ -123,13 +132,19 @@ func main() { <-sync } try = 0 - for i32, ok = <-c32; !ok; i32, ok = <-c32 { - try++ - if try > maxTries { - println("i32sender buffer=", buffer) - panic("fail") + Recv32: + for { + select { + case i32 = <-c32: + break Recv32 + default: + try++ + if try > maxTries { + println("i32sender buffer=", buffer) + panic("fail") + } + sleep() } - sleep() } if i32 != 234 { panic("i32sender value") @@ -140,12 +155,18 @@ func main() { go i64receiver(c64, sync) try = 0 - for !(c64 <- 123456) { - try++ - if try > maxTries { - panic("i64receiver") + Send64: + for { + select { + case c64 <- 123456: + break Send64 + default: + try++ + if try > maxTries { + panic("i64receiver") + } + sleep() } - sleep() } <-sync @@ -154,12 +175,18 @@ func main() { <-sync } try = 0 - for i64, ok = <-c64; !ok; i64, ok = <-c64 { - try++ - if try > maxTries { - panic("i64sender") + Recv64: + for { + select { + case i64 = <-c64: + break Recv64 + default: + try++ + if try > maxTries { + panic("i64sender") + } + sleep() } - sleep() } if i64 != 234567 { panic("i64sender value") @@ -170,12 +197,18 @@ func main() { go breceiver(cb, sync) try = 0 - for !(cb <- true) { - try++ - if try > maxTries { - panic("breceiver") + SendBool: + for { + select { + case cb <- true: + break SendBool + default: + try++ + if try > maxTries { + panic("breceiver") + } + sleep() } - sleep() } <-sync @@ -184,12 +217,18 @@ func main() { <-sync } try = 0 - for b, ok = <-cb; !ok; b, ok = <-cb { - try++ - if try > maxTries { - panic("bsender") + RecvBool: + for { + select { + case b = <-cb: + break RecvBool + default: + try++ + if try > maxTries { + panic("bsender") + } + sleep() } - sleep() } if !b { panic("bsender value") @@ -200,12 +239,18 @@ func main() { go sreceiver(cs, sync) try = 0 - for !(cs <- "hello") { - try++ - if try > maxTries { - panic("sreceiver") + SendString: + for { + select { + case cs <- "hello": + break SendString + default: + try++ + if try > maxTries { + panic("sreceiver") + } + sleep() } - sleep() } <-sync @@ -214,12 +259,18 @@ func main() { <-sync } try = 0 - for s, ok = <-cs; !ok; s, ok = <-cs { - try++ - if try > maxTries { - panic("ssender") + RecvString: + for { + select { + case s = <-cs: + break RecvString + default: + try++ + if try > maxTries { + panic("ssender") + } + sleep() } - sleep() } if s != "hello again" { panic("ssender value") diff --git a/test/chan/perm.go b/test/chan/perm.go index d08c03519..c725829d1 100644 --- a/test/chan/perm.go +++ b/test/chan/perm.go @@ -9,49 +9,46 @@ package main var ( cr <-chan int cs chan<- int - c chan int + c chan int ) func main() { - cr = c // ok - cs = c // ok - c = cr // ERROR "illegal types|incompatible|cannot" - c = cs // ERROR "illegal types|incompatible|cannot" - cr = cs // ERROR "illegal types|incompatible|cannot" - cs = cr // ERROR "illegal types|incompatible|cannot" - - c <- 0 // ok - ok := c <- 0 // ok - _ = ok - <-c // ok - x, ok := <-c // ok - _, _ = x, ok - - cr <- 0 // ERROR "send" - ok = cr <- 0 // ERROR "send" - _ = ok - <-cr // ok - x, ok = <-cr // ok - _, _ = x, ok - - cs <- 0 // ok - ok = cs <- 0 // ok - _ = ok - <-cs // ERROR "receive" - x, ok = <-cs // ERROR "receive" - _, _ = x, ok + cr = c // ok + cs = c // ok + c = cr // ERROR "illegal types|incompatible|cannot" + c = cs // ERROR "illegal types|incompatible|cannot" + cr = cs // ERROR "illegal types|incompatible|cannot" + cs = cr // ERROR "illegal types|incompatible|cannot" + + c <- 0 // ok + <-c // ok + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // x, ok := <-c // ok + // _, _ = x, ok + + cr <- 0 // ERROR "send" + <-cr // ok + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // x, ok = <-cr // ok + // _, _ = x, ok + + cs <- 0 // ok + <-cs // ERROR "receive" + ////TODO(rsc): uncomment when this syntax is valid for receive+check closed + //// x, ok = <-cs // ERROR "receive" + //// _, _ = x, ok select { - case c <- 0: // ok - case x := <-c: // ok + case c <- 0: // ok + case x := <-c: // ok _ = x - case cr <- 0: // ERROR "send" - case x := <-cr: // ok + case cr <- 0: // ERROR "send" + case x := <-cr: // ok _ = x - case cs <- 0: // ok - case x := <-cs: // ERROR "receive" + case cs <- 0: // ok + case x := <-cs: // ERROR "receive" _ = x } } diff --git a/test/chan/select3.go b/test/chan/select3.go index a1a2ef50b..47941063c 100644 --- a/test/chan/select3.go +++ b/test/chan/select3.go @@ -97,13 +97,9 @@ func main() { } }) - // sending (a small number of times) to a closed channel is not specified - // but the current implementation doesn't block: test that different - // implementations behave the same - testBlock(never, func() { - for i := 0; i < 10; i++ { - closedch <- 7 - } + // sending to a closed channel panics. + testPanic(always, func() { + closedch <- 7 }) // receiving from a non-ready channel always blocks @@ -189,15 +185,24 @@ func main() { } }) - // selects with closed channels don't block + // selects with closed channels behave like ordinary operations testBlock(never, func() { select { case <-closedch: } }) - testBlock(never, func() { + testPanic(always, func() { select { case closedch <- 7: } }) + + // select should not get confused if it sees itself + testBlock(always, func() { + c := make(chan int) + select { + case c <- 1: + case <-c: + } + }) } diff --git a/test/chan/select5.go b/test/chan/select5.go new file mode 100644 index 000000000..0678b8dab --- /dev/null +++ b/test/chan/select5.go @@ -0,0 +1,482 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go && +// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: select5 +// rm -f tmp.go + +// Copyright 2011 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. + +// Generate test of channel operations and simple selects. +// Only doing one real send or receive at a time, but phrased +// in various ways that the compiler may or may not rewrite +// into simpler expressions. + +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "template" +) + +func main() { + out := bufio.NewWriter(os.Stdout) + fmt.Fprintln(out, header) + a := new(arg) + + // Generate each kind of test as a separate function to avoid + // hitting the 6g optimizer with one enormous function. + // If we name all the functions init we don't have to + // maintain a list of which ones to run. + do := func(t *template.Template) { + fmt.Fprintln(out, `func init() {`) + for ; next(); a.reset() { + run(t, a, out) + } + fmt.Fprintln(out, `}`) + } + + do(recv) + do(send) + do(recvOrder) + do(sendOrder) + do(nonblock) + + fmt.Fprintln(out, "//", a.nreset, "cases") + out.Flush() +} + +func run(t *template.Template, a interface{}, out io.Writer) { + if err := t.Execute(a, out); err != nil { + panic(err) + } +} + +type arg struct{ + def bool + nreset int +} + +func (a *arg) Maybe() bool { + return maybe() +} + +func (a *arg) MaybeDefault() bool { + if a.def { + return false + } + a.def = maybe() + return a.def +} + +func (a *arg) MustDefault() bool { + return !a.def +} + +func (a *arg) reset() { + a.def = false + a.nreset++ +} + +const header = `// GENERATED BY select5.go; DO NOT EDIT + +package main + +// channel is buffered so test is single-goroutine. +// we are not interested in the concurrency aspects +// of select, just testing that the right calls happen. +var c = make(chan int, 1) +var nilch chan int +var n = 1 +var x int +var i interface{} +var dummy = make(chan int) +var m = make(map[int]int) +var order = 0 + +func f(p *int) *int { + return p +} + +// check order of operations by ensuring that +// successive calls to checkorder have increasing o values. +func checkorder(o int) { + if o <= order { + println("invalid order", o, "after", order) + panic("order") + } + order = o +} + +func fc(c chan int, o int) chan int { + checkorder(o) + return c +} + +func fp(p *int, o int) *int { + checkorder(o) + return p +} + +func fn(n, o int) int { + checkorder(o) + return n +} + +func die(x int) { + println("have", x, "want", n) + panic("chan") +} + +func main() { + // everything happens in init funcs +} +` + +func parse(s string) *template.Template { + t := template.New(nil) + t.SetDelims("〈", "〉") + if err := t.Parse(s); err != nil { + panic(s) + } + return t +} + +var recv = parse(` + 〈# Send n, receive it one way or another into x, check that they match.〉 + c <- n + 〈.section Maybe〉 + x = <-c + 〈.or〉 + select { + 〈# Blocking or non-blocking, before the receive.〉 + 〈# The compiler implements two-case select where one is default with custom code,〉 + 〈# so test the default branch both before and after the send.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Receive from c. Different cases are direct, indirect, :=, interface, and map assignment.〉 + 〈.section Maybe〉 + case x = <-c: + 〈.or〉〈.section Maybe〉 + case *f(&x) = <-c: + 〈.or〉〈.section Maybe〉 + case y := <-c: + x = y + 〈.or〉〈.section Maybe〉 + case i = <-c: + x = i.(int) + 〈.or〉 + case m[13] = <-c: + x = m[13] + 〈.end〉〈.end〉〈.end〉〈.end〉 + 〈# Blocking or non-blocking again, after the receive.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Dummy send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case dummy <- 1: + panic("dummy send") + 〈.end〉 + 〈.section Maybe〉 + case <-dummy: + panic("dummy receive") + 〈.end〉 + 〈# Nil channel send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case nilch <- 1: + panic("nilch send") + 〈.end〉 + 〈.section Maybe〉 + case <-nilch: + panic("nilch recv") + 〈.end〉 + } + 〈.end〉 + if x != n { + die(x) + } + n++ +`) + +var recvOrder = parse(` + 〈# Send n, receive it one way or another into x, check that they match.〉 + 〈# Check order of operations along the way by calling functions that check〉 + 〈# that the argument sequence is strictly increasing.〉 + order = 0 + c <- n + 〈.section Maybe〉 + 〈# Outside of select, left-to-right rule applies.〉 + 〈# (Inside select, assignment waits until case is chosen,〉 + 〈# so right hand side happens before anything on left hand side.〉 + *fp(&x, 1) = <-fc(c, 2) + 〈.or〉〈.section Maybe〉 + m[fn(13, 1)] = <-fc(c, 2) + x = m[13] + 〈.or〉 + select { + 〈# Blocking or non-blocking, before the receive.〉 + 〈# The compiler implements two-case select where one is default with custom code,〉 + 〈# so test the default branch both before and after the send.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Receive from c. Different cases are direct, indirect, :=, interface, and map assignment.〉 + 〈.section Maybe〉 + case *fp(&x, 100) = <-fc(c, 1): + 〈.or〉〈.section Maybe〉 + case y := <-fc(c, 1): + x = y + 〈.or〉〈.section Maybe〉 + case i = <-fc(c, 1): + x = i.(int) + 〈.or〉 + case m[fn(13, 100)] = <-fc(c, 1): + x = m[13] + 〈.end〉〈.end〉〈.end〉 + 〈# Blocking or non-blocking again, after the receive.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Dummy send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case fc(dummy, 2) <- fn(1, 3): + panic("dummy send") + 〈.end〉 + 〈.section Maybe〉 + case <-fc(dummy, 4): + panic("dummy receive") + 〈.end〉 + 〈# Nil channel send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case fc(nilch, 5) <- fn(1, 6): + panic("nilch send") + 〈.end〉 + 〈.section Maybe〉 + case <-fc(nilch, 7): + panic("nilch recv") + 〈.end〉 + } + 〈.end〉〈.end〉 + if x != n { + die(x) + } + n++ +`) + +var send = parse(` + 〈# Send n one way or another, receive it into x, check that they match.〉 + 〈.section Maybe〉 + c <- n + 〈.or〉 + select { + 〈# Blocking or non-blocking, before the receive (same reason as in recv).〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Send c <- n. No real special cases here, because no values come back〉 + 〈# from the send operation.〉 + case c <- n: + 〈# Blocking or non-blocking.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Dummy send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case dummy <- 1: + panic("dummy send") + 〈.end〉 + 〈.section Maybe〉 + case <-dummy: + panic("dummy receive") + 〈.end〉 + 〈# Nil channel send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case nilch <- 1: + panic("nilch send") + 〈.end〉 + 〈.section Maybe〉 + case <-nilch: + panic("nilch recv") + 〈.end〉 + } + 〈.end〉 + x = <-c + if x != n { + die(x) + } + n++ +`) + +var sendOrder = parse(` + 〈# Send n one way or another, receive it into x, check that they match.〉 + 〈# Check order of operations along the way by calling functions that check〉 + 〈# that the argument sequence is strictly increasing.〉 + order = 0 + 〈.section Maybe〉 + fc(c, 1) <- fn(n, 2) + 〈.or〉 + select { + 〈# Blocking or non-blocking, before the receive (same reason as in recv).〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Send c <- n. No real special cases here, because no values come back〉 + 〈# from the send operation.〉 + case fc(c, 1) <- fn(n, 2): + 〈# Blocking or non-blocking.〉 + 〈.section MaybeDefault〉 + default: + panic("nonblock") + 〈.end〉 + 〈# Dummy send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case fc(dummy, 3) <- fn(1, 4): + panic("dummy send") + 〈.end〉 + 〈.section Maybe〉 + case <-fc(dummy, 5): + panic("dummy receive") + 〈.end〉 + 〈# Nil channel send, receive to keep compiler from optimizing select.〉 + 〈.section Maybe〉 + case fc(nilch, 6) <- fn(1, 7): + panic("nilch send") + 〈.end〉 + 〈.section Maybe〉 + case <-fc(nilch, 8): + panic("nilch recv") + 〈.end〉 + } + 〈.end〉 + x = <-c + if x != n { + die(x) + } + n++ +`) + +var nonblock = parse(` + x = n + 〈# Test various combinations of non-blocking operations.〉 + 〈# Receive assignments must not edit or even attempt to compute the address of the lhs.〉 + select { + 〈.section MaybeDefault〉 + default: + 〈.end〉 + 〈.section Maybe〉 + case dummy <- 1: + panic("dummy <- 1") + 〈.end〉 + 〈.section Maybe〉 + case nilch <- 1: + panic("nilch <- 1") + 〈.end〉 + 〈.section Maybe〉 + case <-dummy: + panic("<-dummy") + 〈.end〉 + 〈.section Maybe〉 + case x = <-dummy: + panic("<-dummy x") + 〈.end〉 + 〈.section Maybe〉 + case **(**int)(nil) = <-dummy: + panic("<-dummy (and didn't crash saving result!)") + 〈.end〉 + 〈.section Maybe〉 + case <-nilch: + panic("<-nilch") + 〈.end〉 + 〈.section Maybe〉 + case x = <-nilch: + panic("<-nilch x") + 〈.end〉 + 〈.section Maybe〉 + case **(**int)(nil) = <-nilch: + panic("<-nilch (and didn't crash saving result!)") + 〈.end〉 + 〈.section MustDefault〉 + default: + 〈.end〉 + } + if x != n { + die(x) + } + n++ +`) + +// Code for enumerating all possible paths through +// some logic. The logic should call choose(n) when +// it wants to choose between n possibilities. +// On successive runs through the logic, choose(n) +// will return 0, 1, ..., n-1. The helper maybe() is +// similar but returns true and then false. +// +// Given a function gen that generates an output +// using choose and maybe, code can generate all +// possible outputs using +// +// for next() { +// gen() +// } + +type choice struct { + i, n int +} + +var choices []choice +var cp int = -1 + +func maybe() bool { + return choose(2) == 0 +} + +func choose(n int) int { + if cp >= len(choices) { + // never asked this before: start with 0. + choices = append(choices, choice{0, n}) + cp = len(choices) + return 0 + } + // otherwise give recorded answer + if n != choices[cp].n { + panic("inconsistent choices") + } + i := choices[cp].i + cp++ + return i +} + +func next() bool { + if cp < 0 { + // start a new round + cp = 0 + return true + } + + // increment last choice sequence + cp = len(choices)-1 + for cp >= 0 && choices[cp].i == choices[cp].n-1 { + cp-- + } + if cp < 0 { + choices = choices[:0] + return false + } + choices[cp].i++ + choices = choices[:cp+1] + cp = 0 + return true +} + diff --git a/test/chan/sendstmt.go b/test/chan/sendstmt.go new file mode 100644 index 000000000..ee6f765cf --- /dev/null +++ b/test/chan/sendstmt.go @@ -0,0 +1,37 @@ +// $G $D/$F.go && $L $F.$A && ./$A.out + +// Copyright 2011 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. + +// Test various parsing cases that are a little +// different now that send is a statement, not a expression. + +package main + +func main() { + chanchan() + sendprec() +} + +func chanchan() { + cc := make(chan chan int, 1) + c := make(chan int, 1) + cc <- c + select { + case <-cc <- 2: + default: + panic("nonblock") + } + if <-c != 2 { + panic("bad receive") + } +} + +func sendprec() { + c := make(chan bool, 1) + c <- false || true // not a syntax error: same as c <- (false || true) + if !<-c { + panic("sent false") + } +} diff --git a/test/closedchan.go b/test/closedchan.go index c7c759be3..46d9d0f5d 100644 --- a/test/closedchan.go +++ b/test/closedchan.go @@ -21,14 +21,21 @@ type Chan interface { Impl() string } -// direct channel operations +// direct channel operations when possible type XChan chan int + func (c XChan) Send(x int) { c <- x } func (c XChan) Nbsend(x int) bool { - return c <- x + select { + case c <- x: + return true + default: + return false + } + panic("nbsend") } func (c XChan) Recv() int { @@ -36,8 +43,13 @@ func (c XChan) Recv() int { } func (c XChan) Nbrecv() (int, bool) { - x, ok := <-c - return x, ok + select { + case x := <-c: + return x, true + default: + return 0, false + } + panic("nbrecv") } func (c XChan) Close() { @@ -54,6 +66,7 @@ func (c XChan) Impl() string { // indirect operations via select type SChan chan int + func (c SChan) Send(x int) { select { case c <- x: @@ -62,10 +75,10 @@ func (c SChan) Send(x int) { func (c SChan) Nbsend(x int) bool { select { - case c <- x: - return true default: return false + case c <- x: + return true } panic("nbsend") } @@ -80,10 +93,10 @@ func (c SChan) Recv() int { func (c SChan) Nbrecv() (int, bool) { select { - case x := <-c: - return x, true default: return 0, false + case x := <-c: + return x, true } panic("nbrecv") } @@ -100,6 +113,71 @@ func (c SChan) Impl() string { return "(select)" } +// indirect operations via larger selects +var dummy = make(chan bool) + +type SSChan chan int + +func (c SSChan) Send(x int) { + select { + case c <- x: + case <-dummy: + } +} + +func (c SSChan) Nbsend(x int) bool { + select { + default: + return false + case <-dummy: + case c <- x: + return true + } + panic("nbsend") +} + +func (c SSChan) Recv() int { + select { + case <-dummy: + case x := <-c: + return x + } + panic("recv") +} + +func (c SSChan) Nbrecv() (int, bool) { + select { + case <-dummy: + default: + return 0, false + case x := <-c: + return x, true + } + panic("nbrecv") +} + +func (c SSChan) Close() { + close(c) +} + +func (c SSChan) Closed() bool { + return closed(c) +} + +func (c SSChan) Impl() string { + return "(select)" +} + + +func shouldPanic(f func()) { + defer func() { + if recover() == nil { + panic("did not panic") + } + }() + f() +} + func test1(c Chan) { // not closed until the close signal (a zero value) has been received. if c.Closed() { @@ -128,18 +206,15 @@ func test1(c Chan) { } // send should work with ,ok too: sent a value without blocking, so ok == true. - ok := c.Nbsend(1) - if !ok { - println("test1: send on closed got not ok", c.Impl()) - } + shouldPanic(func() { c.Nbsend(1) }) - // but the value should have been discarded. + // the value should have been discarded. if x := c.Recv(); x != 0 { println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) } // similarly Send. - c.Send(2) + shouldPanic(func() { c.Send(2) }) if x := c.Recv(); x != 0 { println("test1: recv on closed got non-zero after send on closed:", x, c.Impl()) } @@ -189,9 +264,12 @@ func closedasync() chan int { func main() { test1(XChan(closedsync())) test1(SChan(closedsync())) + test1(SSChan(closedsync())) testasync1(XChan(closedasync())) testasync1(SChan(closedasync())) + testasync1(SSChan(closedasync())) testasync2(XChan(closedasync())) testasync2(SChan(closedasync())) + testasync2(SSChan(closedasync())) } diff --git a/test/cmp6.go b/test/cmp6.go index 981a85953..4c0601187 100644 --- a/test/cmp6.go +++ b/test/cmp6.go @@ -11,6 +11,10 @@ func use(bool) {} type T1 *int type T2 *int +type T3 struct {} + +var t3 T3 + func main() { // Arguments to comparison must be // assignable one to the other (or vice versa) @@ -39,4 +43,7 @@ func main() { use(p2 == p2) use(p3 == p1) use(p3 == p2) + + // Comparison of structs should have a good message + use(t3 == t3) // ERROR "struct" } diff --git a/test/cmplx.go b/test/cmplx.go index fad96c605..d5a77d684 100644 --- a/test/cmplx.go +++ b/test/cmplx.go @@ -7,26 +7,19 @@ package main var ( - f float f32 float32 f64 float64 - c complex - c64 complex64 + c64 complex64 c128 complex128 ) - + func main() { // ok - c = cmplx(f, f) - c64 = cmplx(f32, f32) - c128 = cmplx(f64, f64) + c64 = complex(f32, f32) + c128 = complex(f64, f64) - _ = complex(0) // ok - _ = cmplx(f, f32) // ERROR "cmplx" - _ = cmplx(f, f64) // ERROR "cmplx" - _ = cmplx(f32, f) // ERROR "cmplx" - _ = cmplx(f32, f64) // ERROR "cmplx" - _ = cmplx(f64, f) // ERROR "cmplx" - _ = cmplx(f64, f32) // ERROR "cmplx" + _ = complex128(0) // ok + _ = complex(f32, f64) // ERROR "complex" + _ = complex(f64, f32) // ERROR "complex" } diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c index b3c6055ed..b340f04d8 100644 --- a/test/cmplxdivide.c +++ b/test/cmplxdivide.c @@ -72,7 +72,7 @@ main(void) if(iscnan(n) && d == 0) q = (NAN+NAN*I) / zero; - printf("\tTest{cmplx(%s, %s), cmplx(%s, %s), cmplx(%s, %s)},\n", + printf("\tTest{complex(%s, %s), complex(%s, %s), complex(%s, %s)},\n", fmt(creal(n)), fmt(cimag(n)), fmt(creal(d)), fmt(cimag(d)), fmt(creal(q)), fmt(cimag(q))); diff --git a/test/cmplxdivide1.go b/test/cmplxdivide1.go index 96ea704a3..6a1dee9fe 100644 --- a/test/cmplxdivide1.go +++ b/test/cmplxdivide1.go @@ -1,2407 +1,2406 @@ // # generated by cmplxdivide.c package main - var tests = []Test{ - Test{cmplx(0, 0), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(0, 1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(0, -1), cmplx(negzero, 0)}, - Test{cmplx(0, 0), cmplx(0, 2), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 0), cmplx(1, 0), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(1, 1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(1, -1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(1, 2), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 0), cmplx(-1, 0), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-1, 1), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-1, -1), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-1, 2), cmplx(0, negzero)}, - Test{cmplx(0, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(0, 0), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(2, 0), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(2, 1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(2, -1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(2, 2), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, 0), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(0, 0), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, nan), cmplx(0, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(0, 0), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(0, 0), cmplx(nan, inf)}, - Test{cmplx(0, 1), cmplx(0, 1), cmplx(1, 0)}, - Test{cmplx(0, 1), cmplx(0, -1), cmplx(-1, 0)}, - Test{cmplx(0, 1), cmplx(0, 2), cmplx(0.5, 0)}, - Test{cmplx(0, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(1, 0), cmplx(0, 1)}, - Test{cmplx(0, 1), cmplx(1, 1), cmplx(0.5, 0.5)}, - Test{cmplx(0, 1), cmplx(1, -1), cmplx(-0.5, 0.5)}, - Test{cmplx(0, 1), cmplx(1, 2), cmplx(0.4, 0.2)}, - Test{cmplx(0, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(-1, 0), cmplx(negzero, -1)}, - Test{cmplx(0, 1), cmplx(-1, 1), cmplx(0.5, -0.5)}, - Test{cmplx(0, 1), cmplx(-1, -1), cmplx(-0.5, -0.5)}, - Test{cmplx(0, 1), cmplx(-1, 2), cmplx(0.4, -0.2)}, - Test{cmplx(0, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(0, 1), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(0, 1), cmplx(2, 0), cmplx(0, 0.5)}, - Test{cmplx(0, 1), cmplx(2, 1), cmplx(0.2, 0.4)}, - Test{cmplx(0, 1), cmplx(2, -1), cmplx(-0.2, 0.4)}, - Test{cmplx(0, 1), cmplx(2, 2), cmplx(0.25, 0.25)}, - Test{cmplx(0, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, 1), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(0, 1), cmplx(inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 1), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, nan), cmplx(0, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(0, 1), cmplx(-inf, -inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(0, 0), cmplx(nan, -inf)}, - Test{cmplx(0, -1), cmplx(0, 1), cmplx(-1, negzero)}, - Test{cmplx(0, -1), cmplx(0, -1), cmplx(1, negzero)}, - Test{cmplx(0, -1), cmplx(0, 2), cmplx(-0.5, negzero)}, - Test{cmplx(0, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(0, inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(0, -inf), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(1, 0), cmplx(0, -1)}, - Test{cmplx(0, -1), cmplx(1, 1), cmplx(-0.5, -0.5)}, - Test{cmplx(0, -1), cmplx(1, -1), cmplx(0.5, -0.5)}, - Test{cmplx(0, -1), cmplx(1, 2), cmplx(-0.4, -0.2)}, - Test{cmplx(0, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(1, inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(1, -inf), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(-1, 0), cmplx(negzero, 1)}, - Test{cmplx(0, -1), cmplx(-1, 1), cmplx(-0.5, 0.5)}, - Test{cmplx(0, -1), cmplx(-1, -1), cmplx(0.5, 0.5)}, - Test{cmplx(0, -1), cmplx(-1, 2), cmplx(-0.4, 0.2)}, - Test{cmplx(0, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(-1, inf), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-1, -inf), cmplx(0, 0)}, - Test{cmplx(0, -1), cmplx(2, 0), cmplx(0, -0.5)}, - Test{cmplx(0, -1), cmplx(2, 1), cmplx(-0.2, -0.4)}, - Test{cmplx(0, -1), cmplx(2, -1), cmplx(0.2, -0.4)}, - Test{cmplx(0, -1), cmplx(2, 2), cmplx(-0.25, -0.25)}, - Test{cmplx(0, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(2, inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(2, -inf), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, -1), cmplx(nan, inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(0, -1), cmplx(inf, 0), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(inf, 1), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(inf, -1), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(inf, 2), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(inf, nan), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(inf, inf), cmplx(negzero, negzero)}, - Test{cmplx(0, -1), cmplx(inf, -inf), cmplx(0, negzero)}, - Test{cmplx(0, -1), cmplx(-inf, 0), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, 1), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, -1), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, 2), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, nan), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, inf), cmplx(negzero, 0)}, - Test{cmplx(0, -1), cmplx(-inf, -inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(0, 0), cmplx(nan, inf)}, - Test{cmplx(0, 2), cmplx(0, 1), cmplx(2, 0)}, - Test{cmplx(0, 2), cmplx(0, -1), cmplx(-2, 0)}, - Test{cmplx(0, 2), cmplx(0, 2), cmplx(1, 0)}, - Test{cmplx(0, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 2), cmplx(1, 0), cmplx(0, 2)}, - Test{cmplx(0, 2), cmplx(1, 1), cmplx(1, 1)}, - Test{cmplx(0, 2), cmplx(1, -1), cmplx(-1, 1)}, - Test{cmplx(0, 2), cmplx(1, 2), cmplx(0.8, 0.4)}, - Test{cmplx(0, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 2), cmplx(-1, 0), cmplx(negzero, -2)}, - Test{cmplx(0, 2), cmplx(-1, 1), cmplx(1, -1)}, - Test{cmplx(0, 2), cmplx(-1, -1), cmplx(-1, -1)}, - Test{cmplx(0, 2), cmplx(-1, 2), cmplx(0.8, -0.4)}, - Test{cmplx(0, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(0, 2), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(0, 2), cmplx(2, 0), cmplx(0, 1)}, - Test{cmplx(0, 2), cmplx(2, 1), cmplx(0.4, 0.8)}, - Test{cmplx(0, 2), cmplx(2, -1), cmplx(-0.4, 0.8)}, - Test{cmplx(0, 2), cmplx(2, 2), cmplx(0.5, 0.5)}, - Test{cmplx(0, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, 2), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 2), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(0, 2), cmplx(inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(0, 2), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, nan), cmplx(0, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(0, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)}, - Test{cmplx(0, nan), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(0, 0), cmplx(nan, inf)}, - Test{cmplx(0, inf), cmplx(0, 1), cmplx(inf, nan)}, - Test{cmplx(0, inf), cmplx(0, -1), cmplx(-inf, nan)}, - Test{cmplx(0, inf), cmplx(0, 2), cmplx(inf, nan)}, - Test{cmplx(0, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(1, 0), cmplx(nan, inf)}, - Test{cmplx(0, inf), cmplx(1, 1), cmplx(inf, inf)}, - Test{cmplx(0, inf), cmplx(1, -1), cmplx(-inf, inf)}, - Test{cmplx(0, inf), cmplx(1, 2), cmplx(inf, inf)}, - Test{cmplx(0, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-1, 0), cmplx(nan, -inf)}, - Test{cmplx(0, inf), cmplx(-1, 1), cmplx(inf, -inf)}, - Test{cmplx(0, inf), cmplx(-1, -1), cmplx(-inf, -inf)}, - Test{cmplx(0, inf), cmplx(-1, 2), cmplx(inf, -inf)}, - Test{cmplx(0, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(2, 0), cmplx(nan, inf)}, - Test{cmplx(0, inf), cmplx(2, 1), cmplx(inf, inf)}, - Test{cmplx(0, inf), cmplx(2, -1), cmplx(-inf, inf)}, - Test{cmplx(0, inf), cmplx(2, 2), cmplx(inf, inf)}, - Test{cmplx(0, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(0, 0), cmplx(nan, -inf)}, - Test{cmplx(0, -inf), cmplx(0, 1), cmplx(-inf, nan)}, - Test{cmplx(0, -inf), cmplx(0, -1), cmplx(inf, nan)}, - Test{cmplx(0, -inf), cmplx(0, 2), cmplx(-inf, nan)}, - Test{cmplx(0, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(1, 0), cmplx(nan, -inf)}, - Test{cmplx(0, -inf), cmplx(1, 1), cmplx(-inf, -inf)}, - Test{cmplx(0, -inf), cmplx(1, -1), cmplx(inf, -inf)}, - Test{cmplx(0, -inf), cmplx(1, 2), cmplx(-inf, -inf)}, - Test{cmplx(0, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-1, 0), cmplx(nan, inf)}, - Test{cmplx(0, -inf), cmplx(-1, 1), cmplx(-inf, inf)}, - Test{cmplx(0, -inf), cmplx(-1, -1), cmplx(inf, inf)}, - Test{cmplx(0, -inf), cmplx(-1, 2), cmplx(-inf, inf)}, - Test{cmplx(0, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(2, 0), cmplx(nan, -inf)}, - Test{cmplx(0, -inf), cmplx(2, 1), cmplx(-inf, -inf)}, - Test{cmplx(0, -inf), cmplx(2, -1), cmplx(inf, -inf)}, - Test{cmplx(0, -inf), cmplx(2, 2), cmplx(-inf, -inf)}, - Test{cmplx(0, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(0, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(0, 0), cmplx(inf, nan)}, - Test{cmplx(1, 0), cmplx(0, 1), cmplx(0, -1)}, - Test{cmplx(1, 0), cmplx(0, -1), cmplx(negzero, 1)}, - Test{cmplx(1, 0), cmplx(0, 2), cmplx(0, -0.5)}, - Test{cmplx(1, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 0), cmplx(1, 0), cmplx(1, 0)}, - Test{cmplx(1, 0), cmplx(1, 1), cmplx(0.5, -0.5)}, - Test{cmplx(1, 0), cmplx(1, -1), cmplx(0.5, 0.5)}, - Test{cmplx(1, 0), cmplx(1, 2), cmplx(0.2, -0.4)}, - Test{cmplx(1, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 0), cmplx(-1, 0), cmplx(-1, negzero)}, - Test{cmplx(1, 0), cmplx(-1, 1), cmplx(-0.5, -0.5)}, - Test{cmplx(1, 0), cmplx(-1, -1), cmplx(-0.5, 0.5)}, - Test{cmplx(1, 0), cmplx(-1, 2), cmplx(-0.2, -0.4)}, - Test{cmplx(1, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 0), cmplx(2, 0), cmplx(0.5, 0)}, - Test{cmplx(1, 0), cmplx(2, 1), cmplx(0.4, -0.2)}, - Test{cmplx(1, 0), cmplx(2, -1), cmplx(0.4, 0.2)}, - Test{cmplx(1, 0), cmplx(2, 2), cmplx(0.25, -0.25)}, - Test{cmplx(1, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, 0), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(inf, inf), cmplx(0, negzero)}, - Test{cmplx(1, 0), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(1, 0), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, 0), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(1, 1), cmplx(0, 1), cmplx(1, -1)}, - Test{cmplx(1, 1), cmplx(0, -1), cmplx(-1, 1)}, - Test{cmplx(1, 1), cmplx(0, 2), cmplx(0.5, -0.5)}, - Test{cmplx(1, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(1, 0), cmplx(1, 1)}, - Test{cmplx(1, 1), cmplx(1, 1), cmplx(1, 0)}, - Test{cmplx(1, 1), cmplx(1, -1), cmplx(0, 1)}, - Test{cmplx(1, 1), cmplx(1, 2), cmplx(0.6, -0.2)}, - Test{cmplx(1, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(-1, 0), cmplx(-1, -1)}, - Test{cmplx(1, 1), cmplx(-1, 1), cmplx(negzero, -1)}, - Test{cmplx(1, 1), cmplx(-1, -1), cmplx(-1, negzero)}, - Test{cmplx(1, 1), cmplx(-1, 2), cmplx(0.2, -0.6)}, - Test{cmplx(1, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(2, 0), cmplx(0.5, 0.5)}, - Test{cmplx(1, 1), cmplx(2, 1), cmplx(0.6, 0.2)}, - Test{cmplx(1, 1), cmplx(2, -1), cmplx(0.2, 0.6)}, - Test{cmplx(1, 1), cmplx(2, 2), cmplx(0.5, 0)}, - Test{cmplx(1, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, 1), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 1), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(1, 1), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(1, 1), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(1, -1), cmplx(0, 1), cmplx(-1, -1)}, - Test{cmplx(1, -1), cmplx(0, -1), cmplx(1, 1)}, - Test{cmplx(1, -1), cmplx(0, 2), cmplx(-0.5, -0.5)}, - Test{cmplx(1, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(0, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, -1), cmplx(0, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(1, 0), cmplx(1, -1)}, - Test{cmplx(1, -1), cmplx(1, 1), cmplx(0, -1)}, - Test{cmplx(1, -1), cmplx(1, -1), cmplx(1, 0)}, - Test{cmplx(1, -1), cmplx(1, 2), cmplx(-0.2, -0.6)}, - Test{cmplx(1, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(1, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, -1), cmplx(1, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(-1, 0), cmplx(-1, 1)}, - Test{cmplx(1, -1), cmplx(-1, 1), cmplx(-1, negzero)}, - Test{cmplx(1, -1), cmplx(-1, -1), cmplx(negzero, 1)}, - Test{cmplx(1, -1), cmplx(-1, 2), cmplx(-0.6, -0.2)}, - Test{cmplx(1, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(-1, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, -1), cmplx(-1, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(2, 0), cmplx(0.5, -0.5)}, - Test{cmplx(1, -1), cmplx(2, 1), cmplx(0.2, -0.6)}, - Test{cmplx(1, -1), cmplx(2, -1), cmplx(0.6, -0.2)}, - Test{cmplx(1, -1), cmplx(2, 2), cmplx(0, -0.5)}, - Test{cmplx(1, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(2, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, -1), cmplx(2, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, -1), cmplx(nan, inf), cmplx(negzero, negzero)}, - Test{cmplx(1, -1), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(inf, 0), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, 1), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, -1), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, 2), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, nan), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, inf), cmplx(0, negzero)}, - Test{cmplx(1, -1), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(1, -1), cmplx(-inf, 0), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, 1), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, -1), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, 2), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, nan), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, inf), cmplx(negzero, 0)}, - Test{cmplx(1, -1), cmplx(-inf, -inf), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(1, 2), cmplx(0, 1), cmplx(2, -1)}, - Test{cmplx(1, 2), cmplx(0, -1), cmplx(-2, 1)}, - Test{cmplx(1, 2), cmplx(0, 2), cmplx(1, -0.5)}, - Test{cmplx(1, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(1, 0), cmplx(1, 2)}, - Test{cmplx(1, 2), cmplx(1, 1), cmplx(1.5, 0.5)}, - Test{cmplx(1, 2), cmplx(1, -1), cmplx(-0.5, 1.5)}, - Test{cmplx(1, 2), cmplx(1, 2), cmplx(1, 0)}, - Test{cmplx(1, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(-1, 0), cmplx(-1, -2)}, - Test{cmplx(1, 2), cmplx(-1, 1), cmplx(0.5, -1.5)}, - Test{cmplx(1, 2), cmplx(-1, -1), cmplx(-1.5, -0.5)}, - Test{cmplx(1, 2), cmplx(-1, 2), cmplx(0.6, -0.8)}, - Test{cmplx(1, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(2, 0), cmplx(0.5, 1)}, - Test{cmplx(1, 2), cmplx(2, 1), cmplx(0.8, 0.6)}, - Test{cmplx(1, 2), cmplx(2, -1), cmplx(0, 1)}, - Test{cmplx(1, 2), cmplx(2, 2), cmplx(0.75, 0.25)}, - Test{cmplx(1, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, 2), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(1, 2), cmplx(inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(1, 2), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(1, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)}, - Test{cmplx(1, nan), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(1, inf), cmplx(0, 1), cmplx(inf, nan)}, - Test{cmplx(1, inf), cmplx(0, -1), cmplx(-inf, nan)}, - Test{cmplx(1, inf), cmplx(0, 2), cmplx(inf, nan)}, - Test{cmplx(1, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(1, 0), cmplx(nan, inf)}, - Test{cmplx(1, inf), cmplx(1, 1), cmplx(inf, inf)}, - Test{cmplx(1, inf), cmplx(1, -1), cmplx(-inf, inf)}, - Test{cmplx(1, inf), cmplx(1, 2), cmplx(inf, inf)}, - Test{cmplx(1, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-1, 0), cmplx(nan, -inf)}, - Test{cmplx(1, inf), cmplx(-1, 1), cmplx(inf, -inf)}, - Test{cmplx(1, inf), cmplx(-1, -1), cmplx(-inf, -inf)}, - Test{cmplx(1, inf), cmplx(-1, 2), cmplx(inf, -inf)}, - Test{cmplx(1, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(2, 0), cmplx(nan, inf)}, - Test{cmplx(1, inf), cmplx(2, 1), cmplx(inf, inf)}, - Test{cmplx(1, inf), cmplx(2, -1), cmplx(-inf, inf)}, - Test{cmplx(1, inf), cmplx(2, 2), cmplx(inf, inf)}, - Test{cmplx(1, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(1, -inf), cmplx(0, 1), cmplx(-inf, nan)}, - Test{cmplx(1, -inf), cmplx(0, -1), cmplx(inf, nan)}, - Test{cmplx(1, -inf), cmplx(0, 2), cmplx(-inf, nan)}, - Test{cmplx(1, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(1, 0), cmplx(nan, -inf)}, - Test{cmplx(1, -inf), cmplx(1, 1), cmplx(-inf, -inf)}, - Test{cmplx(1, -inf), cmplx(1, -1), cmplx(inf, -inf)}, - Test{cmplx(1, -inf), cmplx(1, 2), cmplx(-inf, -inf)}, - Test{cmplx(1, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-1, 0), cmplx(nan, inf)}, - Test{cmplx(1, -inf), cmplx(-1, 1), cmplx(-inf, inf)}, - Test{cmplx(1, -inf), cmplx(-1, -1), cmplx(inf, inf)}, - Test{cmplx(1, -inf), cmplx(-1, 2), cmplx(-inf, inf)}, - Test{cmplx(1, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(2, 0), cmplx(nan, -inf)}, - Test{cmplx(1, -inf), cmplx(2, 1), cmplx(-inf, -inf)}, - Test{cmplx(1, -inf), cmplx(2, -1), cmplx(inf, -inf)}, - Test{cmplx(1, -inf), cmplx(2, 2), cmplx(-inf, -inf)}, - Test{cmplx(1, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(1, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(0, 0), cmplx(-inf, nan)}, - Test{cmplx(-1, 0), cmplx(0, 1), cmplx(0, 1)}, - Test{cmplx(-1, 0), cmplx(0, -1), cmplx(negzero, -1)}, - Test{cmplx(-1, 0), cmplx(0, 2), cmplx(0, 0.5)}, - Test{cmplx(-1, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(0, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(1, 0), cmplx(-1, 0)}, - Test{cmplx(-1, 0), cmplx(1, 1), cmplx(-0.5, 0.5)}, - Test{cmplx(-1, 0), cmplx(1, -1), cmplx(-0.5, -0.5)}, - Test{cmplx(-1, 0), cmplx(1, 2), cmplx(-0.2, 0.4)}, - Test{cmplx(-1, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(-1, 0), cmplx(1, negzero)}, - Test{cmplx(-1, 0), cmplx(-1, 1), cmplx(0.5, 0.5)}, - Test{cmplx(-1, 0), cmplx(-1, -1), cmplx(0.5, -0.5)}, - Test{cmplx(-1, 0), cmplx(-1, 2), cmplx(0.2, 0.4)}, - Test{cmplx(-1, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(-1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(2, 0), cmplx(-0.5, 0)}, - Test{cmplx(-1, 0), cmplx(2, 1), cmplx(-0.4, 0.2)}, - Test{cmplx(-1, 0), cmplx(2, -1), cmplx(-0.4, -0.2)}, - Test{cmplx(-1, 0), cmplx(2, 2), cmplx(-0.25, 0.25)}, - Test{cmplx(-1, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(2, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 0), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(nan, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(inf, 0), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, 1), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, -1), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, 2), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, nan), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, 0), cmplx(inf, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 0), cmplx(-inf, 0), cmplx(0, negzero)}, - Test{cmplx(-1, 0), cmplx(-inf, 1), cmplx(0, negzero)}, - Test{cmplx(-1, 0), cmplx(-inf, -1), cmplx(0, negzero)}, - Test{cmplx(-1, 0), cmplx(-inf, 2), cmplx(0, negzero)}, - Test{cmplx(-1, 0), cmplx(-inf, nan), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(-inf, inf), cmplx(0, 0)}, - Test{cmplx(-1, 0), cmplx(-inf, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-1, 1), cmplx(0, 1), cmplx(1, 1)}, - Test{cmplx(-1, 1), cmplx(0, -1), cmplx(-1, -1)}, - Test{cmplx(-1, 1), cmplx(0, 2), cmplx(0.5, 0.5)}, - Test{cmplx(-1, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(0, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 1), cmplx(1, 0), cmplx(-1, 1)}, - Test{cmplx(-1, 1), cmplx(1, 1), cmplx(0, 1)}, - Test{cmplx(-1, 1), cmplx(1, -1), cmplx(-1, 0)}, - Test{cmplx(-1, 1), cmplx(1, 2), cmplx(0.2, 0.6)}, - Test{cmplx(-1, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 1), cmplx(-1, 0), cmplx(1, -1)}, - Test{cmplx(-1, 1), cmplx(-1, 1), cmplx(1, negzero)}, - Test{cmplx(-1, 1), cmplx(-1, -1), cmplx(negzero, -1)}, - Test{cmplx(-1, 1), cmplx(-1, 2), cmplx(0.6, 0.2)}, - Test{cmplx(-1, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(-1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 1), cmplx(2, 0), cmplx(-0.5, 0.5)}, - Test{cmplx(-1, 1), cmplx(2, 1), cmplx(-0.2, 0.6)}, - Test{cmplx(-1, 1), cmplx(2, -1), cmplx(-0.6, 0.2)}, - Test{cmplx(-1, 1), cmplx(2, 2), cmplx(0, 0.5)}, - Test{cmplx(-1, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(2, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 1), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(nan, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 1), cmplx(inf, 0), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(inf, 1), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(inf, -1), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(inf, 2), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(inf, nan), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(-1, 1), cmplx(-inf, 0), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(-inf, 1), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(-inf, -1), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(-inf, 2), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(-inf, nan), cmplx(0, negzero)}, - Test{cmplx(-1, 1), cmplx(-inf, inf), cmplx(0, 0)}, - Test{cmplx(-1, 1), cmplx(-inf, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(0, 0), cmplx(-inf, -inf)}, - Test{cmplx(-1, -1), cmplx(0, 1), cmplx(-1, 1)}, - Test{cmplx(-1, -1), cmplx(0, -1), cmplx(1, -1)}, - Test{cmplx(-1, -1), cmplx(0, 2), cmplx(-0.5, 0.5)}, - Test{cmplx(-1, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(0, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(0, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(1, 0), cmplx(-1, -1)}, - Test{cmplx(-1, -1), cmplx(1, 1), cmplx(-1, 0)}, - Test{cmplx(-1, -1), cmplx(1, -1), cmplx(0, -1)}, - Test{cmplx(-1, -1), cmplx(1, 2), cmplx(-0.6, 0.2)}, - Test{cmplx(-1, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(1, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(1, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(-1, 0), cmplx(1, 1)}, - Test{cmplx(-1, -1), cmplx(-1, 1), cmplx(negzero, 1)}, - Test{cmplx(-1, -1), cmplx(-1, -1), cmplx(1, negzero)}, - Test{cmplx(-1, -1), cmplx(-1, 2), cmplx(-0.2, 0.6)}, - Test{cmplx(-1, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(-1, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(-1, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(2, 0), cmplx(-0.5, -0.5)}, - Test{cmplx(-1, -1), cmplx(2, 1), cmplx(-0.6, -0.2)}, - Test{cmplx(-1, -1), cmplx(2, -1), cmplx(-0.2, -0.6)}, - Test{cmplx(-1, -1), cmplx(2, 2), cmplx(-0.5, 0)}, - Test{cmplx(-1, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(2, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(2, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -1), cmplx(nan, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(nan, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(-1, -1), cmplx(inf, inf), cmplx(negzero, 0)}, - Test{cmplx(-1, -1), cmplx(inf, -inf), cmplx(0, negzero)}, - Test{cmplx(-1, -1), cmplx(-inf, 0), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, 1), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, -1), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, 2), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, nan), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, inf), cmplx(0, 0)}, - Test{cmplx(-1, -1), cmplx(-inf, -inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-1, 2), cmplx(0, 1), cmplx(2, 1)}, - Test{cmplx(-1, 2), cmplx(0, -1), cmplx(-2, -1)}, - Test{cmplx(-1, 2), cmplx(0, 2), cmplx(1, 0.5)}, - Test{cmplx(-1, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(0, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(0, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 2), cmplx(1, 0), cmplx(-1, 2)}, - Test{cmplx(-1, 2), cmplx(1, 1), cmplx(0.5, 1.5)}, - Test{cmplx(-1, 2), cmplx(1, -1), cmplx(-1.5, 0.5)}, - Test{cmplx(-1, 2), cmplx(1, 2), cmplx(0.6, 0.8)}, - Test{cmplx(-1, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 2), cmplx(-1, 0), cmplx(1, -2)}, - Test{cmplx(-1, 2), cmplx(-1, 1), cmplx(1.5, -0.5)}, - Test{cmplx(-1, 2), cmplx(-1, -1), cmplx(-0.5, -1.5)}, - Test{cmplx(-1, 2), cmplx(-1, 2), cmplx(1, 0)}, - Test{cmplx(-1, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(-1, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(-1, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 2), cmplx(2, 0), cmplx(-0.5, 1)}, - Test{cmplx(-1, 2), cmplx(2, 1), cmplx(0, 1)}, - Test{cmplx(-1, 2), cmplx(2, -1), cmplx(-0.8, 0.6)}, - Test{cmplx(-1, 2), cmplx(2, 2), cmplx(0.25, 0.75)}, - Test{cmplx(-1, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(2, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(2, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, 2), cmplx(nan, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(nan, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, 2), cmplx(inf, 0), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(inf, 1), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(inf, -1), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(inf, 2), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(inf, nan), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(-1, 2), cmplx(inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(-1, 2), cmplx(-inf, 0), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, 1), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, -1), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, 2), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, nan), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(-1, 2), cmplx(-inf, -inf), cmplx(negzero, negzero)}, - Test{cmplx(-1, nan), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-1, inf), cmplx(0, 1), cmplx(inf, nan)}, - Test{cmplx(-1, inf), cmplx(0, -1), cmplx(-inf, nan)}, - Test{cmplx(-1, inf), cmplx(0, 2), cmplx(inf, nan)}, - Test{cmplx(-1, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(1, 0), cmplx(nan, inf)}, - Test{cmplx(-1, inf), cmplx(1, 1), cmplx(inf, inf)}, - Test{cmplx(-1, inf), cmplx(1, -1), cmplx(-inf, inf)}, - Test{cmplx(-1, inf), cmplx(1, 2), cmplx(inf, inf)}, - Test{cmplx(-1, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-1, 0), cmplx(nan, -inf)}, - Test{cmplx(-1, inf), cmplx(-1, 1), cmplx(inf, -inf)}, - Test{cmplx(-1, inf), cmplx(-1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-1, inf), cmplx(-1, 2), cmplx(inf, -inf)}, - Test{cmplx(-1, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(2, 0), cmplx(nan, inf)}, - Test{cmplx(-1, inf), cmplx(2, 1), cmplx(inf, inf)}, - Test{cmplx(-1, inf), cmplx(2, -1), cmplx(-inf, inf)}, - Test{cmplx(-1, inf), cmplx(2, 2), cmplx(inf, inf)}, - Test{cmplx(-1, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(0, 0), cmplx(-inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(0, 1), cmplx(-inf, nan)}, - Test{cmplx(-1, -inf), cmplx(0, -1), cmplx(inf, nan)}, - Test{cmplx(-1, -inf), cmplx(0, 2), cmplx(-inf, nan)}, - Test{cmplx(-1, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(1, 0), cmplx(nan, -inf)}, - Test{cmplx(-1, -inf), cmplx(1, 1), cmplx(-inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(1, -1), cmplx(inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(1, 2), cmplx(-inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-1, 0), cmplx(nan, inf)}, - Test{cmplx(-1, -inf), cmplx(-1, 1), cmplx(-inf, inf)}, - Test{cmplx(-1, -inf), cmplx(-1, -1), cmplx(inf, inf)}, - Test{cmplx(-1, -inf), cmplx(-1, 2), cmplx(-inf, inf)}, - Test{cmplx(-1, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(2, 0), cmplx(nan, -inf)}, - Test{cmplx(-1, -inf), cmplx(2, 1), cmplx(-inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(2, -1), cmplx(inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(2, 2), cmplx(-inf, -inf)}, - Test{cmplx(-1, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-1, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(0, 0), cmplx(inf, nan)}, - Test{cmplx(2, 0), cmplx(0, 1), cmplx(0, -2)}, - Test{cmplx(2, 0), cmplx(0, -1), cmplx(negzero, 2)}, - Test{cmplx(2, 0), cmplx(0, 2), cmplx(0, -1)}, - Test{cmplx(2, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 0), cmplx(1, 0), cmplx(2, 0)}, - Test{cmplx(2, 0), cmplx(1, 1), cmplx(1, -1)}, - Test{cmplx(2, 0), cmplx(1, -1), cmplx(1, 1)}, - Test{cmplx(2, 0), cmplx(1, 2), cmplx(0.4, -0.8)}, - Test{cmplx(2, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 0), cmplx(-1, 0), cmplx(-2, negzero)}, - Test{cmplx(2, 0), cmplx(-1, 1), cmplx(-1, -1)}, - Test{cmplx(2, 0), cmplx(-1, -1), cmplx(-1, 1)}, - Test{cmplx(2, 0), cmplx(-1, 2), cmplx(-0.4, -0.8)}, - Test{cmplx(2, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 0), cmplx(2, 0), cmplx(1, 0)}, - Test{cmplx(2, 0), cmplx(2, 1), cmplx(0.8, -0.4)}, - Test{cmplx(2, 0), cmplx(2, -1), cmplx(0.8, 0.4)}, - Test{cmplx(2, 0), cmplx(2, 2), cmplx(0.5, -0.5)}, - Test{cmplx(2, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, 0), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(inf, inf), cmplx(0, negzero)}, - Test{cmplx(2, 0), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(2, 0), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, 0), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(2, 1), cmplx(0, 1), cmplx(1, -2)}, - Test{cmplx(2, 1), cmplx(0, -1), cmplx(-1, 2)}, - Test{cmplx(2, 1), cmplx(0, 2), cmplx(0.5, -1)}, - Test{cmplx(2, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(1, 0), cmplx(2, 1)}, - Test{cmplx(2, 1), cmplx(1, 1), cmplx(1.5, -0.5)}, - Test{cmplx(2, 1), cmplx(1, -1), cmplx(0.5, 1.5)}, - Test{cmplx(2, 1), cmplx(1, 2), cmplx(0.8, -0.6)}, - Test{cmplx(2, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(-1, 0), cmplx(-2, -1)}, - Test{cmplx(2, 1), cmplx(-1, 1), cmplx(-0.5, -1.5)}, - Test{cmplx(2, 1), cmplx(-1, -1), cmplx(-1.5, 0.5)}, - Test{cmplx(2, 1), cmplx(-1, 2), cmplx(0, -1)}, - Test{cmplx(2, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(2, 0), cmplx(1, 0.5)}, - Test{cmplx(2, 1), cmplx(2, 1), cmplx(1, 0)}, - Test{cmplx(2, 1), cmplx(2, -1), cmplx(0.6, 0.8)}, - Test{cmplx(2, 1), cmplx(2, 2), cmplx(0.75, -0.25)}, - Test{cmplx(2, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, 1), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 1), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(inf, inf), cmplx(0, negzero)}, - Test{cmplx(2, 1), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(2, 1), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, 1), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(2, -1), cmplx(0, 1), cmplx(-1, -2)}, - Test{cmplx(2, -1), cmplx(0, -1), cmplx(1, 2)}, - Test{cmplx(2, -1), cmplx(0, 2), cmplx(-0.5, -1)}, - Test{cmplx(2, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(0, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(0, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(1, 0), cmplx(2, -1)}, - Test{cmplx(2, -1), cmplx(1, 1), cmplx(0.5, -1.5)}, - Test{cmplx(2, -1), cmplx(1, -1), cmplx(1.5, 0.5)}, - Test{cmplx(2, -1), cmplx(1, 2), cmplx(0, -1)}, - Test{cmplx(2, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(1, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(1, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(-1, 0), cmplx(-2, 1)}, - Test{cmplx(2, -1), cmplx(-1, 1), cmplx(-1.5, -0.5)}, - Test{cmplx(2, -1), cmplx(-1, -1), cmplx(-0.5, 1.5)}, - Test{cmplx(2, -1), cmplx(-1, 2), cmplx(-0.8, -0.6)}, - Test{cmplx(2, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(-1, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(-1, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(2, 0), cmplx(1, -0.5)}, - Test{cmplx(2, -1), cmplx(2, 1), cmplx(0.6, -0.8)}, - Test{cmplx(2, -1), cmplx(2, -1), cmplx(1, 0)}, - Test{cmplx(2, -1), cmplx(2, 2), cmplx(0.25, -0.75)}, - Test{cmplx(2, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(2, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(2, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, -1), cmplx(nan, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(nan, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(inf, 0), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, 1), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, -1), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, 2), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, nan), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, inf), cmplx(0, negzero)}, - Test{cmplx(2, -1), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(2, -1), cmplx(-inf, 0), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(-inf, 1), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(-inf, -1), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(-inf, 2), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(-inf, nan), cmplx(negzero, 0)}, - Test{cmplx(2, -1), cmplx(-inf, inf), cmplx(negzero, negzero)}, - Test{cmplx(2, -1), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(2, 2), cmplx(0, 1), cmplx(2, -2)}, - Test{cmplx(2, 2), cmplx(0, -1), cmplx(-2, 2)}, - Test{cmplx(2, 2), cmplx(0, 2), cmplx(1, -1)}, - Test{cmplx(2, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(0, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(0, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(1, 0), cmplx(2, 2)}, - Test{cmplx(2, 2), cmplx(1, 1), cmplx(2, 0)}, - Test{cmplx(2, 2), cmplx(1, -1), cmplx(0, 2)}, - Test{cmplx(2, 2), cmplx(1, 2), cmplx(1.2, -0.4)}, - Test{cmplx(2, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(-1, 0), cmplx(-2, -2)}, - Test{cmplx(2, 2), cmplx(-1, 1), cmplx(negzero, -2)}, - Test{cmplx(2, 2), cmplx(-1, -1), cmplx(-2, negzero)}, - Test{cmplx(2, 2), cmplx(-1, 2), cmplx(0.4, -1.2)}, - Test{cmplx(2, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(-1, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(-1, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(2, 0), cmplx(1, 1)}, - Test{cmplx(2, 2), cmplx(2, 1), cmplx(1.2, 0.4)}, - Test{cmplx(2, 2), cmplx(2, -1), cmplx(0.4, 1.2)}, - Test{cmplx(2, 2), cmplx(2, 2), cmplx(1, 0)}, - Test{cmplx(2, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(2, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(2, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, 2), cmplx(nan, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(nan, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, 2), cmplx(inf, 0), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, 1), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, -1), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, 2), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, nan), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, inf), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(inf, -inf), cmplx(0, 0)}, - Test{cmplx(2, 2), cmplx(-inf, 0), cmplx(negzero, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, 1), cmplx(negzero, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, -1), cmplx(negzero, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, 2), cmplx(negzero, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, nan), cmplx(negzero, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, inf), cmplx(0, negzero)}, - Test{cmplx(2, 2), cmplx(-inf, -inf), cmplx(negzero, 0)}, - Test{cmplx(2, nan), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(2, inf), cmplx(0, 1), cmplx(inf, nan)}, - Test{cmplx(2, inf), cmplx(0, -1), cmplx(-inf, nan)}, - Test{cmplx(2, inf), cmplx(0, 2), cmplx(inf, nan)}, - Test{cmplx(2, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(1, 0), cmplx(nan, inf)}, - Test{cmplx(2, inf), cmplx(1, 1), cmplx(inf, inf)}, - Test{cmplx(2, inf), cmplx(1, -1), cmplx(-inf, inf)}, - Test{cmplx(2, inf), cmplx(1, 2), cmplx(inf, inf)}, - Test{cmplx(2, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-1, 0), cmplx(nan, -inf)}, - Test{cmplx(2, inf), cmplx(-1, 1), cmplx(inf, -inf)}, - Test{cmplx(2, inf), cmplx(-1, -1), cmplx(-inf, -inf)}, - Test{cmplx(2, inf), cmplx(-1, 2), cmplx(inf, -inf)}, - Test{cmplx(2, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(2, 0), cmplx(nan, inf)}, - Test{cmplx(2, inf), cmplx(2, 1), cmplx(inf, inf)}, - Test{cmplx(2, inf), cmplx(2, -1), cmplx(-inf, inf)}, - Test{cmplx(2, inf), cmplx(2, 2), cmplx(inf, inf)}, - Test{cmplx(2, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(2, -inf), cmplx(0, 1), cmplx(-inf, nan)}, - Test{cmplx(2, -inf), cmplx(0, -1), cmplx(inf, nan)}, - Test{cmplx(2, -inf), cmplx(0, 2), cmplx(-inf, nan)}, - Test{cmplx(2, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(1, 0), cmplx(nan, -inf)}, - Test{cmplx(2, -inf), cmplx(1, 1), cmplx(-inf, -inf)}, - Test{cmplx(2, -inf), cmplx(1, -1), cmplx(inf, -inf)}, - Test{cmplx(2, -inf), cmplx(1, 2), cmplx(-inf, -inf)}, - Test{cmplx(2, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-1, 0), cmplx(nan, inf)}, - Test{cmplx(2, -inf), cmplx(-1, 1), cmplx(-inf, inf)}, - Test{cmplx(2, -inf), cmplx(-1, -1), cmplx(inf, inf)}, - Test{cmplx(2, -inf), cmplx(-1, 2), cmplx(-inf, inf)}, - Test{cmplx(2, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(2, 0), cmplx(nan, -inf)}, - Test{cmplx(2, -inf), cmplx(2, 1), cmplx(-inf, -inf)}, - Test{cmplx(2, -inf), cmplx(2, -1), cmplx(inf, -inf)}, - Test{cmplx(2, -inf), cmplx(2, 2), cmplx(-inf, -inf)}, - Test{cmplx(2, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(2, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 0), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, 2), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(0, 0), cmplx(nan, inf)}, - Test{cmplx(nan, inf), cmplx(0, 1), cmplx(inf, nan)}, - Test{cmplx(nan, inf), cmplx(0, -1), cmplx(-inf, nan)}, - Test{cmplx(nan, inf), cmplx(0, 2), cmplx(inf, nan)}, - Test{cmplx(nan, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(1, 0), cmplx(nan, inf)}, - Test{cmplx(nan, inf), cmplx(1, 1), cmplx(inf, inf)}, - Test{cmplx(nan, inf), cmplx(1, -1), cmplx(-inf, inf)}, - Test{cmplx(nan, inf), cmplx(1, 2), cmplx(inf, inf)}, - Test{cmplx(nan, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-1, 0), cmplx(nan, -inf)}, - Test{cmplx(nan, inf), cmplx(-1, 1), cmplx(inf, -inf)}, - Test{cmplx(nan, inf), cmplx(-1, -1), cmplx(-inf, -inf)}, - Test{cmplx(nan, inf), cmplx(-1, 2), cmplx(inf, -inf)}, - Test{cmplx(nan, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(2, 0), cmplx(nan, inf)}, - Test{cmplx(nan, inf), cmplx(2, 1), cmplx(inf, inf)}, - Test{cmplx(nan, inf), cmplx(2, -1), cmplx(-inf, inf)}, - Test{cmplx(nan, inf), cmplx(2, 2), cmplx(inf, inf)}, - Test{cmplx(nan, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(0, 0), cmplx(nan, -inf)}, - Test{cmplx(nan, -inf), cmplx(0, 1), cmplx(-inf, nan)}, - Test{cmplx(nan, -inf), cmplx(0, -1), cmplx(inf, nan)}, - Test{cmplx(nan, -inf), cmplx(0, 2), cmplx(-inf, nan)}, - Test{cmplx(nan, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(1, 0), cmplx(nan, -inf)}, - Test{cmplx(nan, -inf), cmplx(1, 1), cmplx(-inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(1, -1), cmplx(inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(1, 2), cmplx(-inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-1, 0), cmplx(nan, inf)}, - Test{cmplx(nan, -inf), cmplx(-1, 1), cmplx(-inf, inf)}, - Test{cmplx(nan, -inf), cmplx(-1, -1), cmplx(inf, inf)}, - Test{cmplx(nan, -inf), cmplx(-1, 2), cmplx(-inf, inf)}, - Test{cmplx(nan, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(2, 0), cmplx(nan, -inf)}, - Test{cmplx(nan, -inf), cmplx(2, 1), cmplx(-inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(2, -1), cmplx(inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(2, 2), cmplx(-inf, -inf)}, - Test{cmplx(nan, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(nan, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(0, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 0), cmplx(0, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, 0), cmplx(0, -1), cmplx(nan, inf)}, - Test{cmplx(inf, 0), cmplx(0, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(1, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 0), cmplx(1, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 0), cmplx(1, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 0), cmplx(1, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-1, 0), cmplx(-inf, nan)}, - Test{cmplx(inf, 0), cmplx(-1, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, 0), cmplx(-1, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, 0), cmplx(-1, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(2, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 0), cmplx(2, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 0), cmplx(2, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 0), cmplx(2, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 0), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(inf, 1), cmplx(0, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, 1), cmplx(0, -1), cmplx(nan, inf)}, - Test{cmplx(inf, 1), cmplx(0, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(1, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 1), cmplx(1, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 1), cmplx(1, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 1), cmplx(1, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-1, 0), cmplx(-inf, nan)}, - Test{cmplx(inf, 1), cmplx(-1, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, 1), cmplx(-1, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, 1), cmplx(-1, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(2, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 1), cmplx(2, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 1), cmplx(2, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 1), cmplx(2, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(inf, -1), cmplx(0, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, -1), cmplx(0, -1), cmplx(nan, inf)}, - Test{cmplx(inf, -1), cmplx(0, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(1, 0), cmplx(inf, nan)}, - Test{cmplx(inf, -1), cmplx(1, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, -1), cmplx(1, -1), cmplx(inf, inf)}, - Test{cmplx(inf, -1), cmplx(1, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-1, 0), cmplx(-inf, nan)}, - Test{cmplx(inf, -1), cmplx(-1, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, -1), cmplx(-1, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, -1), cmplx(-1, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(2, 0), cmplx(inf, nan)}, - Test{cmplx(inf, -1), cmplx(2, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, -1), cmplx(2, -1), cmplx(inf, inf)}, - Test{cmplx(inf, -1), cmplx(2, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(inf, 2), cmplx(0, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, 2), cmplx(0, -1), cmplx(nan, inf)}, - Test{cmplx(inf, 2), cmplx(0, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(1, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 2), cmplx(1, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 2), cmplx(1, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 2), cmplx(1, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-1, 0), cmplx(-inf, nan)}, - Test{cmplx(inf, 2), cmplx(-1, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, 2), cmplx(-1, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, 2), cmplx(-1, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(2, 0), cmplx(inf, nan)}, - Test{cmplx(inf, 2), cmplx(2, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, 2), cmplx(2, -1), cmplx(inf, inf)}, - Test{cmplx(inf, 2), cmplx(2, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, 2), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(0, 0), cmplx(inf, nan)}, - Test{cmplx(inf, nan), cmplx(0, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, nan), cmplx(0, -1), cmplx(nan, inf)}, - Test{cmplx(inf, nan), cmplx(0, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(1, 0), cmplx(inf, nan)}, - Test{cmplx(inf, nan), cmplx(1, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, nan), cmplx(1, -1), cmplx(inf, inf)}, - Test{cmplx(inf, nan), cmplx(1, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-1, 0), cmplx(-inf, nan)}, - Test{cmplx(inf, nan), cmplx(-1, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, nan), cmplx(-1, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, nan), cmplx(-1, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(2, 0), cmplx(inf, nan)}, - Test{cmplx(inf, nan), cmplx(2, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, nan), cmplx(2, -1), cmplx(inf, inf)}, - Test{cmplx(inf, nan), cmplx(2, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(0, 0), cmplx(inf, inf)}, - Test{cmplx(inf, inf), cmplx(0, 1), cmplx(inf, -inf)}, - Test{cmplx(inf, inf), cmplx(0, -1), cmplx(-inf, inf)}, - Test{cmplx(inf, inf), cmplx(0, 2), cmplx(inf, -inf)}, - Test{cmplx(inf, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(1, 0), cmplx(inf, inf)}, - Test{cmplx(inf, inf), cmplx(1, 1), cmplx(inf, nan)}, - Test{cmplx(inf, inf), cmplx(1, -1), cmplx(nan, inf)}, - Test{cmplx(inf, inf), cmplx(1, 2), cmplx(inf, nan)}, - Test{cmplx(inf, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-1, 0), cmplx(-inf, -inf)}, - Test{cmplx(inf, inf), cmplx(-1, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, inf), cmplx(-1, -1), cmplx(-inf, nan)}, - Test{cmplx(inf, inf), cmplx(-1, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(2, 0), cmplx(inf, inf)}, - Test{cmplx(inf, inf), cmplx(2, 1), cmplx(inf, nan)}, - Test{cmplx(inf, inf), cmplx(2, -1), cmplx(nan, inf)}, - Test{cmplx(inf, inf), cmplx(2, 2), cmplx(inf, nan)}, - Test{cmplx(inf, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(0, 0), cmplx(inf, -inf)}, - Test{cmplx(inf, -inf), cmplx(0, 1), cmplx(-inf, -inf)}, - Test{cmplx(inf, -inf), cmplx(0, -1), cmplx(inf, inf)}, - Test{cmplx(inf, -inf), cmplx(0, 2), cmplx(-inf, -inf)}, - Test{cmplx(inf, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(1, 0), cmplx(inf, -inf)}, - Test{cmplx(inf, -inf), cmplx(1, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, -inf), cmplx(1, -1), cmplx(inf, nan)}, - Test{cmplx(inf, -inf), cmplx(1, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-1, 0), cmplx(-inf, inf)}, - Test{cmplx(inf, -inf), cmplx(-1, 1), cmplx(-inf, nan)}, - Test{cmplx(inf, -inf), cmplx(-1, -1), cmplx(nan, inf)}, - Test{cmplx(inf, -inf), cmplx(-1, 2), cmplx(-inf, nan)}, - Test{cmplx(inf, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(2, 0), cmplx(inf, -inf)}, - Test{cmplx(inf, -inf), cmplx(2, 1), cmplx(nan, -inf)}, - Test{cmplx(inf, -inf), cmplx(2, -1), cmplx(inf, nan)}, - Test{cmplx(inf, -inf), cmplx(2, 2), cmplx(nan, -inf)}, - Test{cmplx(inf, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(inf, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(0, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 0), cmplx(0, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, 0), cmplx(0, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, 0), cmplx(0, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, 0), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(1, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 0), cmplx(1, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 0), cmplx(1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 0), cmplx(1, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 0), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-1, 0), cmplx(inf, nan)}, - Test{cmplx(-inf, 0), cmplx(-1, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, 0), cmplx(-1, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, 0), cmplx(-1, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, 0), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(2, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 0), cmplx(2, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 0), cmplx(2, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 0), cmplx(2, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 0), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 0), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-inf, 1), cmplx(0, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, 1), cmplx(0, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, 1), cmplx(0, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, 1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(1, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 1), cmplx(1, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 1), cmplx(1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 1), cmplx(1, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-1, 0), cmplx(inf, nan)}, - Test{cmplx(-inf, 1), cmplx(-1, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, 1), cmplx(-1, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, 1), cmplx(-1, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, 1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(2, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 1), cmplx(2, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 1), cmplx(2, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 1), cmplx(2, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(0, 0), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -1), cmplx(0, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, -1), cmplx(0, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, -1), cmplx(0, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, -1), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(1, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, -1), cmplx(1, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, -1), cmplx(1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -1), cmplx(1, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, -1), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-1, 0), cmplx(inf, nan)}, - Test{cmplx(-inf, -1), cmplx(-1, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, -1), cmplx(-1, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, -1), cmplx(-1, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, -1), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(2, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, -1), cmplx(2, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, -1), cmplx(2, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -1), cmplx(2, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, -1), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -1), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-inf, 2), cmplx(0, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, 2), cmplx(0, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, 2), cmplx(0, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, 2), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(1, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 2), cmplx(1, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 2), cmplx(1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 2), cmplx(1, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 2), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-1, 0), cmplx(inf, nan)}, - Test{cmplx(-inf, 2), cmplx(-1, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, 2), cmplx(-1, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, 2), cmplx(-1, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, 2), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(2, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, 2), cmplx(2, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, 2), cmplx(2, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, 2), cmplx(2, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, 2), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, 2), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(0, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, nan), cmplx(0, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, nan), cmplx(0, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, nan), cmplx(0, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, nan), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(1, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, nan), cmplx(1, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, nan), cmplx(1, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, nan), cmplx(1, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, nan), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-1, 0), cmplx(inf, nan)}, - Test{cmplx(-inf, nan), cmplx(-1, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, nan), cmplx(-1, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, nan), cmplx(-1, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, nan), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(2, 0), cmplx(-inf, nan)}, - Test{cmplx(-inf, nan), cmplx(2, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, nan), cmplx(2, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, nan), cmplx(2, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, nan), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, nan), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(0, 0), cmplx(-inf, inf)}, - Test{cmplx(-inf, inf), cmplx(0, 1), cmplx(inf, inf)}, - Test{cmplx(-inf, inf), cmplx(0, -1), cmplx(-inf, -inf)}, - Test{cmplx(-inf, inf), cmplx(0, 2), cmplx(inf, inf)}, - Test{cmplx(-inf, inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(1, 0), cmplx(-inf, inf)}, - Test{cmplx(-inf, inf), cmplx(1, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, inf), cmplx(1, -1), cmplx(-inf, nan)}, - Test{cmplx(-inf, inf), cmplx(1, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-1, 0), cmplx(inf, -inf)}, - Test{cmplx(-inf, inf), cmplx(-1, 1), cmplx(inf, nan)}, - Test{cmplx(-inf, inf), cmplx(-1, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, inf), cmplx(-1, 2), cmplx(inf, nan)}, - Test{cmplx(-inf, inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(2, 0), cmplx(-inf, inf)}, - Test{cmplx(-inf, inf), cmplx(2, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, inf), cmplx(2, -1), cmplx(-inf, nan)}, - Test{cmplx(-inf, inf), cmplx(2, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, inf), cmplx(-inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(0, 0), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -inf), cmplx(0, 1), cmplx(-inf, inf)}, - Test{cmplx(-inf, -inf), cmplx(0, -1), cmplx(inf, -inf)}, - Test{cmplx(-inf, -inf), cmplx(0, 2), cmplx(-inf, inf)}, - Test{cmplx(-inf, -inf), cmplx(0, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(0, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(0, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(1, 0), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -inf), cmplx(1, 1), cmplx(-inf, nan)}, - Test{cmplx(-inf, -inf), cmplx(1, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, -inf), cmplx(1, 2), cmplx(-inf, nan)}, - Test{cmplx(-inf, -inf), cmplx(1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-1, 0), cmplx(inf, inf)}, - Test{cmplx(-inf, -inf), cmplx(-1, 1), cmplx(nan, inf)}, - Test{cmplx(-inf, -inf), cmplx(-1, -1), cmplx(inf, nan)}, - Test{cmplx(-inf, -inf), cmplx(-1, 2), cmplx(nan, inf)}, - Test{cmplx(-inf, -inf), cmplx(-1, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-1, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-1, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(2, 0), cmplx(-inf, -inf)}, - Test{cmplx(-inf, -inf), cmplx(2, 1), cmplx(-inf, nan)}, - Test{cmplx(-inf, -inf), cmplx(2, -1), cmplx(nan, -inf)}, - Test{cmplx(-inf, -inf), cmplx(2, 2), cmplx(-inf, nan)}, - Test{cmplx(-inf, -inf), cmplx(2, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(2, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(2, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(nan, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(inf, -inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, 0), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, 1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, -1), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, 2), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, nan), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, inf), cmplx(nan, nan)}, - Test{cmplx(-inf, -inf), cmplx(-inf, -inf), cmplx(nan, nan)}, + Test{complex(0, 0), complex(0, 0), complex(-nan, -nan)}, + Test{complex(0, 0), complex(0, 1), complex(0, 0)}, + Test{complex(0, 0), complex(0, -1), complex(negzero, 0)}, + Test{complex(0, 0), complex(0, 2), complex(0, 0)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(1, 0), complex(0, 0)}, + Test{complex(0, 0), complex(1, 1), complex(0, 0)}, + Test{complex(0, 0), complex(1, -1), complex(0, 0)}, + Test{complex(0, 0), complex(1, 2), complex(0, 0)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(-1, 0), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-1, 1), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-1, -1), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-1, 2), complex(0, negzero)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(2, 0), complex(0, 0)}, + Test{complex(0, 0), complex(2, 1), complex(0, 0)}, + Test{complex(0, 0), complex(2, -1), complex(0, 0)}, + Test{complex(0, 0), complex(2, 2), complex(0, 0)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(0, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(0, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(0, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(inf, 0), complex(0, 0)}, + Test{complex(0, 0), complex(inf, 1), complex(0, 0)}, + Test{complex(0, 0), complex(inf, -1), complex(0, 0)}, + Test{complex(0, 0), complex(inf, 2), complex(0, 0)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 0), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(0, 0), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(0, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(0, 0), complex(-nan, inf)}, + Test{complex(0, 1), complex(0, 1), complex(1, 0)}, + Test{complex(0, 1), complex(0, -1), complex(-1, 0)}, + Test{complex(0, 1), complex(0, 2), complex(0.5, 0)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(1, 0), complex(0, 1)}, + Test{complex(0, 1), complex(1, 1), complex(0.5, 0.5)}, + Test{complex(0, 1), complex(1, -1), complex(-0.5, 0.5)}, + Test{complex(0, 1), complex(1, 2), complex(0.4, 0.2)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(-1, 0), complex(negzero, -1)}, + Test{complex(0, 1), complex(-1, 1), complex(0.5, -0.5)}, + Test{complex(0, 1), complex(-1, -1), complex(-0.5, -0.5)}, + Test{complex(0, 1), complex(-1, 2), complex(0.4, -0.2)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(2, 0), complex(0, 0.5)}, + Test{complex(0, 1), complex(2, 1), complex(0.2, 0.4)}, + Test{complex(0, 1), complex(2, -1), complex(-0.2, 0.4)}, + Test{complex(0, 1), complex(2, 2), complex(0.25, 0.25)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(0, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(0, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(0, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(inf, 0), complex(0, 0)}, + Test{complex(0, 1), complex(inf, 1), complex(0, 0)}, + Test{complex(0, 1), complex(inf, -1), complex(0, 0)}, + Test{complex(0, 1), complex(inf, 2), complex(0, 0)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 1), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(0, 1), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(0, 1), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(0, 1), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(0, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(0, 0), complex(-nan, -inf)}, + Test{complex(0, -1), complex(0, 1), complex(-1, negzero)}, + Test{complex(0, -1), complex(0, -1), complex(1, negzero)}, + Test{complex(0, -1), complex(0, 2), complex(-0.5, negzero)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(1, 0), complex(0, -1)}, + Test{complex(0, -1), complex(1, 1), complex(-0.5, -0.5)}, + Test{complex(0, -1), complex(1, -1), complex(0.5, -0.5)}, + Test{complex(0, -1), complex(1, 2), complex(-0.4, -0.2)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(-1, 0), complex(negzero, 1)}, + Test{complex(0, -1), complex(-1, 1), complex(-0.5, 0.5)}, + Test{complex(0, -1), complex(-1, -1), complex(0.5, 0.5)}, + Test{complex(0, -1), complex(-1, 2), complex(-0.4, 0.2)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(2, 0), complex(0, -0.5)}, + Test{complex(0, -1), complex(2, 1), complex(-0.2, -0.4)}, + Test{complex(0, -1), complex(2, -1), complex(0.2, -0.4)}, + Test{complex(0, -1), complex(2, 2), complex(-0.25, -0.25)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(0, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(0, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(0, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(inf, 0), complex(0, negzero)}, + Test{complex(0, -1), complex(inf, 1), complex(0, negzero)}, + Test{complex(0, -1), complex(inf, -1), complex(0, negzero)}, + Test{complex(0, -1), complex(inf, 2), complex(0, negzero)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, -1), complex(-inf, 0), complex(negzero, 0)}, + Test{complex(0, -1), complex(-inf, 1), complex(negzero, 0)}, + Test{complex(0, -1), complex(-inf, -1), complex(negzero, 0)}, + Test{complex(0, -1), complex(-inf, 2), complex(negzero, 0)}, + Test{complex(0, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(0, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(0, 2), complex(0, 0), complex(-nan, inf)}, + Test{complex(0, 2), complex(0, 1), complex(2, 0)}, + Test{complex(0, 2), complex(0, -1), complex(-2, 0)}, + Test{complex(0, 2), complex(0, 2), complex(1, 0)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(1, 0), complex(0, 2)}, + Test{complex(0, 2), complex(1, 1), complex(1, 1)}, + Test{complex(0, 2), complex(1, -1), complex(-1, 1)}, + Test{complex(0, 2), complex(1, 2), complex(0.8, 0.4)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(-1, 0), complex(negzero, -2)}, + Test{complex(0, 2), complex(-1, 1), complex(1, -1)}, + Test{complex(0, 2), complex(-1, -1), complex(-1, -1)}, + Test{complex(0, 2), complex(-1, 2), complex(0.8, -0.4)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(2, 0), complex(0, 1)}, + Test{complex(0, 2), complex(2, 1), complex(0.4, 0.8)}, + Test{complex(0, 2), complex(2, -1), complex(-0.4, 0.8)}, + Test{complex(0, 2), complex(2, 2), complex(0.5, 0.5)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(0, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(0, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(0, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(inf, 0), complex(0, 0)}, + Test{complex(0, 2), complex(inf, 1), complex(0, 0)}, + Test{complex(0, 2), complex(inf, -1), complex(0, 0)}, + Test{complex(0, 2), complex(inf, 2), complex(0, 0)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(0, 2), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(0, 2), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(0, 2), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(0, 2), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(0, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(0, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(0, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(1, 0), complex(0, 0), complex(inf, -nan)}, + Test{complex(1, 0), complex(0, 1), complex(0, -1)}, + Test{complex(1, 0), complex(0, -1), complex(negzero, 1)}, + Test{complex(1, 0), complex(0, 2), complex(0, -0.5)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(1, 0), complex(1, 0)}, + Test{complex(1, 0), complex(1, 1), complex(0.5, -0.5)}, + Test{complex(1, 0), complex(1, -1), complex(0.5, 0.5)}, + Test{complex(1, 0), complex(1, 2), complex(0.2, -0.4)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(-1, 0), complex(-1, negzero)}, + Test{complex(1, 0), complex(-1, 1), complex(-0.5, -0.5)}, + Test{complex(1, 0), complex(-1, -1), complex(-0.5, 0.5)}, + Test{complex(1, 0), complex(-1, 2), complex(-0.2, -0.4)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(2, 0), complex(0.5, 0)}, + Test{complex(1, 0), complex(2, 1), complex(0.4, -0.2)}, + Test{complex(1, 0), complex(2, -1), complex(0.4, 0.2)}, + Test{complex(1, 0), complex(2, 2), complex(0.25, -0.25)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(1, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(1, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(1, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(inf, 0), complex(0, 0)}, + Test{complex(1, 0), complex(inf, 1), complex(0, 0)}, + Test{complex(1, 0), complex(inf, -1), complex(0, 0)}, + Test{complex(1, 0), complex(inf, 2), complex(0, 0)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 0), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(1, 0), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(1, 0), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(1, 0), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(0, 0), complex(inf, inf)}, + Test{complex(1, 1), complex(0, 1), complex(1, -1)}, + Test{complex(1, 1), complex(0, -1), complex(-1, 1)}, + Test{complex(1, 1), complex(0, 2), complex(0.5, -0.5)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(1, 0), complex(1, 1)}, + Test{complex(1, 1), complex(1, 1), complex(1, 0)}, + Test{complex(1, 1), complex(1, -1), complex(0, 1)}, + Test{complex(1, 1), complex(1, 2), complex(0.6, -0.2)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(-1, 0), complex(-1, -1)}, + Test{complex(1, 1), complex(-1, 1), complex(negzero, -1)}, + Test{complex(1, 1), complex(-1, -1), complex(-1, negzero)}, + Test{complex(1, 1), complex(-1, 2), complex(0.2, -0.6)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(2, 0), complex(0.5, 0.5)}, + Test{complex(1, 1), complex(2, 1), complex(0.6, 0.2)}, + Test{complex(1, 1), complex(2, -1), complex(0.2, 0.6)}, + Test{complex(1, 1), complex(2, 2), complex(0.5, 0)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(1, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(1, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(1, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(inf, 0), complex(0, 0)}, + Test{complex(1, 1), complex(inf, 1), complex(0, 0)}, + Test{complex(1, 1), complex(inf, -1), complex(0, 0)}, + Test{complex(1, 1), complex(inf, 2), complex(0, 0)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 1), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(1, 1), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(1, 1), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(1, 1), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, -1), complex(0, 0), complex(inf, -inf)}, + Test{complex(1, -1), complex(0, 1), complex(-1, -1)}, + Test{complex(1, -1), complex(0, -1), complex(1, 1)}, + Test{complex(1, -1), complex(0, 2), complex(-0.5, -0.5)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(1, 0), complex(1, -1)}, + Test{complex(1, -1), complex(1, 1), complex(0, -1)}, + Test{complex(1, -1), complex(1, -1), complex(1, 0)}, + Test{complex(1, -1), complex(1, 2), complex(-0.2, -0.6)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(-1, 0), complex(-1, 1)}, + Test{complex(1, -1), complex(-1, 1), complex(-1, negzero)}, + Test{complex(1, -1), complex(-1, -1), complex(negzero, 1)}, + Test{complex(1, -1), complex(-1, 2), complex(-0.6, -0.2)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(2, 0), complex(0.5, -0.5)}, + Test{complex(1, -1), complex(2, 1), complex(0.2, -0.6)}, + Test{complex(1, -1), complex(2, -1), complex(0.6, -0.2)}, + Test{complex(1, -1), complex(2, 2), complex(0, -0.5)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(1, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(1, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(1, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(inf, 0), complex(0, negzero)}, + Test{complex(1, -1), complex(inf, 1), complex(0, negzero)}, + Test{complex(1, -1), complex(inf, -1), complex(0, negzero)}, + Test{complex(1, -1), complex(inf, 2), complex(0, negzero)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, -1), complex(-inf, 0), complex(negzero, 0)}, + Test{complex(1, -1), complex(-inf, 1), complex(negzero, 0)}, + Test{complex(1, -1), complex(-inf, -1), complex(negzero, 0)}, + Test{complex(1, -1), complex(-inf, 2), complex(negzero, 0)}, + Test{complex(1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(1, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(1, 2), complex(0, 0), complex(inf, inf)}, + Test{complex(1, 2), complex(0, 1), complex(2, -1)}, + Test{complex(1, 2), complex(0, -1), complex(-2, 1)}, + Test{complex(1, 2), complex(0, 2), complex(1, -0.5)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(1, 0), complex(1, 2)}, + Test{complex(1, 2), complex(1, 1), complex(1.5, 0.5)}, + Test{complex(1, 2), complex(1, -1), complex(-0.5, 1.5)}, + Test{complex(1, 2), complex(1, 2), complex(1, 0)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(-1, 0), complex(-1, -2)}, + Test{complex(1, 2), complex(-1, 1), complex(0.5, -1.5)}, + Test{complex(1, 2), complex(-1, -1), complex(-1.5, -0.5)}, + Test{complex(1, 2), complex(-1, 2), complex(0.6, -0.8)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(2, 0), complex(0.5, 1)}, + Test{complex(1, 2), complex(2, 1), complex(0.8, 0.6)}, + Test{complex(1, 2), complex(2, -1), complex(0, 1)}, + Test{complex(1, 2), complex(2, 2), complex(0.75, 0.25)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(1, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(1, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(1, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(inf, 0), complex(0, 0)}, + Test{complex(1, 2), complex(inf, 1), complex(0, 0)}, + Test{complex(1, 2), complex(inf, -1), complex(0, 0)}, + Test{complex(1, 2), complex(inf, 2), complex(0, 0)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(1, 2), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(1, 2), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(1, 2), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(1, 2), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(1, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(1, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-1, 0), complex(0, 0), complex(-inf, -nan)}, + Test{complex(-1, 0), complex(0, 1), complex(0, 1)}, + Test{complex(-1, 0), complex(0, -1), complex(negzero, -1)}, + Test{complex(-1, 0), complex(0, 2), complex(0, 0.5)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(1, 0), complex(-1, 0)}, + Test{complex(-1, 0), complex(1, 1), complex(-0.5, 0.5)}, + Test{complex(-1, 0), complex(1, -1), complex(-0.5, -0.5)}, + Test{complex(-1, 0), complex(1, 2), complex(-0.2, 0.4)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(-1, 0), complex(1, negzero)}, + Test{complex(-1, 0), complex(-1, 1), complex(0.5, 0.5)}, + Test{complex(-1, 0), complex(-1, -1), complex(0.5, -0.5)}, + Test{complex(-1, 0), complex(-1, 2), complex(0.2, 0.4)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(2, 0), complex(-0.5, 0)}, + Test{complex(-1, 0), complex(2, 1), complex(-0.4, 0.2)}, + Test{complex(-1, 0), complex(2, -1), complex(-0.4, -0.2)}, + Test{complex(-1, 0), complex(2, 2), complex(-0.25, 0.25)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(-1, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(-1, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(-1, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(inf, 0), complex(negzero, 0)}, + Test{complex(-1, 0), complex(inf, 1), complex(negzero, 0)}, + Test{complex(-1, 0), complex(inf, -1), complex(negzero, 0)}, + Test{complex(-1, 0), complex(inf, 2), complex(negzero, 0)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 0), complex(-inf, 0), complex(0, negzero)}, + Test{complex(-1, 0), complex(-inf, 1), complex(0, negzero)}, + Test{complex(-1, 0), complex(-inf, -1), complex(0, negzero)}, + Test{complex(-1, 0), complex(-inf, 2), complex(0, negzero)}, + Test{complex(-1, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 0), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 0), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 1), complex(0, 0), complex(-inf, inf)}, + Test{complex(-1, 1), complex(0, 1), complex(1, 1)}, + Test{complex(-1, 1), complex(0, -1), complex(-1, -1)}, + Test{complex(-1, 1), complex(0, 2), complex(0.5, 0.5)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(1, 0), complex(-1, 1)}, + Test{complex(-1, 1), complex(1, 1), complex(0, 1)}, + Test{complex(-1, 1), complex(1, -1), complex(-1, 0)}, + Test{complex(-1, 1), complex(1, 2), complex(0.2, 0.6)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(-1, 0), complex(1, -1)}, + Test{complex(-1, 1), complex(-1, 1), complex(1, negzero)}, + Test{complex(-1, 1), complex(-1, -1), complex(negzero, -1)}, + Test{complex(-1, 1), complex(-1, 2), complex(0.6, 0.2)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(2, 0), complex(-0.5, 0.5)}, + Test{complex(-1, 1), complex(2, 1), complex(-0.2, 0.6)}, + Test{complex(-1, 1), complex(2, -1), complex(-0.6, 0.2)}, + Test{complex(-1, 1), complex(2, 2), complex(0, 0.5)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(-1, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(-1, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(-1, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(inf, 0), complex(negzero, 0)}, + Test{complex(-1, 1), complex(inf, 1), complex(negzero, 0)}, + Test{complex(-1, 1), complex(inf, -1), complex(negzero, 0)}, + Test{complex(-1, 1), complex(inf, 2), complex(negzero, 0)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 1), complex(-inf, 0), complex(0, negzero)}, + Test{complex(-1, 1), complex(-inf, 1), complex(0, negzero)}, + Test{complex(-1, 1), complex(-inf, -1), complex(0, negzero)}, + Test{complex(-1, 1), complex(-inf, 2), complex(0, negzero)}, + Test{complex(-1, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 1), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 1), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, -1), complex(0, 0), complex(-inf, -inf)}, + Test{complex(-1, -1), complex(0, 1), complex(-1, 1)}, + Test{complex(-1, -1), complex(0, -1), complex(1, -1)}, + Test{complex(-1, -1), complex(0, 2), complex(-0.5, 0.5)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(1, 0), complex(-1, -1)}, + Test{complex(-1, -1), complex(1, 1), complex(-1, 0)}, + Test{complex(-1, -1), complex(1, -1), complex(0, -1)}, + Test{complex(-1, -1), complex(1, 2), complex(-0.6, 0.2)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(-1, 0), complex(1, 1)}, + Test{complex(-1, -1), complex(-1, 1), complex(negzero, 1)}, + Test{complex(-1, -1), complex(-1, -1), complex(1, negzero)}, + Test{complex(-1, -1), complex(-1, 2), complex(-0.2, 0.6)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(2, 0), complex(-0.5, -0.5)}, + Test{complex(-1, -1), complex(2, 1), complex(-0.6, -0.2)}, + Test{complex(-1, -1), complex(2, -1), complex(-0.2, -0.6)}, + Test{complex(-1, -1), complex(2, 2), complex(-0.5, 0)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(-1, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(-1, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(-1, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(inf, 0), complex(negzero, negzero)}, + Test{complex(-1, -1), complex(inf, 1), complex(negzero, negzero)}, + Test{complex(-1, -1), complex(inf, -1), complex(negzero, negzero)}, + Test{complex(-1, -1), complex(inf, 2), complex(negzero, negzero)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, -1), complex(-inf, 0), complex(0, 0)}, + Test{complex(-1, -1), complex(-inf, 1), complex(0, 0)}, + Test{complex(-1, -1), complex(-inf, -1), complex(0, 0)}, + Test{complex(-1, -1), complex(-inf, 2), complex(0, 0)}, + Test{complex(-1, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, -1), complex(-nan, inf), complex(negzero, 0)}, + Test{complex(-1, -1), complex(-nan, -inf), complex(0, negzero)}, + Test{complex(-1, 2), complex(0, 0), complex(-inf, inf)}, + Test{complex(-1, 2), complex(0, 1), complex(2, 1)}, + Test{complex(-1, 2), complex(0, -1), complex(-2, -1)}, + Test{complex(-1, 2), complex(0, 2), complex(1, 0.5)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(1, 0), complex(-1, 2)}, + Test{complex(-1, 2), complex(1, 1), complex(0.5, 1.5)}, + Test{complex(-1, 2), complex(1, -1), complex(-1.5, 0.5)}, + Test{complex(-1, 2), complex(1, 2), complex(0.6, 0.8)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(-1, 0), complex(1, -2)}, + Test{complex(-1, 2), complex(-1, 1), complex(1.5, -0.5)}, + Test{complex(-1, 2), complex(-1, -1), complex(-0.5, -1.5)}, + Test{complex(-1, 2), complex(-1, 2), complex(1, 0)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(2, 0), complex(-0.5, 1)}, + Test{complex(-1, 2), complex(2, 1), complex(0, 1)}, + Test{complex(-1, 2), complex(2, -1), complex(-0.8, 0.6)}, + Test{complex(-1, 2), complex(2, 2), complex(0.25, 0.75)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(-1, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(-1, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(-1, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(inf, 0), complex(negzero, 0)}, + Test{complex(-1, 2), complex(inf, 1), complex(negzero, 0)}, + Test{complex(-1, 2), complex(inf, -1), complex(negzero, 0)}, + Test{complex(-1, 2), complex(inf, 2), complex(negzero, 0)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(-1, 2), complex(-inf, 0), complex(0, negzero)}, + Test{complex(-1, 2), complex(-inf, 1), complex(0, negzero)}, + Test{complex(-1, 2), complex(-inf, -1), complex(0, negzero)}, + Test{complex(-1, 2), complex(-inf, 2), complex(0, negzero)}, + Test{complex(-1, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-1, 2), complex(-nan, inf), complex(0, 0)}, + Test{complex(-1, 2), complex(-nan, -inf), complex(negzero, negzero)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(2, 0), complex(0, 0), complex(inf, -nan)}, + Test{complex(2, 0), complex(0, 1), complex(0, -2)}, + Test{complex(2, 0), complex(0, -1), complex(negzero, 2)}, + Test{complex(2, 0), complex(0, 2), complex(0, -1)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(1, 0), complex(2, 0)}, + Test{complex(2, 0), complex(1, 1), complex(1, -1)}, + Test{complex(2, 0), complex(1, -1), complex(1, 1)}, + Test{complex(2, 0), complex(1, 2), complex(0.4, -0.8)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(-1, 0), complex(-2, negzero)}, + Test{complex(2, 0), complex(-1, 1), complex(-1, -1)}, + Test{complex(2, 0), complex(-1, -1), complex(-1, 1)}, + Test{complex(2, 0), complex(-1, 2), complex(-0.4, -0.8)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(2, 0), complex(1, 0)}, + Test{complex(2, 0), complex(2, 1), complex(0.8, -0.4)}, + Test{complex(2, 0), complex(2, -1), complex(0.8, 0.4)}, + Test{complex(2, 0), complex(2, 2), complex(0.5, -0.5)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(2, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(2, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(2, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(inf, 0), complex(0, 0)}, + Test{complex(2, 0), complex(inf, 1), complex(0, 0)}, + Test{complex(2, 0), complex(inf, -1), complex(0, 0)}, + Test{complex(2, 0), complex(inf, 2), complex(0, 0)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 0), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(2, 0), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(2, 0), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(2, 0), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(2, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 0), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 0), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(0, 0), complex(inf, inf)}, + Test{complex(2, 1), complex(0, 1), complex(1, -2)}, + Test{complex(2, 1), complex(0, -1), complex(-1, 2)}, + Test{complex(2, 1), complex(0, 2), complex(0.5, -1)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(1, 0), complex(2, 1)}, + Test{complex(2, 1), complex(1, 1), complex(1.5, -0.5)}, + Test{complex(2, 1), complex(1, -1), complex(0.5, 1.5)}, + Test{complex(2, 1), complex(1, 2), complex(0.8, -0.6)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(-1, 0), complex(-2, -1)}, + Test{complex(2, 1), complex(-1, 1), complex(-0.5, -1.5)}, + Test{complex(2, 1), complex(-1, -1), complex(-1.5, 0.5)}, + Test{complex(2, 1), complex(-1, 2), complex(0, -1)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(2, 0), complex(1, 0.5)}, + Test{complex(2, 1), complex(2, 1), complex(1, 0)}, + Test{complex(2, 1), complex(2, -1), complex(0.6, 0.8)}, + Test{complex(2, 1), complex(2, 2), complex(0.75, -0.25)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(2, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(2, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(2, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(inf, 0), complex(0, 0)}, + Test{complex(2, 1), complex(inf, 1), complex(0, 0)}, + Test{complex(2, 1), complex(inf, -1), complex(0, 0)}, + Test{complex(2, 1), complex(inf, 2), complex(0, 0)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 1), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(2, 1), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(2, 1), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(2, 1), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(2, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 1), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 1), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, -1), complex(0, 0), complex(inf, -inf)}, + Test{complex(2, -1), complex(0, 1), complex(-1, -2)}, + Test{complex(2, -1), complex(0, -1), complex(1, 2)}, + Test{complex(2, -1), complex(0, 2), complex(-0.5, -1)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(1, 0), complex(2, -1)}, + Test{complex(2, -1), complex(1, 1), complex(0.5, -1.5)}, + Test{complex(2, -1), complex(1, -1), complex(1.5, 0.5)}, + Test{complex(2, -1), complex(1, 2), complex(0, -1)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(-1, 0), complex(-2, 1)}, + Test{complex(2, -1), complex(-1, 1), complex(-1.5, -0.5)}, + Test{complex(2, -1), complex(-1, -1), complex(-0.5, 1.5)}, + Test{complex(2, -1), complex(-1, 2), complex(-0.8, -0.6)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(2, 0), complex(1, -0.5)}, + Test{complex(2, -1), complex(2, 1), complex(0.6, -0.8)}, + Test{complex(2, -1), complex(2, -1), complex(1, 0)}, + Test{complex(2, -1), complex(2, 2), complex(0.25, -0.75)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(2, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(2, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(2, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(inf, 0), complex(0, negzero)}, + Test{complex(2, -1), complex(inf, 1), complex(0, negzero)}, + Test{complex(2, -1), complex(inf, -1), complex(0, negzero)}, + Test{complex(2, -1), complex(inf, 2), complex(0, negzero)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, -1), complex(-inf, 0), complex(negzero, 0)}, + Test{complex(2, -1), complex(-inf, 1), complex(negzero, 0)}, + Test{complex(2, -1), complex(-inf, -1), complex(negzero, 0)}, + Test{complex(2, -1), complex(-inf, 2), complex(negzero, 0)}, + Test{complex(2, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, -1), complex(-nan, inf), complex(negzero, negzero)}, + Test{complex(2, -1), complex(-nan, -inf), complex(0, 0)}, + Test{complex(2, 2), complex(0, 0), complex(inf, inf)}, + Test{complex(2, 2), complex(0, 1), complex(2, -2)}, + Test{complex(2, 2), complex(0, -1), complex(-2, 2)}, + Test{complex(2, 2), complex(0, 2), complex(1, -1)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(1, 0), complex(2, 2)}, + Test{complex(2, 2), complex(1, 1), complex(2, 0)}, + Test{complex(2, 2), complex(1, -1), complex(0, 2)}, + Test{complex(2, 2), complex(1, 2), complex(1.2, -0.4)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(-1, 0), complex(-2, -2)}, + Test{complex(2, 2), complex(-1, 1), complex(negzero, -2)}, + Test{complex(2, 2), complex(-1, -1), complex(-2, negzero)}, + Test{complex(2, 2), complex(-1, 2), complex(0.4, -1.2)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(2, 0), complex(1, 1)}, + Test{complex(2, 2), complex(2, 1), complex(1.2, 0.4)}, + Test{complex(2, 2), complex(2, -1), complex(0.4, 1.2)}, + Test{complex(2, 2), complex(2, 2), complex(1, 0)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(2, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(2, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(2, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(inf, 0), complex(0, 0)}, + Test{complex(2, 2), complex(inf, 1), complex(0, 0)}, + Test{complex(2, 2), complex(inf, -1), complex(0, 0)}, + Test{complex(2, 2), complex(inf, 2), complex(0, 0)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(2, 2), complex(-inf, 0), complex(negzero, negzero)}, + Test{complex(2, 2), complex(-inf, 1), complex(negzero, negzero)}, + Test{complex(2, 2), complex(-inf, -1), complex(negzero, negzero)}, + Test{complex(2, 2), complex(-inf, 2), complex(negzero, negzero)}, + Test{complex(2, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(2, 2), complex(-nan, inf), complex(0, negzero)}, + Test{complex(2, 2), complex(-nan, -inf), complex(negzero, 0)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, 0), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, 0), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, 0), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, 1), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, 1), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, 1), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, -1), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, -1), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, -1), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, 2), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, 2), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, 2), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(nan, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(0, 0), complex(inf, -nan)}, + Test{complex(inf, 0), complex(0, 1), complex(-nan, -inf)}, + Test{complex(inf, 0), complex(0, -1), complex(-nan, inf)}, + Test{complex(inf, 0), complex(0, 2), complex(-nan, -inf)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(1, 0), complex(inf, -nan)}, + Test{complex(inf, 0), complex(1, 1), complex(inf, -inf)}, + Test{complex(inf, 0), complex(1, -1), complex(inf, inf)}, + Test{complex(inf, 0), complex(1, 2), complex(inf, -inf)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-1, 0), complex(-inf, -nan)}, + Test{complex(inf, 0), complex(-1, 1), complex(-inf, -inf)}, + Test{complex(inf, 0), complex(-1, -1), complex(-inf, inf)}, + Test{complex(inf, 0), complex(-1, 2), complex(-inf, -inf)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(2, 0), complex(inf, -nan)}, + Test{complex(inf, 0), complex(2, 1), complex(inf, -inf)}, + Test{complex(inf, 0), complex(2, -1), complex(inf, inf)}, + Test{complex(inf, 0), complex(2, 2), complex(inf, -inf)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(inf, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(inf, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(inf, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(0, 0), complex(inf, inf)}, + Test{complex(inf, 1), complex(0, 1), complex(-nan, -inf)}, + Test{complex(inf, 1), complex(0, -1), complex(-nan, inf)}, + Test{complex(inf, 1), complex(0, 2), complex(-nan, -inf)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(1, 0), complex(inf, -nan)}, + Test{complex(inf, 1), complex(1, 1), complex(inf, -inf)}, + Test{complex(inf, 1), complex(1, -1), complex(inf, inf)}, + Test{complex(inf, 1), complex(1, 2), complex(inf, -inf)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-1, 0), complex(-inf, -nan)}, + Test{complex(inf, 1), complex(-1, 1), complex(-inf, -inf)}, + Test{complex(inf, 1), complex(-1, -1), complex(-inf, inf)}, + Test{complex(inf, 1), complex(-1, 2), complex(-inf, -inf)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(2, 0), complex(inf, -nan)}, + Test{complex(inf, 1), complex(2, 1), complex(inf, -inf)}, + Test{complex(inf, 1), complex(2, -1), complex(inf, inf)}, + Test{complex(inf, 1), complex(2, 2), complex(inf, -inf)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(inf, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(inf, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(inf, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(0, 0), complex(inf, -inf)}, + Test{complex(inf, -1), complex(0, 1), complex(-nan, -inf)}, + Test{complex(inf, -1), complex(0, -1), complex(-nan, inf)}, + Test{complex(inf, -1), complex(0, 2), complex(-nan, -inf)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(1, 0), complex(inf, -nan)}, + Test{complex(inf, -1), complex(1, 1), complex(inf, -inf)}, + Test{complex(inf, -1), complex(1, -1), complex(inf, inf)}, + Test{complex(inf, -1), complex(1, 2), complex(inf, -inf)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-1, 0), complex(-inf, -nan)}, + Test{complex(inf, -1), complex(-1, 1), complex(-inf, -inf)}, + Test{complex(inf, -1), complex(-1, -1), complex(-inf, inf)}, + Test{complex(inf, -1), complex(-1, 2), complex(-inf, -inf)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(2, 0), complex(inf, -nan)}, + Test{complex(inf, -1), complex(2, 1), complex(inf, -inf)}, + Test{complex(inf, -1), complex(2, -1), complex(inf, inf)}, + Test{complex(inf, -1), complex(2, 2), complex(inf, -inf)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(inf, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(inf, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(inf, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(0, 0), complex(inf, inf)}, + Test{complex(inf, 2), complex(0, 1), complex(-nan, -inf)}, + Test{complex(inf, 2), complex(0, -1), complex(-nan, inf)}, + Test{complex(inf, 2), complex(0, 2), complex(-nan, -inf)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(1, 0), complex(inf, -nan)}, + Test{complex(inf, 2), complex(1, 1), complex(inf, -inf)}, + Test{complex(inf, 2), complex(1, -1), complex(inf, inf)}, + Test{complex(inf, 2), complex(1, 2), complex(inf, -inf)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-1, 0), complex(-inf, -nan)}, + Test{complex(inf, 2), complex(-1, 1), complex(-inf, -inf)}, + Test{complex(inf, 2), complex(-1, -1), complex(-inf, inf)}, + Test{complex(inf, 2), complex(-1, 2), complex(-inf, -inf)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(2, 0), complex(inf, -nan)}, + Test{complex(inf, 2), complex(2, 1), complex(inf, -inf)}, + Test{complex(inf, 2), complex(2, -1), complex(inf, inf)}, + Test{complex(inf, 2), complex(2, 2), complex(inf, -inf)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(inf, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(inf, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(inf, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(0, 0), complex(-inf, -nan)}, + Test{complex(-inf, 0), complex(0, 1), complex(-nan, inf)}, + Test{complex(-inf, 0), complex(0, -1), complex(-nan, -inf)}, + Test{complex(-inf, 0), complex(0, 2), complex(-nan, inf)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(1, 0), complex(-inf, -nan)}, + Test{complex(-inf, 0), complex(1, 1), complex(-inf, inf)}, + Test{complex(-inf, 0), complex(1, -1), complex(-inf, -inf)}, + Test{complex(-inf, 0), complex(1, 2), complex(-inf, inf)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-1, 0), complex(inf, -nan)}, + Test{complex(-inf, 0), complex(-1, 1), complex(inf, inf)}, + Test{complex(-inf, 0), complex(-1, -1), complex(inf, -inf)}, + Test{complex(-inf, 0), complex(-1, 2), complex(inf, inf)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(2, 0), complex(-inf, -nan)}, + Test{complex(-inf, 0), complex(2, 1), complex(-inf, inf)}, + Test{complex(-inf, 0), complex(2, -1), complex(-inf, -inf)}, + Test{complex(-inf, 0), complex(2, 2), complex(-inf, inf)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(nan, 0), complex(nan, nan)}, + Test{complex(-inf, 0), complex(nan, 1), complex(nan, nan)}, + Test{complex(-inf, 0), complex(nan, -1), complex(nan, nan)}, + Test{complex(-inf, 0), complex(nan, 2), complex(nan, nan)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 0), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 0), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(0, 0), complex(-inf, inf)}, + Test{complex(-inf, 1), complex(0, 1), complex(-nan, inf)}, + Test{complex(-inf, 1), complex(0, -1), complex(-nan, -inf)}, + Test{complex(-inf, 1), complex(0, 2), complex(-nan, inf)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(1, 0), complex(-inf, -nan)}, + Test{complex(-inf, 1), complex(1, 1), complex(-inf, inf)}, + Test{complex(-inf, 1), complex(1, -1), complex(-inf, -inf)}, + Test{complex(-inf, 1), complex(1, 2), complex(-inf, inf)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-1, 0), complex(inf, -nan)}, + Test{complex(-inf, 1), complex(-1, 1), complex(inf, inf)}, + Test{complex(-inf, 1), complex(-1, -1), complex(inf, -inf)}, + Test{complex(-inf, 1), complex(-1, 2), complex(inf, inf)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(2, 0), complex(-inf, -nan)}, + Test{complex(-inf, 1), complex(2, 1), complex(-inf, inf)}, + Test{complex(-inf, 1), complex(2, -1), complex(-inf, -inf)}, + Test{complex(-inf, 1), complex(2, 2), complex(-inf, inf)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(nan, 0), complex(nan, nan)}, + Test{complex(-inf, 1), complex(nan, 1), complex(nan, nan)}, + Test{complex(-inf, 1), complex(nan, -1), complex(nan, nan)}, + Test{complex(-inf, 1), complex(nan, 2), complex(nan, nan)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(0, 0), complex(-inf, -inf)}, + Test{complex(-inf, -1), complex(0, 1), complex(-nan, inf)}, + Test{complex(-inf, -1), complex(0, -1), complex(-nan, -inf)}, + Test{complex(-inf, -1), complex(0, 2), complex(-nan, inf)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(1, 0), complex(-inf, -nan)}, + Test{complex(-inf, -1), complex(1, 1), complex(-inf, inf)}, + Test{complex(-inf, -1), complex(1, -1), complex(-inf, -inf)}, + Test{complex(-inf, -1), complex(1, 2), complex(-inf, inf)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-1, 0), complex(inf, -nan)}, + Test{complex(-inf, -1), complex(-1, 1), complex(inf, inf)}, + Test{complex(-inf, -1), complex(-1, -1), complex(inf, -inf)}, + Test{complex(-inf, -1), complex(-1, 2), complex(inf, inf)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(2, 0), complex(-inf, -nan)}, + Test{complex(-inf, -1), complex(2, 1), complex(-inf, inf)}, + Test{complex(-inf, -1), complex(2, -1), complex(-inf, -inf)}, + Test{complex(-inf, -1), complex(2, 2), complex(-inf, inf)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(nan, 0), complex(nan, nan)}, + Test{complex(-inf, -1), complex(nan, 1), complex(nan, nan)}, + Test{complex(-inf, -1), complex(nan, -1), complex(nan, nan)}, + Test{complex(-inf, -1), complex(nan, 2), complex(nan, nan)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, -1), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, -1), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(0, 0), complex(-inf, inf)}, + Test{complex(-inf, 2), complex(0, 1), complex(-nan, inf)}, + Test{complex(-inf, 2), complex(0, -1), complex(-nan, -inf)}, + Test{complex(-inf, 2), complex(0, 2), complex(-nan, inf)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(1, 0), complex(-inf, -nan)}, + Test{complex(-inf, 2), complex(1, 1), complex(-inf, inf)}, + Test{complex(-inf, 2), complex(1, -1), complex(-inf, -inf)}, + Test{complex(-inf, 2), complex(1, 2), complex(-inf, inf)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-1, 0), complex(inf, -nan)}, + Test{complex(-inf, 2), complex(-1, 1), complex(inf, inf)}, + Test{complex(-inf, 2), complex(-1, -1), complex(inf, -inf)}, + Test{complex(-inf, 2), complex(-1, 2), complex(inf, inf)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(2, 0), complex(-inf, -nan)}, + Test{complex(-inf, 2), complex(2, 1), complex(-inf, inf)}, + Test{complex(-inf, 2), complex(2, -1), complex(-inf, -inf)}, + Test{complex(-inf, 2), complex(2, 2), complex(-inf, inf)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(nan, 0), complex(nan, nan)}, + Test{complex(-inf, 2), complex(nan, 1), complex(nan, nan)}, + Test{complex(-inf, 2), complex(nan, -1), complex(nan, nan)}, + Test{complex(-inf, 2), complex(nan, 2), complex(nan, nan)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(nan, nan), complex(nan, nan)}, + Test{complex(-inf, 2), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-inf, 2), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(nan, nan), complex(0, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(0, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-1, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(2, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 0), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, -1), complex(nan, nan)}, + Test{complex(nan, nan), complex(-inf, 2), complex(nan, nan)}, + Test{complex(nan, nan), complex(nan, nan), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, inf), complex(nan, nan)}, + Test{complex(nan, nan), complex(-nan, -inf), complex(nan, nan)}, + Test{complex(-nan, inf), complex(0, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(0, 1), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(0, -1), complex(-inf, -nan)}, + Test{complex(-nan, inf), complex(0, 2), complex(inf, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(1, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(1, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(1, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(1, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-1, 0), complex(-nan, -inf)}, + Test{complex(-nan, inf), complex(-1, 1), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(-1, -1), complex(-inf, -inf)}, + Test{complex(-nan, inf), complex(-1, 2), complex(inf, -inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(2, 0), complex(-nan, inf)}, + Test{complex(-nan, inf), complex(2, 1), complex(inf, inf)}, + Test{complex(-nan, inf), complex(2, -1), complex(-inf, inf)}, + Test{complex(-nan, inf), complex(2, 2), complex(inf, inf)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(0, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(0, 1), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(0, -1), complex(inf, -nan)}, + Test{complex(-nan, -inf), complex(0, 2), complex(-inf, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(1, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(1, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(1, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(1, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-1, 0), complex(-nan, inf)}, + Test{complex(-nan, -inf), complex(-1, 1), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(-1, -1), complex(inf, inf)}, + Test{complex(-nan, -inf), complex(-1, 2), complex(-inf, inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(2, 0), complex(-nan, -inf)}, + Test{complex(-nan, -inf), complex(2, 1), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(2, -1), complex(inf, -inf)}, + Test{complex(-nan, -inf), complex(2, 2), complex(-inf, -inf)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, 0), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, -1), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, 2), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 0), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, -1), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-inf, 2), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(nan, nan), complex(nan, nan)}, + Test{complex(-nan, -inf), complex(-nan, inf), complex(-nan, -nan)}, + Test{complex(-nan, -inf), complex(-nan, -inf), complex(-nan, -nan)}, } diff --git a/test/complit.go b/test/complit.go index f3b7c9abe..f5f7aca9d 100644 --- a/test/complit.go +++ b/test/complit.go @@ -6,9 +6,16 @@ package main -type T struct { i int; f float; s string; next *T } +type T struct { + i int + f float64 + s string + next *T +} -type R struct { num int } +type R struct { + num int +} func itor(a int) *R { r := new(R) @@ -18,11 +25,16 @@ func itor(a int) *R { func eq(a []*R) { for i := 0; i < len(a); i++ { - if a[i].num != i { panic("bad") } + if a[i].num != i { + panic("bad") + } } } -type P struct { a, b int } +type P struct { + a, b int +} + func NewP(a, b int) *P { return &P{a, b} } @@ -34,37 +46,57 @@ func main() { var tp *T tp = &T{0, 7.2, "hi", &t} - a1 := []int{1,2,3} - if len(a1) != 3 { panic("a1") } - a2 := [10]int{1,2,3} - if len(a2) != 10 || cap(a2) != 10 { panic("a2") } + a1 := []int{1, 2, 3} + if len(a1) != 3 { + panic("a1") + } + a2 := [10]int{1, 2, 3} + if len(a2) != 10 || cap(a2) != 10 { + panic("a2") + } - a3 := [10]int{1,2,3,} - if len(a3) != 10 || a2[3] != 0 { panic("a3") } + a3 := [10]int{1, 2, 3} + if len(a3) != 10 || a2[3] != 0 { + panic("a3") + } var oai []int - oai = []int{1,2,3} - if len(oai) != 3 { panic("oai") } + oai = []int{1, 2, 3} + if len(oai) != 3 { + panic("oai") + } at := [...]*T{&t, tp, &t} - if len(at) != 3 { panic("at") } + if len(at) != 3 { + panic("at") + } c := make(chan int) ac := []chan int{c, c, c} - if len(ac) != 3 { panic("ac") } + if len(ac) != 3 { + panic("ac") + } aat := [][len(at)]*T{at, at} - if len(aat) != 2 || len(aat[1]) != 3 { panic("aat") } + if len(aat) != 2 || len(aat[1]) != 3 { + panic("aat") + } s := string([]byte{'h', 'e', 'l', 'l', 'o'}) - if s != "hello" { panic("s") } + if s != "hello" { + panic("s") + } - m := map[string]float{"one":1.0, "two":2.0, "pi":22./7.} - if len(m) != 3 { panic("m") } + m := map[string]float64{"one": 1.0, "two": 2.0, "pi": 22. / 7.} + if len(m) != 3 { + panic("m") + } eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)}) p1 := NewP(1, 2) p2 := NewP(1, 2) - if p1 == p2 { panic("NewP") } + if p1 == p2 { + panic("NewP") + } } diff --git a/test/const1.go b/test/const1.go index cf07055cf..67f36e4fd 100644 --- a/test/const1.go +++ b/test/const1.go @@ -6,76 +6,77 @@ package main -type I interface {} +type I interface{} + const ( // assume all types behave similarly to int8/uint8 - Int8 int8 = 101 - Minus1 int8 = -1 - Uint8 uint8 = 102 - Const = 103 + Int8 int8 = 101 + Minus1 int8 = -1 + Uint8 uint8 = 102 + Const = 103 - Float32 float32 = 104.5 - Float float = 105.5 + Float32 float32 = 104.5 + Float64 float64 = 105.5 ConstFloat = 106.5 - Big float64 = 1e300 + Big float64 = 1e300 String = "abc" - Bool = true + Bool = true ) var ( - a1 = Int8 * 100 // ERROR "overflow" - a2 = Int8 * -1 // OK - a3 = Int8 * 1000 // ERROR "overflow" - a4 = Int8 * int8(1000) // ERROR "overflow" - a5 = int8(Int8 * 1000) // ERROR "overflow" - a6 = int8(Int8 * int8(1000)) // ERROR "overflow" - a7 = Int8 - 2*Int8 - 2*Int8 // ERROR "overflow" - a8 = Int8 * Const / 100 // ERROR "overflow" - a9 = Int8 * (Const / 100) // OK + a1 = Int8 * 100 // ERROR "overflow" + a2 = Int8 * -1 // OK + a3 = Int8 * 1000 // ERROR "overflow" + a4 = Int8 * int8(1000) // ERROR "overflow" + a5 = int8(Int8 * 1000) // ERROR "overflow" + a6 = int8(Int8 * int8(1000)) // ERROR "overflow" + a7 = Int8 - 2*Int8 - 2*Int8 // ERROR "overflow" + a8 = Int8 * Const / 100 // ERROR "overflow" + a9 = Int8 * (Const / 100) // OK - b1 = Uint8 * Uint8 // ERROR "overflow" - b2 = Uint8 * -1 // ERROR "overflow" - b3 = Uint8 - Uint8 // OK - b4 = Uint8 - Uint8 - Uint8 // ERROR "overflow" - b5 = uint8(^0) // ERROR "overflow" - b6 = ^uint8(0) // OK - b7 = uint8(Minus1) // ERROR "overflow" - b8 = uint8(int8(-1)) // ERROR "overflow" - b8a = uint8(-1) // ERROR "overflow" - b9 byte = (1<<10) >> 8 // OK - b10 byte = (1<<10) // ERROR "overflow" - b11 byte = (byte(1)<<10) >> 8 // ERROR "overflow" - b12 byte = 1000 // ERROR "overflow" - b13 byte = byte(1000) // ERROR "overflow" - b14 byte = byte(100) * byte(100) // ERROR "overflow" - b15 byte = byte(100) * 100 // ERROR "overflow" - b16 byte = byte(0) * 1000 // ERROR "overflow" - b16a byte = 0 * 1000 // OK - b17 byte = byte(0) * byte(1000) // ERROR "overflow" - b18 byte = Uint8/0 // ERROR "division by zero" + b1 = Uint8 * Uint8 // ERROR "overflow" + b2 = Uint8 * -1 // ERROR "overflow" + b3 = Uint8 - Uint8 // OK + b4 = Uint8 - Uint8 - Uint8 // ERROR "overflow" + b5 = uint8(^0) // ERROR "overflow" + b6 = ^uint8(0) // OK + b7 = uint8(Minus1) // ERROR "overflow" + b8 = uint8(int8(-1)) // ERROR "overflow" + b8a = uint8(-1) // ERROR "overflow" + b9 byte = (1 << 10) >> 8 // OK + b10 byte = (1 << 10) // ERROR "overflow" + b11 byte = (byte(1) << 10) >> 8 // ERROR "overflow" + b12 byte = 1000 // ERROR "overflow" + b13 byte = byte(1000) // ERROR "overflow" + b14 byte = byte(100) * byte(100) // ERROR "overflow" + b15 byte = byte(100) * 100 // ERROR "overflow" + b16 byte = byte(0) * 1000 // ERROR "overflow" + b16a byte = 0 * 1000 // OK + b17 byte = byte(0) * byte(1000) // ERROR "overflow" + b18 byte = Uint8 / 0 // ERROR "division by zero" - c1 float64 = Big - c2 float64 = Big*Big // ERROR "overflow" - c3 float64 = float64(Big)*Big // ERROR "overflow" - c4 = Big*Big // ERROR "overflow" - c5 = Big/0 // ERROR "division by zero" + c1 float64 = Big + c2 float64 = Big * Big // ERROR "overflow" + c3 float64 = float64(Big) * Big // ERROR "overflow" + c4 = Big * Big // ERROR "overflow" + c5 = Big / 0 // ERROR "division by zero" ) func f(int) func main() { - f(Int8) // ERROR "convert|wrong type|cannot" - f(Minus1) // ERROR "convert|wrong type|cannot" - f(Uint8) // ERROR "convert|wrong type|cannot" - f(Const) // OK - f(Float32) // ERROR "convert|wrong type|cannot" - f(Float) // ERROR "convert|wrong type|cannot" - f(ConstFloat) // ERROR "truncate" - f(ConstFloat - 0.5) // OK - f(Big) // ERROR "convert|wrong type|cannot" - f(String) // ERROR "convert|wrong type|cannot|incompatible" - f(Bool) // ERROR "convert|wrong type|cannot|incompatible" + f(Int8) // ERROR "convert|wrong type|cannot" + f(Minus1) // ERROR "convert|wrong type|cannot" + f(Uint8) // ERROR "convert|wrong type|cannot" + f(Const) // OK + f(Float32) // ERROR "convert|wrong type|cannot" + f(Float64) // ERROR "convert|wrong type|cannot" + f(ConstFloat) // ERROR "truncate" + f(ConstFloat - 0.5) // OK + f(Big) // ERROR "convert|wrong type|cannot" + f(String) // ERROR "convert|wrong type|cannot|incompatible" + f(Bool) // ERROR "convert|wrong type|cannot|incompatible" } -const ptr = nil // ERROR "const.*nil" +const ptr = nil // ERROR "const.*nil" diff --git a/test/convlit.go b/test/convlit.go index 94889d4a9..90ac5490c 100644 --- a/test/convlit.go +++ b/test/convlit.go @@ -11,54 +11,56 @@ package main // the language spec says for now. var x1 = string(1) var x2 string = string(1) -var x3 = int(1.5) // ERROR "convert|truncate" -var x4 int = int(1.5) // ERROR "convert|truncate" +var x3 = int(1.5) // ERROR "convert|truncate" +var x4 int = int(1.5) // ERROR "convert|truncate" var x5 = "a" + string(1) -var x6 = int(1e100) // ERROR "overflow" -var x7 = float(1e1000) // ERROR "overflow" +var x6 = int(1e100) // ERROR "overflow" +var x7 = float32(1e1000) // ERROR "overflow" // implicit conversions merit scrutiny var s string -var bad1 string = 1 // ERROR "conver|incompatible|invalid|cannot" -var bad2 = s + 1 // ERROR "conver|incompatible|invalid" -var bad3 = s + 'a' // ERROR "conver|incompatible|invalid" -var bad4 = "a" + 1 // ERROR "literals|incompatible|convert|invalid" -var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid" +var bad1 string = 1 // ERROR "conver|incompatible|invalid|cannot" +var bad2 = s + 1 // ERROR "conver|incompatible|invalid" +var bad3 = s + 'a' // ERROR "conver|incompatible|invalid" +var bad4 = "a" + 1 // ERROR "literals|incompatible|convert|invalid" +var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid" -var bad6 int = 1.5 // ERROR "convert|truncate" -var bad7 int = 1e100 // ERROR "overflow" -var bad8 float32 = 1e200 // ERROR "overflow" +var bad6 int = 1.5 // ERROR "convert|truncate" +var bad7 int = 1e100 // ERROR "overflow" +var bad8 float32 = 1e200 // ERROR "overflow" // but these implicit conversions are okay var good1 string = "a" var good2 int = 1.0 var good3 int = 1e9 -var good4 float = 1e20 +var good4 float64 = 1e20 // explicit conversion of string is okay var _ = []int("abc") var _ = []byte("abc") // implicit is not -var _ []int = "abc" // ERROR "cannot use|incompatible|invalid" -var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid" +var _ []int = "abc" // ERROR "cannot use|incompatible|invalid" +var _ []byte = "abc" // ERROR "cannot use|incompatible|invalid" // named string is okay type Tstring string + var ss Tstring = "abc" var _ = []int(ss) var _ = []byte(ss) // implicit is still not -var _ []int = ss // ERROR "cannot use|incompatible|invalid" -var _ []byte = ss // ERROR "cannot use|incompatible|invalid" +var _ []int = ss // ERROR "cannot use|incompatible|invalid" +var _ []byte = ss // ERROR "cannot use|incompatible|invalid" // named slice is not type Tint []int type Tbyte []byte -var _ = Tint("abc") // ERROR "convert|incompatible|invalid" -var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid" + +var _ = Tint("abc") // ERROR "convert|incompatible|invalid" +var _ = Tbyte("abc") // ERROR "convert|incompatible|invalid" // implicit is still not -var _ Tint = "abc" // ERROR "cannot use|incompatible|invalid" -var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid" +var _ Tint = "abc" // ERROR "cannot use|incompatible|invalid" +var _ Tbyte = "abc" // ERROR "cannot use|incompatible|invalid" diff --git a/test/decl.go b/test/decl.go index c31082bcf..95b6346c3 100644 --- a/test/decl.go +++ b/test/decl.go @@ -8,26 +8,26 @@ package main -func f1() int { return 1 } -func f2() (float, int) { return 1, 2 } -func f3() (float, int, string) { return 1, 2, "3" } +func f1() int { return 1 } +func f2() (float32, int) { return 1, 2 } +func f3() (float32, int, string) { return 1, 2, "3" } func x() (s string) { a, b, s := f3() _, _ = a, b - return // tests that result var is in scope for redeclaration + return // tests that result var is in scope for redeclaration } func main() { i, f, s := f3() - j, f := f2() // redeclare f + j, f := f2() // redeclare f k := f1() m, g, s := f3() m, h, s := f3() { // new block should be ok. i, f, s := f3() - j, f := f2() // redeclare f + j, f := f2() // redeclare f k := f1() m, g, s := f3() m, h, s := f3() diff --git a/test/declbad.go b/test/declbad.go index 269ebdefb..5e5e14501 100644 --- a/test/declbad.go +++ b/test/declbad.go @@ -8,51 +8,51 @@ package main -func f1() int { return 1 } -func f2() (float, int) { return 1, 2 } -func f3() (float, int, string) { return 1, 2, "3" } +func f1() int { return 1 } +func f2() (float32, int) { return 1, 2 } +func f3() (float32, int, string) { return 1, 2, "3" } func main() { { // simple redeclaration i := f1() - i := f1() // ERROR "redeclared|no new" + i := f1() // ERROR "redeclared|no new" _ = i } { // change of type for f i, f, s := f3() - f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible" + f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible" _, _, _, _, _ = i, f, s, g, t } { // change of type for i i, f, s := f3() - j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible" + j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible" _, _, _, _, _ = i, f, s, j, t } { // no new variables i, f, s := f3() - i, f := f2() // ERROR "redeclared|no new" + i, f := f2() // ERROR "redeclared|no new" _, _, _ = i, f, s } { // single redeclaration i, f, s := f3() - i := f1() // ERROR "redeclared|no new|incompatible" + i := f1() // ERROR "redeclared|no new|incompatible" _, _, _ = i, f, s } - // double redeclaration + // double redeclaration { i, f, s := f3() - i, f := f2() // ERROR "redeclared|no new" + i, f := f2() // ERROR "redeclared|no new" _, _, _ = i, f, s } { // triple redeclaration i, f, s := f3() - i, f, s := f3() // ERROR "redeclared|no new" + i, f, s := f3() // ERROR "redeclared|no new" _, _, _ = i, f, s } } diff --git a/test/errchk b/test/errchk index b0edd7a6b..fbb021ce4 100755 --- a/test/errchk +++ b/test/errchk @@ -73,6 +73,7 @@ sub chk { my @match; foreach my $src (@{$src{$file}}) { $line++; + next if $src =~ m|////|; # double comment disables ERROR next unless $src =~ m|// (GC_)?ERROR (.*)|; $regexp = $2; if($regexp !~ /^"([^"]*)"/) { diff --git a/test/fixedbugs/bug006.go b/test/fixedbugs/bug006.go index e7694f95b..43b5dfb12 100644 --- a/test/fixedbugs/bug006.go +++ b/test/fixedbugs/bug006.go @@ -9,11 +9,16 @@ package main import "os" const ( - x float = iota; - g float = 4.5 * iota; -); + x float64 = iota + g float64 = 4.5 * iota +) func main() { - if g == 0.0 { print("zero\n");} - if g != 4.5 { print(" fail\n"); os.Exit(1); } + if g == 0.0 { + print("zero\n") + } + if g != 4.5 { + print(" fail\n") + os.Exit(1) + } } diff --git a/test/fixedbugs/bug007.go b/test/fixedbugs/bug007.go index bd970de5f..d65f6da45 100644 --- a/test/fixedbugs/bug007.go +++ b/test/fixedbugs/bug007.go @@ -7,7 +7,9 @@ package main type ( - Point struct { x, y float }; + Point struct { + x, y float64 + } Polar Point ) diff --git a/test/fixedbugs/bug010.go b/test/fixedbugs/bug010.go index e71c4d7f0..7d96988d4 100644 --- a/test/fixedbugs/bug010.go +++ b/test/fixedbugs/bug010.go @@ -7,14 +7,14 @@ package main -func f(i int, f float) { - i = 8; - f = 8.0; - return; +func f(i int, f float64) { + i = 8 + f = 8.0 + return } func main() { - f(3, float(5)) + f(3, float64(5)) } /* diff --git a/test/fixedbugs/bug011.go b/test/fixedbugs/bug011.go index 551adb77d..ce627472c 100644 --- a/test/fixedbugs/bug011.go +++ b/test/fixedbugs/bug011.go @@ -8,19 +8,19 @@ package main type T struct { - x, y int; + x, y int } -func (t *T) m(a int, b float) int { - return (t.x+a) * (t.y+int(b)); +func (t *T) m(a int, b float64) int { + return (t.x + a) * (t.y + int(b)) } func main() { - var t *T = new(T); - t.x = 1; - t.y = 2; - r10 := t.m(1, 3.0); - _ = r10; + var t *T = new(T) + t.x = 1 + t.y = 2 + r10 := t.m(1, 3.0) + _ = r10 } /* bug11.go:16: fatal error: walktype: switch 1 unknown op CALLMETH l(16) <int32>INT32 diff --git a/test/fixedbugs/bug016.go b/test/fixedbugs/bug016.go index 461bcf82a..1cdd8df08 100644 --- a/test/fixedbugs/bug016.go +++ b/test/fixedbugs/bug016.go @@ -1,4 +1,4 @@ -// ! $G $D/$F.go +// errchk $G -e $D/$F.go // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -7,8 +7,8 @@ package main func main() { - var i int = 100; - i = i << -3; // BUG: should not compile (negative shift) + var i int = 100 + i = i << -3 // ERROR "overflows" } /* diff --git a/test/fixedbugs/bug035.go b/test/fixedbugs/bug035.go index 461c0607a..bd2a633f2 100644 --- a/test/fixedbugs/bug035.go +++ b/test/fixedbugs/bug035.go @@ -6,8 +6,8 @@ package main -func f9(a int) (i int, f float) { - i := 9; // ERROR "redecl|no new" - f := float(9); // ERROR "redecl|no new" - return i, f; +func f9(a int) (i int, f float64) { + i := 9 // ERROR "redecl|no new" + f := float64(9) // ERROR "redecl|no new" + return i, f } diff --git a/test/fixedbugs/bug047.go b/test/fixedbugs/bug047.go index f3749e739..5a776abce 100644 --- a/test/fixedbugs/bug047.go +++ b/test/fixedbugs/bug047.go @@ -9,15 +9,15 @@ package main func main() { type T struct { - s string; - f float; - }; - var s string = "hello"; - var f float = 0.2; - t := T{s, f}; + s string + f float64 + } + var s string = "hello" + var f float64 = 0.2 + t := T{s, f} - type M map[int] int; - m0 := M{7:8}; + type M map[int]int + m0 := M{7: 8} - _, _ = t, m0; + _, _ = t, m0 } diff --git a/test/fixedbugs/bug069.go b/test/fixedbugs/bug069.go index d6796cd72..bf7316313 100644 --- a/test/fixedbugs/bug069.go +++ b/test/fixedbugs/bug069.go @@ -6,15 +6,16 @@ package main -func main(){ - c := make(chan int); - ok := false; - var i int; - - i, ok = <-c; // works - _, _ = i, ok; - - ca := new([2]chan int); - i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2 - _, _ = i, ok; +func main() { + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // c := make(chan int); + // ok := false; + // var i int; + // + // i, ok = <-c; // works + // _, _ = i, ok; + // + // ca := new([2]chan int); + // i, ok = <-(ca[0]); // fails: c.go:11: bad shape across assignment - cr=1 cl=2 + // _, _ = i, ok; } diff --git a/test/fixedbugs/bug080.go b/test/fixedbugs/bug080.go index a5003d29b..bae16cdb2 100644 --- a/test/fixedbugs/bug080.go +++ b/test/fixedbugs/bug080.go @@ -4,18 +4,18 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package main - -func f1() (x int, y float) { - return; +package main + +func f1() (x int, y float64) { + return } -func f2 (x int, y float) { - return; +func f2(x int, y float64) { + return } func main() { - f2(f1()); // this should be a legal call + f2(f1()) // this should be a legal call } /* diff --git a/test/fixedbugs/bug081.go b/test/fixedbugs/bug081.go index ccb369953..8d3d538c8 100644 --- a/test/fixedbugs/bug081.go +++ b/test/fixedbugs/bug081.go @@ -1,12 +1,12 @@ -// ! $G $D/$F.go +// errchk $G $D/$F.go // Copyright 2009 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. -package main - -const x x = 2; +package main + +const x x = 2 // ERROR "loop" /* bug081.go:3: first constant must evaluate an expression diff --git a/test/fixedbugs/bug109.go b/test/fixedbugs/bug109.go index c679771f2..766657723 100644 --- a/test/fixedbugs/bug109.go +++ b/test/fixedbugs/bug109.go @@ -5,10 +5,11 @@ // license that can be found in the LICENSE file. package main -func f(a float) float { - e := 1.0; - e = e * a; - return e; + +func f(a float64) float64 { + e := 1.0 + e = e * a + return e } /* diff --git a/test/fixedbugs/bug167.go b/test/fixedbugs/bug167.go index 729299b66..33eb3cb1a 100644 --- a/test/fixedbugs/bug167.go +++ b/test/fixedbugs/bug167.go @@ -7,20 +7,24 @@ package main func f1() { - type T struct { x int } + type T struct { + x int + } } func f2() { - type T struct { x float } + type T struct { + x float64 + } } func main() { - f1(); - f2(); + f1() + f2() } /* 1606416576: conflicting definitions for main.T·bug167 bug167.6: type main.T·bug167 struct { x int } -bug167.6: type main.T·bug167 struct { x float } +bug167.6: type main.T·bug167 struct { x float64 } */ diff --git a/test/fixedbugs/bug193.go b/test/fixedbugs/bug193.go index f6b03e13d..5ef02b1c1 100644 --- a/test/fixedbugs/bug193.go +++ b/test/fixedbugs/bug193.go @@ -7,10 +7,10 @@ package main func main() { - s := uint(10); - ss := 1<<s; - y1 := float(ss); - y2 := float(1<<s); // ERROR "shift" - y3 := string(1<<s); // ERROR "shift" - _, _, _, _, _ = s, ss, y1, y2, y3; + s := uint(10) + ss := 1 << s + y1 := float64(ss) + y2 := float64(1 << s) // ERROR "shift" + y3 := string(1 << s) // ERROR "shift" + _, _, _, _, _ = s, ss, y1, y2, y3 } diff --git a/test/fixedbugs/bug196.go b/test/fixedbugs/bug196.go index ea8ab0dc1..8cb9c9990 100644 --- a/test/fixedbugs/bug196.go +++ b/test/fixedbugs/bug196.go @@ -13,11 +13,12 @@ var i int func multi() (int, int) { return 1, 2 } func xxx() { - var c chan int - x, ok := <-c + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // var c chan int + // x, ok := <-c var m map[int]int - x, ok = m[1] + x, ok := m[1] var i interface{} var xx int diff --git a/test/fixedbugs/bug220.go b/test/fixedbugs/bug220.go index 3f8aaa4ec..ff027ddc2 100644 --- a/test/fixedbugs/bug220.go +++ b/test/fixedbugs/bug220.go @@ -7,8 +7,8 @@ package main func main() { - m := make(map[int]map[uint]float); - - m[0] = make(map[uint]float), false; // 6g used to reject this - m[1] = nil; + m := make(map[int]map[uint]float64) + + m[0] = make(map[uint]float64), false // 6g used to reject this + m[1] = nil } diff --git a/test/fixedbugs/bug230.go b/test/fixedbugs/bug230.go index 81b256e31..c7ad1a366 100644 --- a/test/fixedbugs/bug230.go +++ b/test/fixedbugs/bug230.go @@ -8,14 +8,17 @@ package main type S string type I int -type F float +type F float64 func (S) m() {} func (I) m() {} func (F) m() {} func main() { - c := make(chan interface { m() }, 10) + c := make(chan interface { + m() + }, + 10) c <- I(0) c <- F(1) c <- S("hi") diff --git a/test/fixedbugs/bug234.go b/test/fixedbugs/bug234.go index b806ca64e..9affad043 100644 --- a/test/fixedbugs/bug234.go +++ b/test/fixedbugs/bug234.go @@ -7,16 +7,17 @@ package main func main() { - c := make(chan int, 1) - c <- 100 - x, ok := <-c - if x != 100 || !ok { - println("x=", x, " ok=", ok, " want 100, true") - panic("fail") - } - x, ok = <-c - if x != 0 || ok { - println("x=", x, " ok=", ok, " want 0, false") - panic("fail") - } + //TODO(rsc): uncomment when this syntax is valid for receive+check closed + // c := make(chan int, 1) + // c <- 100 + // x, ok := <-c + // if x != 100 || !ok { + // println("x=", x, " ok=", ok, " want 100, true") + // panic("fail") + // } + // x, ok = <-c + // if x != 0 || ok { + // println("x=", x, " ok=", ok, " want 0, false") + // panic("fail") + // } } diff --git a/test/fixedbugs/bug238.go b/test/fixedbugs/bug238.go index 8b7c7ac38..7e8660d37 100644 --- a/test/fixedbugs/bug238.go +++ b/test/fixedbugs/bug238.go @@ -17,6 +17,6 @@ const f struct{} = 6 // ERROR "convert|wrong|invalid" const g interface{} = 7 // ERROR "constant|wrong|invalid" const h bool = false const i int = 2 -const j float = 5 +const j float64 = 5 func main() { println(a, b, c, d, e, f, g) } diff --git a/test/fixedbugs/bug242.go b/test/fixedbugs/bug242.go index 5c21eaaf0..ad1cef8df 100644 --- a/test/fixedbugs/bug242.go +++ b/test/fixedbugs/bug242.go @@ -101,10 +101,13 @@ func main() { c := make(chan byte, 1) c <- 'C' + //TODO(rsc): uncomment when this syntax is valid for receive+check closed // 15 16 - *f(), p1 = <-e1(c, 16) + // *f(), p1 = <-e1(c, 16) + *f(), p1 = <-e1(c, 16), true // delete uncommenting above // 17 18 - *f(), p2 = <-e1(c, 18) + // *f(), p2 = <-e1(c, 18) + *f(), p2, _ = 0, false, e1(c, 18) // delete when uncommenting above a[17] += '0' if !p1 || p2 { println("bad chan check", i, p1, p2) diff --git a/test/fixedbugs/bug248.dir/bug2.go b/test/fixedbugs/bug248.dir/bug2.go index 68c0ce0bc..4ea187a4b 100644 --- a/test/fixedbugs/bug248.dir/bug2.go +++ b/test/fixedbugs/bug248.dir/bug2.go @@ -23,7 +23,7 @@ type t0 int func (t0) M(p0.T) {} -type t1 float +type t1 float64 func (t1) M(p1.T) {} diff --git a/test/fixedbugs/bug248.dir/bug3.go b/test/fixedbugs/bug248.dir/bug3.go index c96bf1676..e5a244955 100644 --- a/test/fixedbugs/bug248.dir/bug3.go +++ b/test/fixedbugs/bug248.dir/bug3.go @@ -26,7 +26,7 @@ type t0 int func (t0) M(p0.T) {} // t1 satisfies I1 and p1.I -type t1 float +type t1 float64 func (t1) M(p1.T) {} diff --git a/test/fixedbugs/bug299.go b/test/fixedbugs/bug299.go index 4d7314432..1c7adb5f5 100644 --- a/test/fixedbugs/bug299.go +++ b/test/fixedbugs/bug299.go @@ -11,9 +11,9 @@ type T struct { x int y (int) int - *float + *float64 // not legal according to spec - (complex) // ERROR "non-declaration|expected|parenthesize" + (complex128) // ERROR "non-declaration|expected|parenthesize" (*string) // ERROR "non-declaration|expected|parenthesize" *(bool) // ERROR "non-declaration|expected|parenthesize" } diff --git a/test/fixedbugs/bug307.go b/test/fixedbugs/bug307.go index a1a30dfb7..1b42c09ab 100644 --- a/test/fixedbugs/bug307.go +++ b/test/fixedbugs/bug307.go @@ -5,11 +5,11 @@ // license that can be found in the LICENSE file. // Valid program, gccgo reported an error. -// bug307.go:14:6: error: cmplx arguments must have identical types +// bug307.go:14:6: error: complex arguments must have identical types package main func main() { var f float64 - _ = cmplx(1 / f, 0) + _ = complex(1/f, 0) } diff --git a/test/fixedbugs/bug315.go b/test/fixedbugs/bug315.go index 198bae77a..c59ef29e6 100644 --- a/test/fixedbugs/bug315.go +++ b/test/fixedbugs/bug315.go @@ -9,7 +9,7 @@ package main func main() { - a := cmplx(2, 2) + a := complex(2, 2) a /= 2 } diff --git a/test/fixedbugs/bug316.go b/test/fixedbugs/bug316.go index bd4d99eb6..2146408a1 100644 --- a/test/fixedbugs/bug316.go +++ b/test/fixedbugs/bug316.go @@ -9,7 +9,7 @@ package main const ( - c = cmplx(1, 2) + c = complex(1, 2) r = real(c) // was: const initializer must be constant i = imag(c) // was: const initializer must be constant ) diff --git a/test/fixedbugs/bug318.go b/test/fixedbugs/bug318.go new file mode 100644 index 000000000..9c46a0426 --- /dev/null +++ b/test/fixedbugs/bug318.go @@ -0,0 +1,12 @@ +// errchk $G $D/$F.go + +// Copyright 2011 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. + +// Issue 1411. + +package main + +const ui uint = 0 +const i int = ui // ERROR "type" diff --git a/test/fixedbugs/bug319.go b/test/fixedbugs/bug319.go new file mode 100644 index 000000000..f60eee4fb --- /dev/null +++ b/test/fixedbugs/bug319.go @@ -0,0 +1,22 @@ +// $G $D/$F.go + +// Copyright 2011 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. + +package main + +import "unsafe" + +func main() { + var x int + + a := uint64(uintptr(unsafe.Pointer(&x))) + b := uint32(uintptr(unsafe.Pointer(&x))) + c := uint16(uintptr(unsafe.Pointer(&x))) + d := int64(uintptr(unsafe.Pointer(&x))) + e := int32(uintptr(unsafe.Pointer(&x))) + f := int16(uintptr(unsafe.Pointer(&x))) + + _, _, _, _, _, _ = a, b, c, d, e, f +} diff --git a/test/func.go b/test/func.go index 0c1a07979..e8ed928bc 100644 --- a/test/func.go +++ b/test/func.go @@ -21,10 +21,10 @@ func f2(a int) { } func f3(a, b int) int { - return a+b + return a + b } -func f4(a, b int, c float) int { +func f4(a, b int, c float32) int { return (a+b)/2 + int(c) } @@ -36,12 +36,12 @@ func f6(a int) (r int) { return 6 } -func f7(a int) (x int, y float) { +func f7(a int) (x int, y float32) { return 7, 7.0 } -func f8(a int) (x int, y float) { +func f8(a int) (x int, y float32) { return 8, 8.0 } @@ -49,12 +49,12 @@ type T struct { x, y int } -func (t *T) m10(a int, b float) int { - return (t.x+a) * (t.y+int(b)) +func (t *T) m10(a int, b float32) int { + return (t.x + a) * (t.y + int(b)) } -func f9(a int) (i int, f float) { +func f9(a int) (i int, f float32) { i = 9 f = 9.0 return diff --git a/test/func1.go b/test/func1.go index 56f4dfcba..056ff9877 100644 --- a/test/func1.go +++ b/test/func1.go @@ -8,11 +8,11 @@ package main -func f1(a int) (int, float) { // BUG (not caught by compiler): multiple return values must have names +func f1(a int) (int, float32) { // BUG (not caught by compiler): multiple return values must have names return 7, 7.0 } -func f2(a int) (a int, b float) { // ERROR "redeclared|definition" +func f2(a int) (a int, b float32) { // ERROR "redeclared|definition" return 8, 8.0 } diff --git a/test/garbage/Makefile b/test/garbage/Makefile index ab29e0956..e83384382 100644 --- a/test/garbage/Makefile +++ b/test/garbage/Makefile @@ -11,8 +11,8 @@ ALL=\ all: $(addsuffix .out, $(ALL)) -%.$O: %.go - $(GC) $*.go +%.$O: %.go stats.go + $(GC) $*.go stats.go %.out: %.$O $(LD) -o $@ $*.$O diff --git a/test/garbage/parser.go b/test/garbage/parser.go index cf68737fb..19a96bc63 100644 --- a/test/garbage/parser.go +++ b/test/garbage/parser.go @@ -11,13 +11,19 @@ import ( "fmt" "go/ast" "go/parser" + "go/token" "os" "path" "runtime" "strings" "time" + "http" + _ "http/pprof" + "log" ) +var serve = flag.String("serve", "", "serve http on this address at end") + func isGoFile(dir *os.FileInfo) bool { return dir.IsRegular() && !strings.HasPrefix(dir.Name, ".") && // ignore .files @@ -30,7 +36,7 @@ func isPkgFile(dir *os.FileInfo) bool { } func pkgName(filename string) string { - file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly) + file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly) if err != nil || file == nil { return "" } @@ -58,7 +64,7 @@ func parseDir(dirpath string) map[string]*ast.Package { } // get package AST - pkgs, err := parser.ParseDir(dirpath, filter, parser.ParseComments) + pkgs, err := parser.ParseDir(token.NewFileSet(), dirpath, filter, parser.ParseComments) if err != nil { println("parse", dirpath, err.String()) panic("fail") @@ -67,12 +73,19 @@ func parseDir(dirpath string) map[string]*ast.Package { } func main() { + runtime.GOMAXPROCS(4) + go func() {}() + go func() {}() + go func() {}() st := &runtime.MemStats + packages = append(packages, packages...) + packages = append(packages, packages...) n := flag.Int("n", 4, "iterations") p := flag.Int("p", len(packages), "# of packages to keep in memory") flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)") flag.Parse() + var lastParsed []map[string]*ast.Package var t0 int64 pkgroot := runtime.GOROOT() + "/src/pkg/" for pass := 0; pass < 2; pass++ { @@ -81,7 +94,7 @@ func main() { // than the normal pauses and would otherwise make // the average look much better than it actually is. st.NumGC = 0 - st.PauseNs = 0 + st.PauseTotalNs = 0 t0 = time.Nanoseconds() for i := 0; i < *n; i++ { @@ -89,25 +102,34 @@ func main() { for j := range parsed { parsed[j] = parseDir(pkgroot + packages[j%len(packages)]) } + if i+1 == *n && *serve != "" { + lastParsed = parsed + } } runtime.GC() + runtime.GC() } t1 := time.Nanoseconds() fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n", st.Alloc, st.TotalAlloc, st.Sys, - st.Mallocs, float64(st.PauseNs)/1e9, - st.NumGC, float64(st.PauseNs)/1e9/float64(st.NumGC)) - - fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free") - for _, s := range st.BySize { - fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees) - } + st.Mallocs, float64(st.PauseTotalNs)/1e9, + st.NumGC, float64(st.PauseTotalNs)/1e9/float64(st.NumGC)) + /* + fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free") + for _, s := range st.BySize { + fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees) + } + */ // Standard gotest benchmark output, collected by build dashboard. - fmt.Printf("garbage.BenchmarkParser %d %d ns/op\n", *n, (t1-t0)/int64(*n)) - fmt.Printf("garbage.BenchmarkParserPause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC)) + gcstats("BenchmarkParser", *n, t1-t0) + + if *serve != "" { + log.Fatal(http.ListenAndServe(*serve, nil)) + println(lastParsed) + } } @@ -183,7 +205,6 @@ var packages = []string{ "math", "mime", "net", - "nntp", "os", "os/signal", "patch", @@ -195,6 +216,7 @@ var packages = []string{ "runtime", "scanner", "sort", + "smtp", "strconv", "strings", "sync", diff --git a/test/garbage/peano.go b/test/garbage/peano.go index b026354e8..b4d318561 100644 --- a/test/garbage/peano.go +++ b/test/garbage/peano.go @@ -123,7 +123,6 @@ func verify() { func main() { - st := &runtime.MemStats t0 := time.Nanoseconds() verify() for i := 0; i <= 9; i++ { @@ -132,6 +131,5 @@ func main() { runtime.GC() t1 := time.Nanoseconds() - fmt.Printf("garbage.BenchmarkPeano 1 %d ns/op\n", t1-t0) - fmt.Printf("garbage.BenchmarkPeanoPause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC)) + gcstats("BenchmarkPeano", 1, t1-t0) } diff --git a/test/garbage/stats.go b/test/garbage/stats.go new file mode 100644 index 000000000..474e6ad4a --- /dev/null +++ b/test/garbage/stats.go @@ -0,0 +1,44 @@ +// Copyright 2010 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. + +package main + +import ( + "fmt" + "runtime" + "sort" +) + +func gcstats(name string, n int, t int64) { + st := &runtime.MemStats + fmt.Printf("garbage.%sMem Alloc=%d/%d Heap=%d NextGC=%d Mallocs=%d\n", name, st.Alloc, st.TotalAlloc, st.Sys, st.NextGC, st.Mallocs) + fmt.Printf("garbage.%s %d %d ns/op\n", name, n, t/int64(n)) + fmt.Printf("garbage.%sLastPause 1 %d ns/op\n", name, st.PauseNs[(st.NumGC-1)%uint32(len(st.PauseNs))]) + fmt.Printf("garbage.%sPause %d %d ns/op\n", name, st.NumGC, int64(st.PauseTotalNs)/int64(st.NumGC)) + nn := int(st.NumGC) + if nn >= len(st.PauseNs) { + nn = len(st.PauseNs) + } + t1, t2, t3, t4, t5 := tukey5(st.PauseNs[0:nn]) + fmt.Printf("garbage.%sPause5: %d %d %d %d %d\n", name, t1, t2, t3, t4, t5) + +// fmt.Printf("garbage.%sScan: %v\n", name, st.ScanDist) +} + +type T []uint64 +func (t T) Len() int { return len(t) } +func (t T) Swap(i, j int) { t[i], t[j] = t[j], t[i] } +func (t T) Less(i, j int) bool { return t[i] < t[j] } + +func tukey5(raw []uint64) (lo, q1, q2, q3, hi uint64) { + x := make(T, len(raw)) + copy(x, raw) + sort.Sort(T(x)) + lo = x[0] + q1 = x[len(x)/4] + q2 = x[len(x)/2] + q3 = x[len(x)*3/4] + hi = x[len(x)-1] + return +} diff --git a/test/garbage/tree.go b/test/garbage/tree.go index 816693fbe..c5eae9760 100644 --- a/test/garbage/tree.go +++ b/test/garbage/tree.go @@ -39,7 +39,6 @@ package main import ( "flag" "fmt" - "runtime" "time" ) @@ -95,10 +94,7 @@ func main() { fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck()) t1 := time.Nanoseconds() - st := &runtime.MemStats // Standard gotest benchmark output, collected by build dashboard. - fmt.Printf("garbage.BenchmarkTree %d %d ns/op\n", *n, (t1-t0)/int64(*n)) - fmt.Printf("garbage.BenchmarkTreePause %d %d ns/op\n", st.NumGC, int64(st.PauseNs)/int64(st.NumGC)) - + gcstats("BenchmarkTree", *n, t1-t0) } diff --git a/test/golden.out b/test/golden.out index e587912a4..425771b4a 100644 --- a/test/golden.out +++ b/test/golden.out @@ -4,22 +4,18 @@ =========== ./cmp2.go panic: runtime error: comparing uncomparable type []int -panic PC=xxx =========== ./cmp3.go panic: runtime error: comparing uncomparable type []int -panic PC=xxx =========== ./cmp4.go panic: runtime error: hash of unhashable type []int -panic PC=xxx =========== ./cmp5.go panic: runtime error: hash of unhashable type []int -panic PC=xxx =========== ./deferprint.go printing: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @@ -64,7 +60,6 @@ Hello World! =========== ken/cplx3.go (+1.292308e+000-1.384615e-001i) (+1.292308e+000-1.384615e-001i) -64 =========== ken/cplx4.go c = (-5.000000-6.000000i) @@ -117,12 +112,10 @@ PASS =========== interface/fail.go panic: interface conversion: *main.S is not main.I: missing method Foo -panic PC=xxx =========== interface/returntype.go panic: interface conversion: *main.S is not main.I2: missing method Name -panic PC=xxx == nilptr/ @@ -130,9 +123,6 @@ panic PC=xxx == fixedbugs/ -=========== fixedbugs/bug016.go -fixedbugs/bug016.go:11: constant -3 overflows uint - =========== fixedbugs/bug027.go hi 0 44444 @@ -155,21 +145,16 @@ inner loop top i 0 do break broke -=========== fixedbugs/bug081.go -fixedbugs/bug081.go:9: typechecking loop - =========== fixedbugs/bug093.go M =========== fixedbugs/bug113.go panic: interface conversion: interface is int, not int32 -panic PC=xxx =========== fixedbugs/bug148.go 2 3 panic: interface conversion: interface is main.T, not main.T -panic PC=xxx == bugs/ diff --git a/test/interface/explicit.go b/test/interface/explicit.go index b952f8fc8..b6a582fff 100644 --- a/test/interface/explicit.go +++ b/test/interface/explicit.go @@ -51,21 +51,25 @@ func main() { t = T(e) // ERROR "need explicit|need type assertion|incompatible" } -type M interface { M() } +type M interface { + M() +} + var m M -var _ = m.(int) // ERROR "impossible type assertion" +var _ = m.(int) // ERROR "impossible type assertion" type Int int -func (Int) M(float) {} -var _ = m.(Int) // ERROR "impossible type assertion" +func (Int) M(float64) {} + +var _ = m.(Int) // ERROR "impossible type assertion" var ii int var jj Int -var m1 M = ii // ERROR "incompatible|missing" -var m2 M = jj // ERROR "incompatible|wrong type for M method" +var m1 M = ii // ERROR "incompatible|missing" +var m2 M = jj // ERROR "incompatible|wrong type for M method" -var m3 = M(ii) // ERROR "invalid|missing" -var m4 = M(jj) // ERROR "invalid|wrong type for M method" +var m3 = M(ii) // ERROR "invalid|missing" +var m4 = M(jj) // ERROR "invalid|wrong type for M method" diff --git a/test/iota.go b/test/iota.go index 20b77c6cc..c40ca1f38 100644 --- a/test/iota.go +++ b/test/iota.go @@ -17,8 +17,8 @@ const ( x int = iota y = iota z = 1 << iota - f float = 2 * iota - g float = 4.5 * float(iota) + f float32 = 2 * iota + g float32 = 4.5 * float32(iota) ) const ( @@ -57,7 +57,7 @@ const ( ) const ( - p = float(iota) + p = float32(iota) q r ) @@ -68,9 +68,9 @@ const ( ) const ( - abit, amask = 1 << iota, 1 << iota - 1 - bbit, bmask = 1 << iota, 1 << iota - 1 - cbit, cmask = 1 << iota, 1 << iota - 1 + abit, amask = 1 << iota, 1<<iota - 1 + bbit, bmask = 1 << iota, 1<<iota - 1 + cbit, cmask = 1 << iota, 1<<iota - 1 ) func main() { diff --git a/test/ken/cplx0.go b/test/ken/cplx0.go index 6e9bfd023..ba1fa196f 100644 --- a/test/ken/cplx0.go +++ b/test/ken/cplx0.go @@ -13,7 +13,7 @@ const ( C1 = R + I // ADD(5,6) ) -func doprint(c complex) { println(c) } +func doprint(c complex128) { println(c) } func main() { diff --git a/test/ken/cplx1.go b/test/ken/cplx1.go index 26b113992..8ec7d40f5 100644 --- a/test/ken/cplx1.go +++ b/test/ken/cplx1.go @@ -48,7 +48,7 @@ func main() { booltest(6+9i, false) } -func booltest(a complex, r bool) { +func booltest(a complex64, r bool) { var b bool b = a == C1 diff --git a/test/ken/cplx2.go b/test/ken/cplx2.go index 5a66dc9a9..b36e93ecd 100644 --- a/test/ken/cplx2.go +++ b/test/ken/cplx2.go @@ -28,13 +28,13 @@ const ( func main() { - r := 5 + 0i + var r complex64 = 5 + 0i if r != R { println("opcode 1", r, R) panic("fail") } - i := 6i + var i complex64 = 6i if i != I { println("opcode 2", i, I) panic("fail") diff --git a/test/ken/cplx3.go b/test/ken/cplx3.go index 997894b41..83acc15ff 100644 --- a/test/ken/cplx3.go +++ b/test/ken/cplx3.go @@ -16,24 +16,18 @@ const ( C1 = R + I // ADD(5,6) ) -var complexBits = reflect.Typeof(complex(0i)).Size() * 8 - func main() { c0 := C1 c0 = (c0 + c0 + c0) / (c0 + c0 + 3i) println(c0) - c := *(*complex)(unsafe.Pointer(&c0)) + c := *(*complex128)(unsafe.Pointer(&c0)) println(c) - println(complexBits) - var a interface{} switch c := reflect.NewValue(a).(type) { case *reflect.ComplexValue: - if complexBits == 64 { - v := c.Get() - _, _ = complex64(v), true - } + v := c.Get() + _, _ = complex128(v), true } } diff --git a/test/ken/cplx4.go b/test/ken/cplx4.go index 3c6f1f68c..8524e47ae 100644 --- a/test/ken/cplx4.go +++ b/test/ken/cplx4.go @@ -15,7 +15,7 @@ const ( C1 = R + I // ADD(5,6) ) -func doprint(c complex) { fmt.Printf("c = %f\n", c) } +func doprint(c complex128) { fmt.Printf("c = %f\n", c) } func main() { @@ -32,12 +32,12 @@ func main() { c2 := complex128(C1) fmt.Printf("c = %G\n", c2) - // real, imag, cmplx - c3 := cmplx(real(c2)+3, imag(c2)-5) + c2 + // real, imag, complex + c3 := complex(real(c2)+3, imag(c2)-5) + c2 fmt.Printf("c = %G\n", c3) // compiler used to crash on nested divide - c4 := cmplx(real(c3/2), imag(c3/2)) + c4 := complex(real(c3/2), imag(c3/2)) if c4 != c3/2 { fmt.Printf("BUG: c3 = %G != c4 = %G\n", c3, c4) } diff --git a/test/ken/cplx5.go b/test/ken/cplx5.go index af2a1c57d..d425a7c4c 100644 --- a/test/ken/cplx5.go +++ b/test/ken/cplx5.go @@ -6,49 +6,49 @@ package main -var a [12]complex -var s []complex -var c chan complex +var a [12]complex128 +var s []complex128 +var c chan complex128 var f struct { - c complex + c complex128 } -var m map[complex]complex +var m map[complex128]complex128 func main() { - // array of complex + // array of complex128 for i := 0; i < len(a); i++ { - a[i] = cmplx(float(i), float(-i)) + a[i] = complex(float64(i), float64(-i)) } println(a[5]) - // slice of complex - s = make([]complex, len(a)) + // slice of complex128 + s = make([]complex128, len(a)) for i := 0; i < len(s); i++ { s[i] = a[i] } println(s[5]) // chan - c = make(chan complex) + c = make(chan complex128) go chantest(c) println(<-c) - // pointer of complex + // pointer of complex128 v := a[5] pv := &v println(*pv) - // field of complex + // field of complex128 f.c = a[5] println(f.c) - // map of complex - m = make(map[complex]complex) + // map of complex128 + m = make(map[complex128]complex128) for i := 0; i < len(s); i++ { m[-a[i]] = a[i] } println(m[5i-5]) - println(m[cmplx(-5, 5)]) + println(m[complex(-5, 5)]) } -func chantest(c chan complex) { c <- a[5] } +func chantest(c chan complex128) { c <- a[5] } diff --git a/test/ken/robfunc.go b/test/ken/robfunc.go index 12b4b6d7b..6b3d4b2e4 100644 --- a/test/ken/robfunc.go +++ b/test/ken/robfunc.go @@ -8,8 +8,8 @@ package main func assertequal(is, shouldbe int, msg string) { if is != shouldbe { - print("assertion fail" + msg + "\n"); - panic(1); + print("assertion fail" + msg + "\n") + panic(1) } } @@ -20,75 +20,75 @@ func f2(a int) { } func f3(a, b int) int { - return a+b; + return a + b } -func f4(a, b int, c float) int { - return (a+b)/2 + int(c); +func f4(a, b int, c float64) int { + return (a+b)/2 + int(c) } func f5(a int) int { - return 5; + return 5 } func f6(a int) (r int) { - return 6; + return 6 } -func f7(a int) (x int, y float) { - return 7, 7.0; +func f7(a int) (x int, y float64) { + return 7, 7.0 } -func f8(a int) (x int, y float) { - return 8, 8.0; +func f8(a int) (x int, y float64) { + return 8, 8.0 } type T struct { - x, y int; + x, y int } -func (t *T) m10(a int, b float) int { - return (t.x+a) * (t.y+int(b)); +func (t *T) m10(a int, b float64) int { + return (t.x + a) * (t.y + int(b)) } -func f9(a int) (in int, fl float) { - i := 9; - f := float(9); - return i, f; +func f9(a int) (in int, fl float64) { + i := 9 + f := float64(9) + return i, f } func main() { - f1(); - f2(1); - r3 := f3(1, 2); - assertequal(r3, 3, "3"); - r4 := f4(0, 2, 3.0); - assertequal(r4, 4, "4"); - r5 := f5(1); - assertequal(r5, 5, "5"); - r6 := f6(1); - assertequal(r6, 6, "6"); - var r7 int; - var s7 float; - r7, s7 = f7(1); - assertequal(r7, 7, "r7"); - assertequal(int(s7), 7, "s7"); - var r8 int; - var s8 float; - r8, s8 = f8(1); - assertequal(r8, 8, "r8"); - assertequal(int(s8), 8, "s8"); - var r9 int; - var s9 float; - r9, s9 = f9(1); - assertequal(r9, 9, "r9"); - assertequal(int(s9), 9, "s9"); - var t *T = new(T); - t.x = 1; - t.y = 2; - r10 := t.m10(1, 3.0); - assertequal(r10, 10, "10"); + f1() + f2(1) + r3 := f3(1, 2) + assertequal(r3, 3, "3") + r4 := f4(0, 2, 3.0) + assertequal(r4, 4, "4") + r5 := f5(1) + assertequal(r5, 5, "5") + r6 := f6(1) + assertequal(r6, 6, "6") + var r7 int + var s7 float64 + r7, s7 = f7(1) + assertequal(r7, 7, "r7") + assertequal(int(s7), 7, "s7") + var r8 int + var s8 float64 + r8, s8 = f8(1) + assertequal(r8, 8, "r8") + assertequal(int(s8), 8, "s8") + var r9 int + var s9 float64 + r9, s9 = f9(1) + assertequal(r9, 9, "r9") + assertequal(int(s9), 9, "s9") + var t *T = new(T) + t.x = 1 + t.y = 2 + r10 := t.m10(1, 3.0) + assertequal(r10, 10, "10") } diff --git a/test/ken/simpconv.go b/test/ken/simpconv.go index cb443e3a1..feb85d299 100644 --- a/test/ken/simpconv.go +++ b/test/ken/simpconv.go @@ -6,20 +6,23 @@ package main -type vlong int64; -type short int16; +type vlong int64 +type short int16 -func -main() { - s1 := vlong(0); - for i:=short(0); i<10; i=i+1 { - s1 = s1 + vlong(i); +func main() { + s1 := vlong(0) + for i := short(0); i < 10; i = i + 1 { + s1 = s1 + vlong(i) + } + if s1 != 45 { + panic(s1) } - if s1 != 45 { panic(s1); } - s2 := float(0); - for i:=0; i<10; i=i+1 { - s2 = s2 + float(i); + s2 := float64(0) + for i := 0; i < 10; i = i + 1 { + s2 = s2 + float64(i) + } + if s2 != 45 { + panic(s2) } - if s2 != 45 { panic(s2); } } diff --git a/test/ken/slicearray.go b/test/ken/slicearray.go index 6e7088e19..5c31270fc 100644 --- a/test/ken/slicearray.go +++ b/test/ken/slicearray.go @@ -8,8 +8,8 @@ package main var bx [10]byte var by []byte -var fx [10]float -var fy []float +var fx [10]float64 +var fy []float64 var lb, hb int var t int @@ -87,7 +87,7 @@ func main() { by = bx[2:8] tstb() - // width 4 (float) + // width 4 (float64) lb = 0 hb = 10 fy = fx[lb:hb] @@ -204,7 +204,7 @@ func init() { by = nil for i := 0; i < len(fx); i++ { - fx[i] = float(i + 20) + fx[i] = float64(i + 20) } fy = nil } diff --git a/test/ken/sliceslice.go b/test/ken/sliceslice.go index 5a35acaf4..639042128 100644 --- a/test/ken/sliceslice.go +++ b/test/ken/sliceslice.go @@ -8,8 +8,8 @@ package main var bx []byte var by []byte -var fx []float -var fy []float +var fx []float64 +var fy []float64 var lb, hb int var t int @@ -78,7 +78,7 @@ func main() { by = bx[2:8] tstb() - // width 4 (float) + // width 4 (float64) lb = 0 hb = 10 fy = fx[lb:hb] @@ -195,9 +195,9 @@ func init() { } by = nil - fx = make([]float, 10) + fx = make([]float64, 10) for i := 0; i < len(fx); i++ { - fx[i] = float(i + 20) + fx[i] = float64(i + 20) } fy = nil } diff --git a/test/literal.go b/test/literal.go index 9bdbabca8..bf0538812 100644 --- a/test/literal.go +++ b/test/literal.go @@ -18,7 +18,7 @@ func assert(cond bool, msg string) { } } -func equal(a, b float) bool { +func equal(a, b float32) bool { return a == b } @@ -116,23 +116,23 @@ func main() { _, _, _, _ = u30, u31, u32, u33 // float - var f00 float = 3.14159 - var f01 float = -3.14159 - var f02 float = +3.14159 - var f03 float = 0.0 - var f04 float = .0 - var f05 float = 0. - var f06 float = -0.0 - var f07 float = 1e10 - var f08 float = -1e10 - var f09 float = 1e-10 - var f10 float = 1e+10 - var f11 float = 1.e-10 - var f12 float = 1.e+10 - var f13 float = .1e-10 - var f14 float = .1e+10 - var f15 float = 1.1e-10 - var f16 float = 1.1e+10 + var f00 float32 = 3.14159 + var f01 float32 = -3.14159 + var f02 float32 = +3.14159 + var f03 float32 = 0.0 + var f04 float32 = .0 + var f05 float32 = 0. + var f06 float32 = -0.0 + var f07 float32 = 1e10 + var f08 float32 = -1e10 + var f09 float32 = 1e-10 + var f10 float32 = 1e+10 + var f11 float32 = 1.e-10 + var f12 float32 = 1.e+10 + var f13 float32 = .1e-10 + var f14 float32 = .1e+10 + var f15 float32 = 1.1e-10 + var f16 float32 = 1.1e+10 assert(f01 == -f00, "f01") assert(f02 == -f01, "f02") assert(f03 == f04, "f03") diff --git a/test/map.go b/test/map.go index ddff7c7a7..c3963499b 100644 --- a/test/map.go +++ b/test/map.go @@ -21,73 +21,73 @@ func P(a []string) string { } s += `"` + a[i] + `"` } - s +="}" + s += "}" return s } func main() { // Test a map literal. - mlit := map[string] int { "0":0, "1":1, "2":2, "3":3, "4":4 } + mlit := map[string]int{"0": 0, "1": 1, "2": 2, "3": 3, "4": 4} for i := 0; i < len(mlit); i++ { - s := string([]byte{byte(i)+'0'}) + s := string([]byte{byte(i) + '0'}) if mlit[s] != i { fmt.Printf("mlit[%s] = %d\n", s, mlit[s]) } } - mib := make(map[int] bool) - mii := make(map[int] int) - mfi := make(map[float] int) - mif := make(map[int] float) - msi := make(map[string] int) - mis := make(map[int] string) - mss := make(map[string] string) - mspa := make(map[string] []string) + mib := make(map[int]bool) + mii := make(map[int]int) + mfi := make(map[float32]int) + mif := make(map[int]float32) + msi := make(map[string]int) + mis := make(map[int]string) + mss := make(map[string]string) + mspa := make(map[string][]string) // BUG need an interface map both ways too type T struct { - i int64 // can't use string here; struct values are only compared at the top level - f float + i int64 // can't use string here; struct values are only compared at the top level + f float32 } - mipT := make(map[int] *T) - mpTi := make(map[*T] int) - mit := make(map[int] T) -// mti := make(map[T] int) + mipT := make(map[int]*T) + mpTi := make(map[*T]int) + mit := make(map[int]T) + // mti := make(map[T] int) - type M map[int] int - mipM := make(map[int] M) + type M map[int]int + mipM := make(map[int]M) - var apT [2*count]*T + var apT [2 * count]*T for i := 0; i < count; i++ { s := strconv.Itoa(i) - s10 := strconv.Itoa(i*10) - f := float(i) - t := T{int64(i),f} + s10 := strconv.Itoa(i * 10) + f := float32(i) + t := T{int64(i), f} apT[i] = new(T) apT[i].i = int64(i) apT[i].f = f - apT[2*i] = new(T) // need twice as many entries as we use, for the nonexistence check + apT[2*i] = new(T) // need twice as many entries as we use, for the nonexistence check apT[2*i].i = int64(i) apT[2*i].f = f - m := M{i: i+1} + m := M{i: i + 1} mib[i] = (i != 0) - mii[i] = 10*i - mfi[float(i)] = 10*i - mif[i] = 10.0*f + mii[i] = 10 * i + mfi[float32(i)] = 10 * i + mif[i] = 10.0 * f mis[i] = s msi[s] = i mss[s] = s10 mss[s] = s10 as := make([]string, 2) - as[0] = s10 - as[1] = s10 + as[0] = s10 + as[1] = s10 mspa[s] = as mipT[i] = apT[i] mpTi[apT[i]] = i mipM[i] = m mit[i] = t - // mti[t] = i + // mti[t] = i } // test len @@ -121,15 +121,15 @@ func main() { if len(mpTi) != count { fmt.Printf("len(mpTi) = %d\n", len(mpTi)) } -// if len(mti) != count { -// fmt.Printf("len(mti) = %d\n", len(mti)) -// } + // if len(mti) != count { + // fmt.Printf("len(mti) = %d\n", len(mti)) + // } if len(mipM) != count { fmt.Printf("len(mipM) = %d\n", len(mipM)) } -// if len(mti) != count { -// fmt.Printf("len(mti) = %d\n", len(mti)) -// } + // if len(mti) != count { + // fmt.Printf("len(mti) = %d\n", len(mti)) + // } if len(mit) != count { fmt.Printf("len(mit) = %d\n", len(mit)) } @@ -137,25 +137,25 @@ func main() { // test construction directly for i := 0; i < count; i++ { s := strconv.Itoa(i) - s10 := strconv.Itoa(i*10) - f := float(i) + s10 := strconv.Itoa(i * 10) + f := float32(i) // BUG m := M(i, i+1) if mib[i] != (i != 0) { fmt.Printf("mib[%d] = %t\n", i, mib[i]) } - if(mii[i] != 10*i) { + if mii[i] != 10*i { fmt.Printf("mii[%d] = %d\n", i, mii[i]) } - if(mfi[f] != 10*i) { + if mfi[f] != 10*i { fmt.Printf("mfi[%d] = %d\n", i, mfi[f]) } - if(mif[i] != 10.0*f) { + if mif[i] != 10.0*f { fmt.Printf("mif[%d] = %g\n", i, mif[i]) } - if(mis[i] != s) { + if mis[i] != s { fmt.Printf("mis[%d] = %s\n", i, mis[i]) } - if(msi[s] != i) { + if msi[s] != i { fmt.Printf("msi[%s] = %d\n", s, msi[s]) } if mss[s] != s10 { @@ -166,22 +166,22 @@ func main() { fmt.Printf("mspa[%s][%d] = %s\n", s, j, mspa[s][j]) } } - if(mipT[i].i != int64(i) || mipT[i].f != f) { + if mipT[i].i != int64(i) || mipT[i].f != f { fmt.Printf("mipT[%d] = %v\n", i, mipT[i]) } - if(mpTi[apT[i]] != i) { + if mpTi[apT[i]] != i { fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]) } - // if(mti[t] != i) { - // fmt.Printf("mti[%s] = %s\n", s, mti[t]) - // } - if (mipM[i][i] != i + 1) { + // if(mti[t] != i) { + // fmt.Printf("mti[%s] = %s\n", s, mti[t]) + // } + if mipM[i][i] != i+1 { fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]) } - // if(mti[t] != i) { - // fmt.Printf("mti[%v] = %d\n", t, mti[t]) - // } - if(mit[i].i != int64(i) || mit[i].f != f) { + // if(mti[t] != i) { + // fmt.Printf("mti[%v] = %d\n", t, mti[t]) + // } + if mit[i].i != int64(i) || mit[i].f != f { fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f) } } @@ -190,7 +190,7 @@ func main() { // failed lookups yield a false value for the boolean. for i := 0; i < count; i++ { s := strconv.Itoa(i) - f := float(i) + f := float32(i) { _, b := mib[i] if !b { @@ -311,23 +311,23 @@ func main() { fmt.Printf("tuple existence assign: mit[%d]\n", i) } } -// { -// _, b := mti[t] -// if !b { -// fmt.Printf("tuple existence decl: mti[%d]\n", i) -// } -// _, b = mti[t] -// if !b { -// fmt.Printf("tuple existence assign: mti[%d]\n", i) -// } -// } + // { + // _, b := mti[t] + // if !b { + // fmt.Printf("tuple existence decl: mti[%d]\n", i) + // } + // _, b = mti[t] + // if !b { + // fmt.Printf("tuple existence assign: mti[%d]\n", i) + // } + // } } // test nonexistence with tuple check // failed lookups yield a false value for the boolean. for i := count; i < 2*count; i++ { s := strconv.Itoa(i) - f := float(i) + f := float32(i) { _, b := mib[i] if b { @@ -438,16 +438,16 @@ func main() { fmt.Printf("tuple nonexistence assign: mipM[%d]", i) } } -// { -// _, b := mti[t] -// if b { -// fmt.Printf("tuple nonexistence decl: mti[%d]", i) -// } -// _, b = mti[t] -// if b { -// fmt.Printf("tuple nonexistence assign: mti[%d]", i) -// } -// } + // { + // _, b := mti[t] + // if b { + // fmt.Printf("tuple nonexistence decl: mti[%d]", i) + // } + // _, b = mti[t] + // if b { + // fmt.Printf("tuple nonexistence assign: mti[%d]", i) + // } + // } { _, b := mit[i] if b { @@ -460,32 +460,31 @@ func main() { } } - // tests for structured map element updates for i := 0; i < count; i++ { s := strconv.Itoa(i) - mspa[s][i % 2] = "deleted" - if mspa[s][i % 2] != "deleted" { - fmt.Printf("update mspa[%s][%d] = %s\n", s, i %2, mspa[s][i % 2]) + mspa[s][i%2] = "deleted" + if mspa[s][i%2] != "deleted" { + fmt.Printf("update mspa[%s][%d] = %s\n", s, i%2, mspa[s][i%2]) } mipT[i].i += 1 if mipT[i].i != int64(i)+1 { fmt.Printf("update mipT[%d].i = %d\n", i, mipT[i].i) } - mipT[i].f = float(i + 1) - if (mipT[i].f != float(i + 1)) { + mipT[i].f = float32(i + 1) + if mipT[i].f != float32(i+1) { fmt.Printf("update mipT[%d].f = %g\n", i, mipT[i].f) } mipM[i][i]++ - if mipM[i][i] != (i + 1) + 1 { + if mipM[i][i] != (i+1)+1 { fmt.Printf("update mipM[%d][%d] = %i\n", i, i, mipM[i][i]) } } // test range on nil map - var mnil map[string] int + var mnil map[string]int for _, _ = range mnil { panic("range mnil") } diff --git a/test/method1.go b/test/method1.go index 1a2f8cae5..ec14ef9e4 100644 --- a/test/method1.go +++ b/test/method1.go @@ -8,10 +8,10 @@ package main type T struct { } func (t *T) M(int, string) // GCCGO_ERROR "previous" -func (t *T) M(int, float) { } // ERROR "redeclared|redefinition" +func (t *T) M(int, float64) { } // ERROR "redeclared|redefinition" func f(int, string) // GCCGO_ERROR "previous" -func f(int, float) { } // ERROR "redeclared|redefinition" +func f(int, float64) { } // ERROR "redeclared|redefinition" func g(a int, b string) // GCCGO_ERROR "previous" func g(a int, c string) // ERROR "redeclared|redefinition" diff --git a/test/named.go b/test/named.go index d2039bab4..5b6bb81fe 100644 --- a/test/named.go +++ b/test/named.go @@ -12,7 +12,7 @@ package main type Array [10]byte type Bool bool type Chan chan int -type Float float +type Float float32 type Int int type Map map[int]byte type Slice []byte diff --git a/test/named1.go b/test/named1.go index 600e502f9..1776313f0 100644 --- a/test/named1.go +++ b/test/named1.go @@ -43,12 +43,9 @@ func main() { _, b = m[2] // ERROR "cannot .* bool.*type Bool" m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool" - b = c <- 1 // ERROR "cannot use.*type bool.*type Bool" - _ = b - asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool" - - _, b = <-c // ERROR "cannot .* bool.*type Bool" - _ = b + ////TODO(rsc): uncomment when this syntax is valid for receive+check closed + //// _, b = <-c // ERROR "cannot .* bool.*type Bool" + //// _ = b var inter interface{} _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool" diff --git a/test/nil.go b/test/nil.go index 6a72b72eb..4f4c75527 100644 --- a/test/nil.go +++ b/test/nil.go @@ -10,14 +10,13 @@ type T struct { i int } -type IN interface { -} +type IN interface{} func main() { var i *int - var f *float + var f *float32 var s *string - var m map[float] *int + var m map[float32]*int var c chan int var t *T var in IN diff --git a/test/recover2.go b/test/recover2.go index f33af4457..9affe25d4 100644 --- a/test/recover2.go +++ b/test/recover2.go @@ -58,7 +58,7 @@ func test3() { func test4() { defer mustRecover("interface") var x interface{} = 1 - println(x.(float)) + println(x.(float32)) } type T struct { @@ -42,7 +42,9 @@ TMP2FILE=/tmp/gotest2-$$-$USER # don't run the machine out of memory: limit individual processes to 4GB. # on thresher, 3GB suffices to run the tests; with 2GB, peano fails. -ulimit -v 4000000 +# Linux charges reserved but not mapped addresses to ulimit -v +# so we have to use ulimit -m. +ulimit -m 4000000 # no core files please ulimit -c 0 diff --git a/test/stack.go b/test/stack.go index 816b555a4..1fd57161f 100644 --- a/test/stack.go +++ b/test/stack.go @@ -30,6 +30,32 @@ func d(t T) { } } +func f0() { + // likely to make a new stack for f0, + // because the call to f1 puts 3000 bytes + // in our frame. + f1() +} + +func f1() [3000]byte { + // likely to make a new stack for f1, + // because 3000 bytes were used by f0 + // and we need 3000 more for the call + // to f2. if the call to morestack in f1 + // does not pass the frame size, the new + // stack (default size 5k) will not be big + // enough for the frame, and the morestack + // check in f2 will die, if we get that far + // without faulting. + f2() + return [3000]byte{} +} + +func f2() [3000]byte { + // just take up space + return [3000]byte{} +} + var c = make(chan int) var t T var b = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} @@ -40,6 +66,7 @@ func recur(n int) { panic("bad []byte -> string") } go g(c, t) + f0() s := <-c if s != len(t) { println("bad go", s) diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go new file mode 100644 index 000000000..9c12e5e6f --- /dev/null +++ b/test/syntax/chan1.go @@ -0,0 +1,17 @@ +// errchk $G -e $D/$F.go + +// Copyright 2010 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. + +package main + +var c chan int +var v int + +func main() { + if c <- v { // ERROR "send statement.*value.*select" + } +} + +var _ = c <- v // ERROR "send statement.*value.*select" diff --git a/test/syntax/typesw.go b/test/syntax/typesw.go new file mode 100644 index 000000000..47f683cdf --- /dev/null +++ b/test/syntax/typesw.go @@ -0,0 +1,13 @@ +// errchk $G -e $D/$F.go + +// Copyright 2011 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. + +package main + +func main() { + switch main() := interface{}(nil).(type) { // ERROR "invalid variable name" + default: + } +} diff --git a/test/test0.go b/test/test0.go index dd2033a98..d8d86c427 100644 --- a/test/test0.go +++ b/test/test0.go @@ -6,12 +6,11 @@ package main -const - a_const = 0 +const a_const = 0 const ( - pi = /* the usual */ 3.14159265358979323 - e = 2.718281828 + pi = /* the usual */ 3.14159265358979323 + e = 2.718281828 mask1 int = 1 << iota mask2 = 1 << iota mask3 = 1 << iota @@ -19,7 +18,7 @@ const ( ) type ( - Empty interface {} + Empty interface{} Point struct { x, y int } @@ -32,19 +31,21 @@ func (p *Point) Initialize(x, y int) *Point { } func (p *Point) Distance() int { - return p.x * p.x + p.y * p.y + return p.x*p.x + p.y*p.y } var ( - x1 int - x2 int - u, v, w float + x1 int + x2 int + u, v, w float32 ) func foo() {} func min(x, y int) int { - if x < y { return x; } + if x < y { + return x + } return y } @@ -57,24 +58,29 @@ func swap(x, y int) (u, v int) { func control_structs() { var p *Point = new(Point).Initialize(2, 3) i := p.Distance() - var f float = 0.3 + var f float32 = 0.3 _ = f - for {} - for {} + for { + } + for { + } for j := 0; j < i; j++ { if i == 0 { - } else i = 0 - var x float + } else { + i = 0 + } + var x float32 _ = x } - foo: // a label +foo: // a label var j int switch y := 0; true { case i < y: fallthrough case i < j: case i == 0, i == 1, i == j: - i++; i++ + i++ + i++ goto foo default: i = -+-+i diff --git a/test/typeswitch.go b/test/typeswitch.go index 9e6d10ea8..83fb0985a 100644 --- a/test/typeswitch.go +++ b/test/typeswitch.go @@ -21,12 +21,15 @@ const ( Last ) -type S struct { a int } +type S struct { + a int +} + var s S = S{1234} var c = make(chan int) -var a = []int{0,1,2,3} +var a = []int{0, 1, 2, 3} var m = make(map[string]int) @@ -68,10 +71,10 @@ func main() { assert(x == true && i == Bool, "bool") case int: assert(x == 7 && i == Int, "int") - case float: - assert(x == 7.4 && i == Float, "float") + case float64: + assert(x == 7.4 && i == Float, "float64") case string: - assert(x == "hello"&& i == String, "string") + assert(x == "hello" && i == String, "string") case S: assert(x.a == 1234 && i == Struct, "struct") case chan int: diff --git a/test/zerodivide.go b/test/zerodivide.go index cd4f52215..1948528d2 100644 --- a/test/zerodivide.go +++ b/test/zerodivide.go @@ -17,56 +17,90 @@ type Error interface { } type ErrorTest struct { - name string - fn func() - err string + name string + fn func() + err string } var ( - i, j, k int = 0, 0, 1 - i8, j8, k8 int8 = 0, 0, 1 + i, j, k int = 0, 0, 1 + i8, j8, k8 int8 = 0, 0, 1 i16, j16, k16 int16 = 0, 0, 1 i32, j32, k32 int32 = 0, 0, 1 i64, j64, k64 int64 = 0, 0, 1 - u, v, w uint = 0, 0, 1 - u8, v8, w8 uint8 = 0, 0, 1 - u16, v16, w16 uint16 = 0, 0, 1 - u32, v32, w32 uint32 = 0, 0, 1 - u64, v64, w64 uint64 = 0, 0, 1 - up, vp, wp uintptr = 0, 0, 1 + u, v, w uint = 0, 0, 1 + u8, v8, w8 uint8 = 0, 0, 1 + u16, v16, w16 uint16 = 0, 0, 1 + u32, v32, w32 uint32 = 0, 0, 1 + u64, v64, w64 uint64 = 0, 0, 1 + up, vp, wp uintptr = 0, 0, 1 - f, g, h float = 0, 0, 1 - f32, g32, h32 float32 = 0, 0, 1 + f, g, h float64 = 0, 0, 1 + f32, g32, h32 float32 = 0, 0, 1 f64, g64, h64, inf, negInf, nan float64 = 0, 0, 1, math.Inf(1), math.Inf(-1), math.NaN() - c, d, e complex = 0+0i, 0+0i, 1+1i - c64, d64, e64 complex64 = 0+0i, 0+0i, 1+1i - c128, d128, e128 complex128 = 0+0i, 0+0i, 1+1i + c, d, e complex128 = 0 + 0i, 0 + 0i, 1 + 1i + c64, d64, e64 complex64 = 0 + 0i, 0 + 0i, 1 + 1i + c128, d128, e128 complex128 = 0 + 0i, 0 + 0i, 1 + 1i ) // Fool gccgo into thinking that these variables can change. func NotCalled() { - i++; j++; k++ - i8++; j8++; k8++ - i16++; j16++; k16++ - i32++; j32++; k32++ - i64++; j64++; k64++ - - u++; v++; w++ - u8++; v8++; w8++ - u16++; v16++; w16++ - u32++; v32++; w32++ - u64++; v64++; w64++ - up++; vp++; wp++ - - f += 1; g += 1; h += 1 - f32 += 1; g32 += 1; h32 += 1 - f64 += 1; g64 += 1; h64 += 1 - - c += 1+1i; d += 1+1i; e += 1+1i - c64 += 1+1i; d64 += 1+1i; e64 += 1+1i - c128 += 1+1i; d128 += 1+1i; e128 += 1+1i + i++ + j++ + k++ + i8++ + j8++ + k8++ + i16++ + j16++ + k16++ + i32++ + j32++ + k32++ + i64++ + j64++ + k64++ + + u++ + v++ + w++ + u8++ + v8++ + w8++ + u16++ + v16++ + w16++ + u32++ + v32++ + w32++ + u64++ + v64++ + w64++ + up++ + vp++ + wp++ + + f += 1 + g += 1 + h += 1 + f32 += 1 + g32 += 1 + h32 += 1 + f64 += 1 + g64 += 1 + h64 += 1 + + c += 1 + 1i + d += 1 + 1i + e += 1 + 1i + c64 += 1 + 1i + d64 += 1 + 1i + e64 += 1 + 1i + c128 += 1 + 1i + d128 += 1 + 1i + e128 += 1 + 1i } var tmp interface{} @@ -79,52 +113,52 @@ func use(v interface{}) { // Verify error/no error for all types. var errorTests = []ErrorTest{ // All integer divide by zero should error. - ErrorTest{ "int 0/0", func() { use(i/j) }, "divide", }, - ErrorTest{ "int8 0/0", func() { use(i8/j8) }, "divide", }, - ErrorTest{ "int16 0/0", func() { use(i16/j16) }, "divide", }, - ErrorTest{ "int32 0/0", func() { use(i32/j32) }, "divide", }, - ErrorTest{ "int64 0/0", func() { use(i64/j64) }, "divide", }, - - ErrorTest{ "int 1/0", func() { use(k/j) }, "divide", }, - ErrorTest{ "int8 1/0", func() { use(k8/j8) }, "divide", }, - ErrorTest{ "int16 1/0", func() { use(k16/j16) }, "divide", }, - ErrorTest{ "int32 1/0", func() { use(k32/j32) }, "divide", }, - ErrorTest{ "int64 1/0", func() { use(k64/j64) }, "divide", }, - - ErrorTest{ "uint 0/0", func() { use(u/v) }, "divide", }, - ErrorTest{ "uint8 0/0", func() { use(u8/v8) }, "divide", }, - ErrorTest{ "uint16 0/0", func() { use(u16/v16) }, "divide", }, - ErrorTest{ "uint32 0/0", func() { use(u32/v32) }, "divide", }, - ErrorTest{ "uint64 0/0", func() { use(u64/v64) }, "divide", }, - ErrorTest{ "uintptr 0/0", func() { use(up/vp) }, "divide", }, - - ErrorTest{ "uint 1/0", func() { use(w/v) }, "divide", }, - ErrorTest{ "uint8 1/0", func() { use(w8/v8) }, "divide", }, - ErrorTest{ "uint16 1/0", func() { use(w16/v16) }, "divide", }, - ErrorTest{ "uint32 1/0", func() { use(w32/v32) }, "divide", }, - ErrorTest{ "uint64 1/0", func() { use(w64/v64) }, "divide", }, - ErrorTest{ "uintptr 1/0", func() { use(wp/vp) }, "divide", }, - - // All floating divide by zero should not error. - ErrorTest{ "float 0/0", func() { use(f/g) }, "", }, - ErrorTest{ "float32 0/0", func() { use(f32/g32) }, "", }, - ErrorTest{ "float64 0/0", func() { use(f64/g64) }, "", }, - - ErrorTest{ "float 1/0", func() { use(h/g) }, "", }, - ErrorTest{ "float32 1/0", func() { use(h32/g32) }, "", }, - ErrorTest{ "float64 1/0", func() { use(h64/g64) }, "", }, - ErrorTest{ "float64 inf/0", func() { use(inf/g64) }, "", }, - ErrorTest{ "float64 -inf/0", func() { use(negInf/g64) }, "", }, - ErrorTest{ "float64 nan/0", func() { use(nan/g64) }, "", }, + ErrorTest{"int 0/0", func() { use(i / j) }, "divide"}, + ErrorTest{"int8 0/0", func() { use(i8 / j8) }, "divide"}, + ErrorTest{"int16 0/0", func() { use(i16 / j16) }, "divide"}, + ErrorTest{"int32 0/0", func() { use(i32 / j32) }, "divide"}, + ErrorTest{"int64 0/0", func() { use(i64 / j64) }, "divide"}, + + ErrorTest{"int 1/0", func() { use(k / j) }, "divide"}, + ErrorTest{"int8 1/0", func() { use(k8 / j8) }, "divide"}, + ErrorTest{"int16 1/0", func() { use(k16 / j16) }, "divide"}, + ErrorTest{"int32 1/0", func() { use(k32 / j32) }, "divide"}, + ErrorTest{"int64 1/0", func() { use(k64 / j64) }, "divide"}, + + ErrorTest{"uint 0/0", func() { use(u / v) }, "divide"}, + ErrorTest{"uint8 0/0", func() { use(u8 / v8) }, "divide"}, + ErrorTest{"uint16 0/0", func() { use(u16 / v16) }, "divide"}, + ErrorTest{"uint32 0/0", func() { use(u32 / v32) }, "divide"}, + ErrorTest{"uint64 0/0", func() { use(u64 / v64) }, "divide"}, + ErrorTest{"uintptr 0/0", func() { use(up / vp) }, "divide"}, + + ErrorTest{"uint 1/0", func() { use(w / v) }, "divide"}, + ErrorTest{"uint8 1/0", func() { use(w8 / v8) }, "divide"}, + ErrorTest{"uint16 1/0", func() { use(w16 / v16) }, "divide"}, + ErrorTest{"uint32 1/0", func() { use(w32 / v32) }, "divide"}, + ErrorTest{"uint64 1/0", func() { use(w64 / v64) }, "divide"}, + ErrorTest{"uintptr 1/0", func() { use(wp / vp) }, "divide"}, + + // All float64ing divide by zero should not error. + ErrorTest{"float64 0/0", func() { use(f / g) }, ""}, + ErrorTest{"float32 0/0", func() { use(f32 / g32) }, ""}, + ErrorTest{"float64 0/0", func() { use(f64 / g64) }, ""}, + + ErrorTest{"float64 1/0", func() { use(h / g) }, ""}, + ErrorTest{"float32 1/0", func() { use(h32 / g32) }, ""}, + ErrorTest{"float64 1/0", func() { use(h64 / g64) }, ""}, + ErrorTest{"float64 inf/0", func() { use(inf / g64) }, ""}, + ErrorTest{"float64 -inf/0", func() { use(negInf / g64) }, ""}, + ErrorTest{"float64 nan/0", func() { use(nan / g64) }, ""}, // All complex divide by zero should not error. - ErrorTest{ "complex 0/0", func() { use(c/d) }, "", }, - ErrorTest{ "complex64 0/0", func() { use(c64/d64) }, "", }, - ErrorTest{ "complex128 0/0", func() { use(c128/d128) }, "", }, + ErrorTest{"complex 0/0", func() { use(c / d) }, ""}, + ErrorTest{"complex64 0/0", func() { use(c64 / d64) }, ""}, + ErrorTest{"complex128 0/0", func() { use(c128 / d128) }, ""}, - ErrorTest{ "complex 1/0", func() { use(e/d) }, "", }, - ErrorTest{ "complex64 1/0", func() { use(e64/d64) }, "", }, - ErrorTest{ "complex128 1/0", func() { use(e128/d128) }, "", }, + ErrorTest{"complex 1/0", func() { use(e / d) }, ""}, + ErrorTest{"complex64 1/0", func() { use(e64 / d64) }, ""}, + ErrorTest{"complex128 1/0", func() { use(e128 / d128) }, ""}, } func error(fn func()) (error string) { @@ -137,12 +171,12 @@ func error(fn func()) (error string) { return "" } -type FloatTest struct{ - f, g float64 - out float64 +type FloatTest struct { + f, g float64 + out float64 } -var floatTests = []FloatTest{ +var float64Tests = []FloatTest{ FloatTest{0, 0, nan}, FloatTest{nan, 0, nan}, FloatTest{inf, 0, inf}, @@ -194,8 +228,8 @@ func main() { } // At this point we know we don't error on the values we're testing - for _, t := range floatTests { - x := t.f/t.g + for _, t := range float64Tests { + x := t.f / t.g if !alike(x, t.out) { if !bad { bad = true |