Compare commits

...

29 Commits

Author SHA1 Message Date
Andrew Gerrand
6c4e7f4b68 [release-branch.r60] doc: document r60.2
««« CL 5204041 / 1fb56f387a76
doc: document r60.2

R=rsc, dsymonds
CC=golang-dev
https://golang.org/cl/5204041
»»»

R=bradfitz
CC=golang-dev
https://golang.org/cl/5204043
2011-10-05 14:23:39 -07:00
Andrew Gerrand
609de85973 [release-branch.r60] doc: link to A Tour of Go
««« CL 5181045 / bc48691295c8
doc: link to A Tour of Go

R=golang-dev, rsc, r
CC=golang-dev
https://golang.org/cl/5181045
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5203041
2011-10-05 13:33:48 -07:00
Andrew Gerrand
60000444b8 [release-branch.r60] doc: update tutorial.
««« CL 5175052 / e144a6dec55e
doc: update tutorial.
Fix for new regexp library ($ isn't end of line any more).
Don't assume . is in PATH.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5175052
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5199042
2011-10-05 13:29:59 -07:00
Andrew Gerrand
31c829af98 [release-branch.r60] documentation: Debugging Go code with GDB tutorial.
««« CL 5168046 / 320d83ed794a
documentation: Debugging Go code with GDB tutorial.

R=adg, cw, lvd
CC=golang-dev
https://golang.org/cl/5168046

»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5172053
2011-10-05 13:28:08 -07:00
Andrew Gerrand
efcce1bedd [release-branch.r60] doc: link to image/draw blog post.
««« CL 5154046 / 087a4bd61f20
doc: link to image/draw blog post.

R=adg
TBR=adg
CC=golang-dev
https://golang.org/cl/5154046
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5202041
2011-10-05 13:25:52 -07:00
Andrew Gerrand
246c2fb736 [release-branch.r60] doc: link to image blog post
««« CL 5086048 / 09032e16d47c
doc: link to image blog post

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5086048
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5201041
2011-10-05 13:18:41 -07:00
Russ Cox
af68419ab2 [release-branch.r60] runtime: fix map memory leak
««« CL 5158045 / aaf8ddb0c780
runtime: fix map memory leak

The map implementation was using the C idiom of using
a pointer just past the end of its table as a limit pointer.
Unfortunately, the garbage collector sees that pointer as
pointing at the block adjacent to the map table, pinning
in memory a block that would otherwise be freed.

Fix by making limit pointer point at last valid entry, not
just past it.

Reviewed by Mike Burrows.

R=golang-dev, bradfitz, lvd, r
CC=golang-dev
https://golang.org/cl/5158045
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5169047
2011-10-03 13:34:24 -04:00
Andrew Gerrand
4af7136fcf [release-branch.r60] doc: update release.r60.1 notes
««« CL 5045045 / d101b482f64e
doc: update release.r60.1 notes

R=dsymonds
CC=golang-dev
https://golang.org/cl/5045045
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5063041
2011-09-19 12:32:07 +10:00
Andrew Gerrand
88102c4d10 [release-branch.r60] json: add struct tag option to wrap literals in strings
««« CL 4918051 / ba6daf799367
json: add struct tag option to wrap literals in strings

Since JavaScript doesn't have [u]int64 types, some JSON APIs
encode such types as strings to avoid losing precision.

This adds a new struct tag option ",string" to cause
fields to be wrapped in JSON strings on encoding
and unwrapped from strings when decoding.

R=rsc, gustavo
CC=golang-dev
https://golang.org/cl/4918051
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5049043
2011-09-19 11:59:19 +10:00
Andrew Gerrand
ab046b2afa [release-branch.r60] json: fix decode bug with struct tag names with ,opts being ignored
««« CL 4965049 / f8e4df3c4048
json: fix decode bug with struct tag names with ,opts being ignored

When the encoder was updated to respect the ",omitempty"
struct tag options, the decoder half was never updated to know
about the new struct tag format. (the format is now an optional
name, followed by zero or more ",option" strings)

This only affected people who used ",omitempty" along with
a field name. In that case, the serialized JSON wouldn't
decode to the original value.

R=golang-dev, dvyukov
CC=golang-dev
https://golang.org/cl/4965049
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5029043
2011-09-19 11:54:29 +10:00
Andrew Gerrand
37a9064879 [release-branch.r60] doc: release.r60.1
««« CL 5002041 / d21944c38c39
doc: release.r60.1

R=r
CC=golang-dev
https://golang.org/cl/5002041
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5019044
2011-09-15 21:32:34 +10:00
Andrew Gerrand
070fc85831 [release-branch.r60] doc: link to notable blog posts
««« CL 4996041 / f6fdb6a54203
doc: link to notable blog posts

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4996041
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4969081
2011-09-13 14:52:58 +10:00
Andrew Gerrand
8b8e079462 [release-branch.r60] misc/goplay: another template fix
««« CL 4950063 / 775543b0795c
misc/goplay: another template fix

Fixes #2219.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4950063
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/5000041
2011-09-13 14:45:37 +10:00
Andrew Gerrand
728eb92503 [release-branch.r60] misc/goplay: Fix template output
««« CL 4960052 / da491846e511
misc/goplay: Fix template output

Fixes #2219.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/4960052
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4960067
2011-09-13 14:43:18 +10:00
Andrew Gerrand
50026d415b [release-branch.r60] ld: grow dwarf includestack on demand.
««« CL 4988048 / c0abe3f34cec
ld: grow dwarf includestack on demand.

Fixes #2241
while not breaking issue 1878 again.

R=rsc
CC=golang-dev
https://golang.org/cl/4988048
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4973075
2011-09-12 10:20:04 +10:00
Andrew Gerrand
5464bfebe7 [release-branch.r60] doc: release.r60
««« CL 4981047 / c0fea223bc90
doc: release.r60

R=dsymonds, r, rsc
CC=golang-dev
https://golang.org/cl/4981047
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4961072
2011-09-08 12:16:42 +10:00
Andrew Gerrand
8b228654d0 [release-branch.r60] template: indirect or dereference function arguments if necessary to match the type of the formal.
««« CL 4967056 / a163a464ef59
template: indirect or dereference function arguments if necessary to match the type of the formal.
Fixes #2235

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4967056
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4992043
2011-09-08 11:15:38 +10:00
Andrew Gerrand
2800956682 [release-branch.r60] template: fix deadlock.
««« CL 4963054 / c581abafc917
template: fix deadlock.
No need for lexInsideAction to loop.
Fixes #2217.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/4963054
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4974068
2011-09-08 11:12:11 +10:00
Andrew Gerrand
1adba86fdd [release-branch.r60] template: range over channel
««« CL 4951046 / 379452c085ab
template: range over channel

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4951046
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4983052
2011-09-08 11:06:22 +10:00
Andrew Gerrand
dda8180c96 [release-branch.r60] template: Grammar fix for template documentation.
««« CL 4944043 / 6577cd4b870f
template: Grammar fix for template documentation.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/4944043

»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4978058
2011-09-08 11:02:39 +10:00
Andrew Gerrand
1fc3d23ca0 [release-branch.r60] exp/template: remove else and end nodes from public view.
««« CL 4905052 / 508513bbf607
exp/template: remove else and end nodes from public view.
They are used internally and do not appear in the final parse tree.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4905052
»»»

R=dsymonds
CC=golang-dev
https://golang.org/cl/4951069
2011-09-08 10:59:11 +10:00
Andrew Gerrand
b8f72d6110 [release-branch.r60] gc: fix pc/line table
««« CL 4938042 / 5671737303a0
gc: fix pc/line table

When a line directive was encountered we would push a new 'z' entry into
the history to indicate the start of new file attributation, and a 'Z'
entry to change line numbering.  However we didn't pop the 'z' entry, so
we were actually corrupting the history stack.  The most obvious
occurance of this was in the code that build the symbol tables for the
DWARF information - where an internal stack in the linker would overflow
when more than a few line directives were encountered in a single stack
(Issue 1878).  So now we pop the 'z' entry when we encounter the end of
the file that the directive was in, which maintains the history stack
integrity.

Also, although new 'z' entries for new files had relative paths
expanded, the same was not done for line directives.  Now we do it for
line directives also - so that the now correct DWARF information has the
full path available.

Fixes #1878.

R=rsc
CC=golang-dev
https://golang.org/cl/4938042

»»»

R=golang-dev
CC=golang-dev
https://golang.org/cl/4973069
2011-09-08 10:55:54 +10:00
Andrew Gerrand
616801951b [release-branch.r60] gofix: do not convert url in field names
««« CL 4972052 / 0f7a647510f9
gofix: do not convert url in field names

There's some ambiguity in the U{url: url} case as it could be
both a map or a struct literal, but given context it's more
likely a struct, so U{url: url_} rather than U{url_: url_}.
At least that was the case for me.

R=golang-dev, rsc, adg
CC=golang-dev
https://golang.org/cl/4972052
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4962058
2011-09-08 10:52:28 +10:00
Andrew Gerrand
e84d4effa1 [release-branch.r60] gofix: forgot to rename the URL type
««« CL 4952041 / c51a2f3f897a
gofix: forgot to rename the URL type
Fixes #2182

R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/4952041
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4951068
2011-09-08 10:51:09 +10:00
Andrew Gerrand
d28f559503 [release-branch.r60] gofix: osopen: fixed=true when changing O_CREAT
««« CL 4921047 / 15cefddbe963
gofix: osopen: fixed=true when changing O_CREAT

R=rsc, r
CC=golang-dev
https://golang.org/cl/4921047

»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4961071
2011-09-08 10:49:40 +10:00
Andrew Gerrand
f7e76c75f1 [release-branch.r60] goinstall: select the tag that is closest to runtime.Version
««« CL 4873057 / db63f3a1f992
goinstall: select the tag that is closest to runtime.Version

release.r50 looks for newest tag <= go.r50
weekly.2010-10-10 looks for newest tag <= go.2010-10-10

Implements behavior for hg, git, and bzr.

R=dsymonds, rsc, n13m3y3r
CC=golang-dev
https://golang.org/cl/4873057
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4974067
2011-09-08 10:48:19 +10:00
Andrew Gerrand
adc856a211 [release-branch.r60] goinstall: report lack of $GOPATH on errors
««« CL 4929047 / 7bfbbfb1ad42
goinstall: report lack of $GOPATH on errors

Fixes #2175.

R=alex.brainman, rsc, gustavo, adg
CC=golang-dev
https://golang.org/cl/4929047
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4964068
2011-09-08 10:45:04 +10:00
Andrew Gerrand
6a571c5191 [release-branch.r60] goinstall: error out with paths that end with '/'
««« CL 4807048 / ae3b2b092cf7
goinstall: error out with paths that end with '/'

R=adg, rsc, tarmigan+golang
CC=golang-dev
https://golang.org/cl/4807048

»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4968077
2011-09-08 10:43:40 +10:00
Andrew Gerrand
808bb141a6 create release-branch.r60 2011-09-08 10:39:39 +10:00
69 changed files with 1736 additions and 272 deletions

479
doc/debugging_with_gdb.html Normal file
View File

@@ -0,0 +1,479 @@
<!-- title Debugging Go Code with GDB -->
<p><i>
This applies to the 6g toolchain. Gccgo has native gdb support. Besides this
overview you might want to consult the
<a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
</i></p>
<h2 id="Introduction">Introduction</h2>
<p>
When you compile and link your Go programs with the 6g/6l or 8g/8l toolchains
on Linux, Mac OSX or FreeBSD, the resulting binaries contain DWARFv3
debugging information that recent versions (>7.1) of the GDB debugger can
use to inspect a live process or a core dump.
</p>
<p>
Pass the <code>'-s'</code> flag to the linker to omit the debug information.
</p>
<h3 id="Common_Operations">Common Operations</h3>
<ul>
<li>
Show file and line number for code
and set breakpoints:
<pre>(gdb) <b>list</b>
(gdb) <b>list <i>line</i></b>
(gdb) <b>list <i>file.go</i>:<i>line</i></b>
(gdb) <b>break <i>line</i></b>
(gdb) <b>break <i>file.go</i>:<i>line</i></b>
(gdb) <b>disas</b></pre>
</li>
<li>
Unwind stack frames:
<pre>(gdb) <b>bt</b>
(gdb) <b>frame <i>n</i></b></pre>
</li>
<li>
Show the name, type and location on the stack frame of local variables,
arguments and return values:
<pre>(gdb) <b>info locals</b>
(gdb) <b>info args</b>
(gdb) <b>p variable</b>
(gdb) <b>whatis variable</b></pre>
</li>
<li>
Show the name, type and location of global variables:
<pre>(gdb) <b>info variables <i>regexp</i></b></pre>
</li>
</ul>
<h3 id="Go_Extensions">Go Extensions</h3>
<p>
A recent extension mechanism to GDB allows it to load extension scripts for a
given binary. The tool chain uses this to extend GDB with a handful of
commands to inspect internals of the runtime code (such as goroutines) and to
pretty print the built-in map, slice and channel types.
</p>
<ul>
<li>
Pretty printing a string, slice, map, channel or interface:
<pre>(gdb) <b>p <i>var</i></b></pre>
</li>
<li>
A $len() and $cap() function for strings, slices and maps:
<pre>(gdb) <b>p $len(<i>var</i>)</b></pre>
</li>
<li>
A function to cast interfaces to their dynamic types:
<pre>(gdb) <b>p $dtype(<i>var</i>)</b>
(gdb) <b>iface <i>var</i></b></pre>
<p class="detail"><b>Known issue:</b> GDB cant automatically find the dynamic
type of an interface value if its long name differs from its short name
(annoying when printing stacktraces, the pretty printer falls back to printing
the short type name and a pointer).</p>
</li>
<li>
Inspecting goroutines:
<pre>(gdb) <b>info goroutines</b>
(gdb) <b>goroutine <i>n</i> <i>cmd</i></b>
(gdb) <b>help goroutine</b></pre>
For example:
<pre>(gdb) <b>goroutine 12 bt</b></pre>
</li>
</ul>
<p>
If you'd like to see how this works, or want to extend it, take a look at <a
href="/src/pkg/runtime/runtime-gdb.py">src/pkg/runtime/runtime-gdb.py</a> in
the Go source distribution. It depends on some special magic types
(<code>hash&lt;T,U&gt;</code>) and variables (<code>runtime.m</code> and
<code>runtime.g</code>) that the linker
(<a href="/src/cmd/ld/dwarf.c">src/cmd/ld/dwarf.c</a>) ensures are described in
the DWARF code.
</ines
<p>
If you're interested in what the debugging information looks like, run
'<code>objdump -W 6.out</code>' and browse through the <code>.debug_*</code>
sections.
</p>
<h3 id="Known_Issues">Known Issues</h3>
<ol>
<li>String pretty printing only triggers for type string, not for types derived
from it.</li>
<li>Type information is missing for the C parts of the runtime library.</li>
<li>GDB does not understand Gos name qualifications and treats
<code>"fmt.Print"</code> as an unstructured literal with a <code>"."</code>
that needs to be quoted. It objects even more strongly to method names of
the form <code>pkg.(*MyType).Meth</code>.
<li>All global variables are lumped into package <code>"main"</code>.</li>
</ol>
<h2 id="Tutorial">Tutorial</h2>
<p>
In this tutorial we will inspect the binary of the
<a href="/pkg/regexp/">regexp</a> package's unit tests. To build the binary,
change to <code>$GOROOT/src/pkg/regexp</code> and run <code>gotest</code>.
This should produce an executable file named <code>6.out</code>.
</p>
<h3 id="Getting_Started">Getting Started</h3>
<p>
Launch GDB, debugging <code>6.out</code>:
</p>
<pre>
$ <b>gdb 6.out</b>
GNU gdb (GDB) 7.2-gg8
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv 3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;
Type "show copying" and "show warranty" for licensing/warranty details.
This GDB was configured as "x86_64-linux".
Reading symbols from /home/user/go/src/pkg/regexp/6.out...
done.
Loading Go Runtime support.
(gdb)
</pre>
<p>
The message <code>"Loading Go Runtime support"</code> means that GDB loaded the
extension from <code>$GOROOT/src/pkg/runtime/runtime-gdb.py</code>.
</p>
<p>
To help GDB find the Go runtime sources and the accompanying support script,
pass your <code>$GOROOT</code> with the <code>'-d'</code> flag:
</p>
<pre>
$ <b>gdb 6.out -d $GOROOT</b>
</pre>
<p>
If for some reason GDB still can't find that directory or that script, you can load
it by hand by telling gdb (assuming you have the go sources in
<code>~/go/</code>):
<p>
<pre>
(gdb) <b>source ~/go/src/pkg/runtime/runtime-gdb.py</b>
Loading Go Runtime support.
</pre>
<h3 id="Inspecting_the_source">Inspecting the source</h3>
<p>
Use the <code>"l"</code> or <code>"list"</code> command to inspect source code.
</p>
<pre>
(gdb) <b>l</b>
</pre>
<p>
List a specific part of the source parametrizing <code>"list"</code> with a
function name (it must be qualified with its package name).
</p>
<pre>
(gdb) <b>l main.main</b>
</pre>
<p>
List a specific file and line number:
</p>
<pre>
(gdb) <b>l regexp.go:1</b>
(gdb) <i># Hit enter to repeat last command. Here, this lists next 10 lines.</i>
</pre>
<h3 id="Naming">Naming</h3>
<p>
Variable and function names must be qualified with the name of the packages
they belong to. The <code>Compile</code> function from the <code>regexp</code>
package is known to GDB as <code>'regexp.Compile'</code>.
</p>
<p>
Methods must be qualified with the name of their receiver types. For example,
the <code>*Regexp</code> types <code>doParse</code> method is known as
<code>'regexp.*Regexp.doParse'</code>. (Note that the second dot is a "middot,"
an artifact of Gos internal representation of methods.)
</p>
<p>
Variables that shadow other variables are magically suffixed with a number in the debug info.
Variables referenced by closures will appear as pointers magically prefixed with '&amp'.
</p>
<h3 id="Setting_breakpoints">Setting breakpoints</h3>
<p>
Set a breakpoint at the <code>TestFind</code> function:
</p>
<pre>
(gdb) <b>b 'regexp.TestFind'</b>
Breakpoint 1 at 0x424908: file /home/user/go/src/pkg/regexp/find_test.go, line 148.
</pre>
<p>
Run the program:
</p>
<pre>
(gdb) <b>run</b>
Starting program: /home/lvd/g/src/pkg/regexp/6.out
Breakpoint 1, regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/pkg/regexp/find_test.go:148
148 func TestFind(t *testing.T) {
</pre>
<p>
Execution has paused at the breakpoint.
See which goroutines are running, and what they're doing:
</p>
<pre>
(gdb) <b>info goroutines</b>
1 waiting runtime.gosched
* 13 running runtime.goexit
</pre>
<p>
the one marked with the <code>*</code> is the current goroutine.
</p>
<h3 id="Inspecting_the_stack">Inspecting the stack</h3>
<p>
Look at the stack trace for where weve paused the program:
</p>
<pre>
(gdb) <b>bt</b> <i># backtrace</i>
#0 regexp.TestFind (t=0xf8404a89c0) at /home/user/go/src/pkg/regexp/find_test.go:148
#1 0x000000000042f60b in testing.tRunner (t=0xf8404a89c0, test=0x573720) at /home/user/go/src/pkg/testing/testing.go:156
#2 0x000000000040df64 in runtime.initdone () at /home/user/go/src/pkg/runtime/proc.c:242
#3 0x000000f8404a89c0 in ?? ()
#4 0x0000000000573720 in ?? ()
#5 0x0000000000000000 in ?? ()
</pre>
<p>
The other goroutine, number 1, is stuck in <code>runtime.gosched</code>, blocked on a channel receive:
</p>
<pre>
(gdb) <b>goroutine 1 bt</b>
#0 0x000000000040facb in runtime.gosched () at /home/lvd/g/src/pkg/runtime/proc.c:873
#1 0x00000000004031c9 in runtime.chanrecv (c=void, ep=void, selected=void, received=void)
at /home/lvd/g/src/pkg/runtime/chan.c:342
#2 0x0000000000403299 in runtime.chanrecv1 (t=void, c=void) at/home/lvd/g/src/pkg/runtime/chan.c:423
#3 0x000000000043075b in testing.RunTests (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef60, tests= []testing.InternalTest = {...}) at /home/lvd/g/src/pkg/testing/testing.go:201
#4 0x00000000004302b1 in testing.Main (matchString={void (struct string, struct string, bool *, os.Error *)} 0x7ffff7f9ef80, tests= []testing.InternalTest = {...}, benchmarks= []testing.InternalBenchmark = {...})
at /home/lvd/g/src/pkg/testing/testing.go:168
#5 0x0000000000400dc1 in main.main () at /home/lvd/g/src/pkg/regexp/_testmain.go:98
#6 0x00000000004022e7 in runtime.mainstart () at /home/lvd/g/src/pkg/runtime/amd64/asm.s:78
#7 0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/runtime/proc.c:243
#8 0x0000000000000000 in ?? ()
</pre>
<p>
The stack frame shows were currently executing the <code>regexp.TestFind</code> function, as expected.
</p>
<pre>
(gdb) <b>info frame</b>
Stack level 0, frame at 0x7ffff7f9ff88:
rip = 0x425530 in regexp.TestFind (/home/lvd/g/src/pkg/regexp/find_test.go:148);
saved rip 0x430233
called by frame at 0x7ffff7f9ffa8
source language minimal.
Arglist at 0x7ffff7f9ff78, args: t=0xf840688b60
Locals at 0x7ffff7f9ff78, Previous frame's sp is 0x7ffff7f9ff88
Saved registers:
rip at 0x7ffff7f9ff80
</pre>
<p>
The command <code>info locals</code> lists all variables local to the function and their values, but is a bit
dangerous to use, since it will also try to print uninitialized variables. Uninitialized slices may cause gdb to try
to print arbitrary large arrays.
</p>
<p>
The functions arguments:
</p>
<pre>
(gdb) <b>info args</b>
t = 0xf840688b60
</pre>
<p>
When printing the argument, notice that its a pointer to a
<code>Regexp</code> value. Note that GDB has incorrectly put the <code>*</code>
on the right-hand side of the type name and made up a 'struct' keyword, in traditional C style.
</p>
<pre>
(gdb) <b>p re</b>
(gdb) p t
$1 = (struct testing.T *) 0xf840688b60
(gdb) p t
$1 = (struct testing.T *) 0xf840688b60
(gdb) p *t
$2 = {errors = "", failed = false, ch = 0xf8406f5690}
(gdb) p *t->ch
$3 = struct hchan<*testing.T>
</pre>
<p>
That <code>struct hchan<*testing.T></code> is the runtime-internal represntation of a channel. It is currently empty, or gdb would have pretty-printed it's contents.
</p>
<p>
Stepping forward:
</p>
<pre>
(gdb) <b>n</b> <i># execute next line</i>
149 for _, test := range findTests {
(gdb) <i># enter is repeat</i>
150 re := MustCompile(test.pat)
(gdb) <b>p test.pat</b>
$4 = ""
(gdb) <b>p re</b>
$5 = (struct regexp.Regexp *) 0xf84068d070
(gdb) <b>p *re</b>
$6 = {expr = "", prog = 0xf840688b80, prefix = "", prefixBytes = []uint8, prefixComplete = true,
prefixRune = 0, cond = 0 '\000', numSubexp = 0, longest = false, mu = {state = 0, sema = 0},
machine = []*regexp.machine}
(gdb) <b>p *re->prog</b>
$7 = {Inst = []regexp/syntax.Inst = {{Op = 5 '\005', Out = 0, Arg = 0, Rune = []int}, {Op =
6 '\006', Out = 2, Arg = 0, Rune = []int}, {Op = 4 '\004', Out = 0, Arg = 0, Rune = []int}},
Start = 1, NumCap = 2}
</pre>
<p>
We can step into the <code>String</code>function call with <code>"s"</code>:
</p>
<pre>
(gdb) <b>s</b>
regexp.(*Regexp).String (re=0xf84068d070, noname=void) at /home/lvd/g/src/pkg/regexp/regexp.go:97
97 func (re *Regexp) String() string {
</pre>
<p>
Get a stack trace to see where we are:
</p>
<pre>
(gdb) <b>bt</b>
(gdb) bt
#0 regexp.(*Regexp).String (re=0xf84068d070, noname=void)
at /home/lvd/g/src/pkg/regexp/regexp.go:97
#1 0x0000000000425615 in regexp.TestFind (t=0xf840688b60)
at /home/lvd/g/src/pkg/regexp/find_test.go:151
#2 0x0000000000430233 in testing.tRunner (t=0xf840688b60, test=0x5747b8)
at /home/lvd/g/src/pkg/testing/testing.go:156
#3 0x000000000040ea6f in runtime.initdone () at /home/lvd/g/src/pkg/runtime/proc.c:243
....
</pre>
<p>
Look at the source code:
</p>
<pre>
(gdb) <b>l</b>
92 mu sync.Mutex
93 machine []*machine
94 }
95
96 // String returns the source text used to compile the regular expression.
97 func (re *Regexp) String() string {
98 return re.expr
99 }
100
101 // Compile parses a regular expression and returns, if successful,
</pre>
<h3 id="Pretty_Printing">Pretty Printing</h3>
<p>
GDB's pretty printing mechanism is triggered by regexp matches on type names. An example for slices:
</p>
<pre>
(gdb) <b>p utf</b>
$22 = []uint8 = {0 '\000', 0 '\000', 0 '\000', 0 '\000'}
</pre>
<p>
Since slices, arrays and strings are not C pointers, GDB can't interpret the subscripting operation for you, but
you can look inside the runtime representation to do that (tab completion helps here):
</p>
<pre>
(gdb) <b>p slc</b>
$11 = []int = {0, 0}
(gdb) <b>p slc-&gt</b><i>&ltTAB&gt</i>
array slc len
(gdb) <b>p slc->array</b>
$12 = (int *) 0xf84057af00
(gdb) <b>p slc->array[1]</b>
$13 = 0</pre>
<p>
The extension functions $len and $cap work on strings, arrays and slices:
</p>
<pre>
(gdb) <b>p $len(utf)</b>
$23 = 4
(gdb) <b>p $cap(utf)</b>
$24 = 4
</pre>
<p>
Channels and maps are 'reference' types, which gdb shows as pointers to C++-like types <code>hash&ltint,string&gt*</code>. Dereferencing will trigger prettyprinting
</p>
<p>
Interfaces are represented in the runtime as a pointer to a type descriptor and a pointer to a value. The Go GDB runtime extension decodes this and automatically triggers pretty printing for the runtime type. The extension function <code>$dtype</code> decodes the dynamic type for you (examples are taken from a breakpoint at <code>regexp.go</code> line 293.)
</p>
<pre>
(gdb) <b>p i</b>
$4 = {str = "cbb"}
(gdb) <b>whatis i</b>
type = regexp.input
(gdb) <b>p $dtype(i)</b>
$26 = (struct regexp.inputBytes *) 0xf8400b4930
(gdb) <b>iface i</b>
regexp.input: struct regexp.inputBytes *
</pre>

View File

@@ -14,6 +14,102 @@ hg pull
hg update release.r<i>NN</i>
</pre>
<h2 id="r60">r60 (released 2011/09/07)</h2>
<p>
The r60 release corresponds to
<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
This section highlights the most significant changes in this release.
For a more detailed summary, see the
<a href="weekly.html#2011-08-17">weekly release notes</a>.
For complete information, see the
<a href="http://code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
</p>
<h3 id="r60.lang">Language</h3>
<p>
An "else" block is now required to have braces except if the body of the "else"
is another "if". Since gofmt always puts those braces in anyway,
gofmt-formatted programs will not be affected.
To fix other programs, run gofmt.
</p>
<h3 id="r60.pkg">Packages</h3>
<p>
<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
the new <a href="/pkg/url/">url package</a>, with several simplifications to
the names. Client code can be updated automatically with gofix.
</p>
<p>
<a href="/pkg/image/">Package image</a> has had significant changes made to the
<code>Pix</code> field of struct types such as
<a href="/pkg/image/#RGBA">image.RGBA</a> and
<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
though, and you should not need to change your code if you don't explicitly
refer to <code>Pix</code> fields. For example, if you decode a number of images
using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
<a href="/pkg/img/png">image/png</a>, then your code should still work as
before.
If your code <i>does</i> refer to <code>Pix</code> fields see the
<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
snapshot notes for how to update your code.
</p>
<p>
<a href="/pkg/template/">Package template</a> has been replaced with a new
templating package (formerly <code>exp/template</code>). The original template
package is still available as <a href="/pkg/old/template/">old/template</a>.
The <code>old/template</code> package is deprecated and will be removed.
The Go tree has been updated to use the new template package. We encourage
users of the old template package to switch to the new one. Code that uses
<code>template</code> or <code>exp/template</code> will need to change its
import lines to <code>"old/template"</code> or <code>"template"</code>,
respectively.
</p>
<h3 id="r60.cmd">Tools</h3>
<p>
<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
When downloading or updating, goinstall looks for a tag or branch with the
<code>"go."</code> prefix that corresponds to the local Go version. For Go
<code>release.r58</code> it looks for <code>go.r58</code>. For
<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
If the specific <code>go.X</code> tag or branch is not found, it chooses the
closest earlier version. If an appropriate tag or branch is found, goinstall
uses that version of the code. Otherwise it uses the default version selected
by the version control system. Library authors are encouraged to use the
appropriate tag or branch names in their repositories to make their libraries
more accessible.
</p>
<h3 id="r60.minor">Minor revisions</h3>
<p>
r60.1 includes a
<a href="http://code.google.com/p/go/source/detail?r=1824581bf62d">linker
fix</a>, a pair of
<a href="http://code.google.com/p/go/source/detail?r=9ef4429c2c64">goplay</a>
<a href="http://code.google.com/p/go/source/detail?r=d42ed8c3098e">fixes</a>,
and a <code>json</code> package
<a href="http://code.google.com/p/go/source/detail?r=d5e97874fe84">fix</a> and
a new
<a href="http://code.google.com/p/go/source/detail?r=4f0e6269213f">struct tag
option</a>.
</p>
<p>
r60.2
<a href="http://code.google.com/p/go/source/detail?r=ff19536042ac">fixes</a>
a memory leak involving maps.
</p>
<h2 id="r59">r59 (released 2011/08/01)</h2>
<p>
@@ -323,7 +419,7 @@ Remember that gofix will handle the bulk of the rewrites
necessary for these changes to package APIs.
</p>
<h3 id="r57.tool">Tools</h3>
<h3 id="r57.cmd">Tools</h3>
<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>

View File

@@ -14,7 +14,195 @@ hg pull
hg update weekly.<i>YYYY-MM-DD</i>
</pre>
<h2 id="2011-08-17">2011-08-17</h2>
<h2 id="2011-09-07">2011-09-07</h2>
<pre>
This weekly snapshot consists of improvements and bug fixes, including fixes
for issues introduced by escape analysis changes in the gc compiler.
* build: clear execute bit from Go files (thanks Mike Rosset),
error out if problem with sudo.bash /usr/local/bin (thanks Mike Rosset).
* exp/norm: add Reader and Writer,
performance improvements of quickSpan.
* exp/regexp: bug fixes and RE2 tests.
* exp/template/html: string replacement refactoring,
tweaks to js{,_test}.go.
* gc: add -p flag to catch import cycles earlier,
fix label recursion bugs,
fix zero-length struct eval,
zero stack-allocated slice backing arrays,
* gc, ld: fix Windows file paths (thanks Hector Chu).
* go/parser: accept corner cases of signature syntax.
* gobuilder: ignore _test.go files when looking for docs, more logging.
* godoc: minor tweaks for App Engine use.
* gofix: do not convert url in field names (thanks Gustavo Niemeyer).
* gofmt: indent multi-line signatures.
* gopprof: regexp fixes (thanks Hector Chu).
* image/png: check zlib checksum during Decode.
* libmach: fix incorrect use of memset (thanks Dave Cheney).
* misc/goplay: fix template output.
* net: ParseCIDR returns IPNet instead of IPMask (thanks Mikio Hara),
sync CIDRMask code, doc.
* os: use GetFileAttributesEx to implement Stat on windows (thanks Alex Brainman).
* runtime: fix openbsd 386 raisesigpipe,
implement exception handling on windows/amd64 (thanks Hector Chu),
test for concurrent channel consumers (thanks Christopher Wedgwood).
* sort: use heapsort to bail out quicksort (thanks Ziad Hatahet).
* sync/atomic: add LoadUintptr, add Store functions.
* syscall: update routing message attributes handling (thanks Mikio Hara).
* template: fix deadlock,
indirect or dereference function arguments if necessary,
slightly simplify the test for assignability of arguments.
* url: handle ; in ParseQuery.
* websocket: fix incorrect prints found by govet (thanks Robert Hencke).
</pre>
<h2 id="2011-09-01">2011-09-01</h2>
<pre>
This weekly contains performance improvements and bug fixes.
The gc compiler now does escape analysis, which improves program performance
by placing variables on the call stack instead of the heap when it is safe to
do so.
The container/vector package is deprecated and will be removed at some point
in the future.
Other changes:
* archive/tar: support symlinks. (thanks Mike Rosset)
* big: fix nat.scan bug. (thanks Evan Shaw)
* bufio: handle a "\r\n" that straddles the buffer.
add openbsd.
avoid redundant bss declarations.
fix unused parameters.
fix windows/amd64 build with newest mingw-w64. (thanks Hector Chu)
* bytes: clarify that NewBuffer is not for beginners.
* cgo: explain how to free something.
fix GoBytes. (thanks Gustavo Niemeyer)
fixes callback for windows amd64. (thanks Wei Guangjing)
note that CString result must be freed. (thanks Gustavo Niemeyer)
* cov: remove tautological #defines. (thanks Lucio De Re)
* dashboard: yet another utf-8 fix.
* doc/codelab/wiki: fix Makefile.
* doc/progs: fix windows/amd64. (thanks Jaroslavas Počepko)
* doc/tmpltohtml: update to new template package.
* doc: emphasize that environment variables are optional.
* effective_go: convert to use tmpltohtml.
* exp/norm: reduced the size of the byte buffer used by reorderBuffer by half by reusing space when combining.
a few minor fixes to support the implementation of norm.
added implementation for []byte versions of methods.
* exp/template/html: add some tests for ">" attributes.
added handling for URL attributes.
differentiate URL-valued attributes (such as href).
reworked escapeText to recognize attr boundaries.
* exp/wingui: made compatible with windows/amd64. (thanks Jaroslavas Počepko)
* flag: add Parsed, restore Usage.
* gc: add openbsd.
escape analysis.
fix build on Plan 9. (thanks Lucio De Re)
fix div bug.
fix pc/line table. (thanks Julian Phillips)
fix some spurious leaks.
make static initialization more static.
remove JCXZ; add JCXZW, JCXZL, and JCXZQ instructions. (thanks Jaroslavas Počepko)
shuffle #includes.
simplify escape analysis recursion.
tweak and enable escape analysis.
* go/ast cleanup: base File/PackageExports on FilterFile/FilterPackage code.
adjustments to filter function.
fix ast.MergePackageFiles to collect infos about imports. (thanks Sebastien Binet)
generalize ast.FilterFile.
* go/build: add test support & use in gotest.
separate test imports out when scanning. (thanks Gustavo Niemeyer)
* go/parser: fix type switch scoping.
fix type switch scoping.
* gob: explain that Debug isn't useful unless it's compiled in.
* gobuilder: increase log limit.
* godashboard: fix utf-8 in user names.
* godoc: first step towards reducing index size.
add dummy playground.js to silence godoc warning at start-up.
added systematic throttling to indexing goroutine.
fix bug in zip.go.
support for reading/writing (splitted) index files.
use virtual file system when generating package synopses.
* gofix: forgot to rename the URL type.
osopen: fixed=true when changing O_CREAT. (thanks Tarmigan Casebolt)
* goinstall: error out with paths that end with '/'. (thanks Tarmigan Casebolt)
report lack of $GOPATH on errors. (thanks Gustavo Niemeyer)
select the tag that is closest to runtime.Version.
* gotry: add missing $. (thanks Tarmigan Casebolt)
* http: add MaxBytesReader to limit request body size.
add file protocol transport.
adjust test threshold for larger suse buffers.
delete error kludge.
on invalid request, send 400 response.
return 413 instead of 400 when the request body is too large. (thanks Dave Cheney)
support setting Transport's TLS client config.
* image/tiff: add a decode benchmark. (thanks Benny Siegert)
decoder optimization. (thanks Benny Siegert)
* image: add PalettedImage interface, and make image/png recognize it. (thanks Jaroslavas Počepko)
* io: add TeeReader. (thanks Hector Chu)
* json: add struct tag option to wrap literals in strings.
calculate Offset for Indent correctly. (thanks Jeff Hodges)
fix decode bug with struct tag names with ,opts being ignored.
* ld: handle Plan 9 ar format. (thanks Lucio De Re)
remove duplicate bss definitions.
* libmach: support reading symbols from Windows .exe for nm. (thanks Mateusz Czapliński)
* math: fix Pow10 loop. (thanks Volker Dobler)
* mime: ParseMediaType returns os.Error now, not a nil map.
media type formatter. (thanks Pascal S. de Kloe)
text charset defaults. (thanks Pascal S. de Kloe)
* misc/dashboard: remove limit for json package list.
* misc/emacs: refine label detection.
* net: add ParseMAC function. (thanks Paul Borman)
change the internal form of IPMask for IPv4. (thanks Mikio Hara)
disable "tcp" test on openbsd.
fix windows build. (thanks Alex Brainman)
join and leave a IPv6 group address, on a specific interface. (thanks Mikio Hara)
make use of IPv4len, IPv6len. (thanks Mikio Hara)
move internal string manipulation routines to parse.go. (thanks Mikio Hara)
* os: disable Hostname test on OpenBSD.
fix WNOHANG Waitmsg. (thanks Gustavo Niemeyer)
* reflect: add Value.Bytes, Value.SetBytes methods.
* rpc: add benchmark for async rpc calls.
* runtime: add openbsd 386 defs.h.
add runtime support for openbsd 386.
add runtime· prefix to showframe.
ctrlhandler for windows amd64. (thanks Wei Guangjing)
fix stack cleanup on windows/amd64. (thanks Hector Chu)
fix void warnings.
go interface to cdecl calbacks. (thanks Jaroslavas Počepko)
handle string + char literals in goc2c.
make arm work on Ubuntu Natty qemu.
openbsd thread tweaks.
simplify stack traces.
speed up cgo calls. (thanks Alex Brainman)
use cgo runtime functions to call windows syscalls. (thanks Alex Brainman)
windows/amd64 callbacks fixed and syscall fixed to allow using it in callbacks. (thanks Jaroslavas Počepko)
* strconv: put decimal on stack.
* spec: update section on Implementation Differences.
* syscall: SOMAXCONN should be 0x7fffffff at winsock2. (thanks Yasuhiro Matsumoto)
add openbsd 386.
handle RTM_NEWROUTE in ParseNetlinkRouteAttr on Linux. (thanks Albert Strasheim)
handle routing entry in ParseRoutingSockaddr on BSD variants. (thanks Mikio Hara)
openbsd amd64 syscall support.
use the vdso page on linux x86 for faster syscalls instead of int $0x80. (thanks Yuval Pavel Zholkover)
* template/parse: give if, range, and with a common representation.
* template: grammar fix for template documentation. (thanks Bill Neubauer)
range over channel.
remove else and end nodes from public view.
* test: put GOROOT/bin before all others in run.
* time: fix Plan 9 build. (thanks Fazlul Shahriar)
fix zone during windows test.
* type switches: test for pathological case.
* version.bash: update VERSION on -save if already present. (thanks Gustavo Niemeyer)
* websocket: implements new version of WebSocket protocol. (thanks Fumitoshi Ukai)
* windows/386: clean stack after syscall. (thanks Jaroslavas Počepko)
* xml: marshal "parent>child" tags correctly. (thanks Ross Light)
</pre>
<h2 id="2011-08-17">2011-08-17 (<a href="release.html#r60">base for r60</a>)</h2>
<pre>
This weekly contains some package re-shuffling. Users of the http and

View File

@@ -16,6 +16,16 @@ Once you've learned a little about the language,
idioms of programming in Go.
</p>
<h3 id="go_tour"><a href="http://go-tour.appspot.com/">A Tour of Go</a></h3>
<p>
An interactive introduction to Go in three sections.
The first section covers basic syntax and data structures; the second discusses
methods and interfaces; and the third introduces Go's concurrency primitives.
Each section concludes with a few exercises so you can practice what you've
learned. You can <a href="http://go-tour.appspot.com/">take the tour online</a> or
<a href="http://code.google.com/p/go-tour/">install it locally</a>.
</p>
<h3 id="orig_tutorial"><a href="go_tutorial.html">A Tutorial for the Go Programming Language</a></h3>
<p>
The first tutorial. An introductory text that touches upon several core
@@ -29,9 +39,9 @@ Slides from a 3-day course about the Go programming language.
A more thorough introduction than the tutorial.
</p>
<ul>
<li><a href="GoCourseDay1.pdf">Day 1: Basics</a> <small>[270KB PDF]</small>
<li><a href="GoCourseDay2.pdf">Day 2: Types, Methods, Interfaces</a> <small>[270KB PDF]</small>
<li><a href="GoCourseDay3.pdf">Day 3: Concurrency and Communication</a> <small>[180KB PDF]</small>
<li><a href="GoCourseDay1.pdf">Day 1: Basics</a> <small>[270KB PDF]</small></li>
<li><a href="GoCourseDay2.pdf">Day 2: Types, Methods, Interfaces</a> <small>[270KB PDF]</small></li>
<li><a href="GoCourseDay3.pdf">Day 3: Concurrency and Communication</a> <small>[180KB PDF]</small></li>
</ul>
<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
@@ -62,12 +72,53 @@ and closures.
<p>
Guided tours of Go programs.
</p>
<ul>
<li><a href="/doc/codewalk/functions">First-Class Functions in Go</a></li>
<li><a href="/doc/codewalk/markov">Generating arbitrary text: a Markov chain algorithm</a></li>
<li><a href="/doc/codewalk/sharemem">Share Memory by Communicating</a></li>
</ul>
<h3 id="go_for_cpp_programmers"><a href="go_for_cpp_programmers.html">Go for C++ Programmers</a></h3>
<p>
An introduction to Go for C++ programmers.
</p>
<h2 id="articles">Go Articles</h2>
<p>
Notable articles from the <a href="http://blog.golang.org/">Go Blog</a>.
</p>
<h3>Language</h3>
<ul>
<li><a href="http://blog.golang.org/2010/04/json-rpc-tale-of-interfaces.html">JSON-RPC: a tale of interfaces</a></li>
<li><a href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">Go's Declaration Syntax</a></li>
<li><a href="http://blog.golang.org/2010/08/defer-panic-and-recover.html">Defer, Panic, and Recover</a></li>
<li><a href="http://blog.golang.org/2010/09/go-concurrency-patterns-timing-out-and.html">Go Concurrency Patterns: Timing out, moving on</a></li>
<li><a href="http://blog.golang.org/2011/01/go-slices-usage-and-internals.html">Go Slices: usage and internals</a></li>
<li><a href="http://blog.golang.org/2011/05/gif-decoder-exercise-in-go-interfaces.html">A GIF decoder: an exercise in Go interfaces</a></li>
<li><a href="http://blog.golang.org/2011/07/error-handling-and-go.html">Error Handling and Go</a></li>
</ul>
<h3>Packages</h3>
<ul>
<li><a href="http://blog.golang.org/2011/01/json-and-go.html">JSON and Go</a> - using the <a href="/pkg/json/">json</a> package.</li>
<li><a href="http://blog.golang.org/2011/03/gobs-of-data.html">Gobs of data</a> - the design and use of the <a href="/pkg/gob/">gob</a> package.</li>
<li><a href="http://blog.golang.org/2011/09/laws-of-reflection.html">The Laws of Reflection</a> - the fundamentals of the <a href="/pkg/reflect/">reflect</a> package.</li>
<li><a href="http://blog.golang.org/2011/09/go-image-package.html">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</a> package.</li>
<li><a href="http://blog.golang.org/2011/09/go-imagedraw-package.html">The Go image/draw package</a> - the fundamentals of the <a href="/pkg/image/draw/">image/draw</a> package.</li>
</ul>
<h3>Tools</h3>
<ul>
<li><a href="http://blog.golang.org/2011/03/c-go-cgo.html">C? Go? Cgo!</a> - linking against C code with <a href="/cmd/cgo/">cgo</a>.</li>
<li><a href="http://blog.golang.org/2011/03/godoc-documenting-go-code.html">Godoc: documenting Go code</a> - writing good documentation for <a href="/cmd/godoc/">godoc</a>.</li>
<li><a href="http://blog.golang.org/2011/06/profiling-go-programs.html">Profiling Go Programs</a></li>
</ul>
<h2 id="tutorials_nonenglish">Non-English Documentation</h2>
<h3 id="docs_be">Belarusian &mdash; Беларуская</h3>
@@ -140,6 +191,11 @@ one goroutine can be guaranteed to observe values produced by writes to the
same variable in a different goroutine.
</p>
<h3 id="debugging_with_gdb"><a href="debugging_with_gdb.html">Debugging Go Code with GDB</a></h3>
<p>
Using GDB to debug Go programs.
</p>
<h2 id="videos_talks">Videos and Talks</h2>
<h3 id="writing_web_apps"><a href="http://www.youtube.com/watch?v=-i0hat7pdpk">Writing Web Apps in Go</a></h3>

View File

@@ -95,7 +95,7 @@ Here's how to compile and run our program. With <code>6g</code>, say,
<pre>
$ 6g helloworld.go # compile; object goes into helloworld.6
$ 6l helloworld.6 # link; output goes into 6.out
$ 6.out
$ ./6.out
Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
$
</pre>
@@ -544,13 +544,12 @@ composite literal, as is done here in the <code>return</code> statement from <co
<p>
We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
<p>
<pre><!--{{code "progs/file.go" `/var/` `/^.$/`}}
<pre><!--{{code "progs/file.go" `/var/` `/^\)/`}}
-->var (
Stdin = newFile(syscall.Stdin, &#34;/dev/stdin&#34;)
Stdout = newFile(syscall.Stdout, &#34;/dev/stdout&#34;)
Stderr = newFile(syscall.Stderr, &#34;/dev/stderr&#34;)
)
</pre>
<p>
The <code>newFile</code> function was not exported because it's internal. The proper,

View File

@@ -87,7 +87,7 @@ Here's how to compile and run our program. With <code>6g</code>, say,
<pre>
$ 6g helloworld.go # compile; object goes into helloworld.6
$ 6l helloworld.6 # link; output goes into 6.out
$ 6.out
$ ./6.out
Hello, world; or Καλημέρα κόσμε; or こんにちは 世界
$
</pre>
@@ -470,7 +470,7 @@ composite literal, as is done here in the <code>return</code> statement from <co
<p>
We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
<p>
{{code "progs/file.go" `/var/` `/^.$/`}}
{{code "progs/file.go" `/var/` `/^\)/`}}
<p>
The <code>newFile</code> function was not exported because it's internal. The proper,
exported factory to use is <code>OpenFile</code> (we'll explain that name in a moment):

View File

@@ -257,7 +257,8 @@ the process of building and testing Go programs.
<h2 id="next">What's next</h2>
<p>
Start by reading the <a href="go_tutorial.html">Go Tutorial</a>.
Start by taking <a href="http://code.google.com/p/go-tour/">A Tour of Go</a>
or reading the <a href="go_tutorial.html">Go Tutorial</a>.
</p>
<p>

View File

@@ -49,10 +49,13 @@ google.setOnLoadCallback(loadFeed);
It's a fast, statically typed, compiled language that feels like a
dynamically typed, interpreted language.
</p>
<h2>Check it out!</h2>
<h2>
Get started now with
<a target="_blank" href="http://go-tour.appspot.com/">A Tour of Go</a>.
</h2>
<p>
<div class="how">[<a href="/doc/playground.html">How does this work?</a>]</div>
<a href="/doc/install.html">Install Go now</a>, or try it right here in your browser:</p>
Or try it right here in your browser:</p>
<div id="playground" class="small"></div>
<script src="/doc/play/playground.js"></script>
</div>

View File

@@ -145,7 +145,7 @@ func run(cmd ...string) ([]byte, os.Error) {
var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
var output = template.Must(template.New("output").Parse(outputText)) // HTML template
var outputText = `<pre>{{html .}}</pre>`
var outputText = `<pre>{{printf "%s" . |html}}</pre>`
var frontPageText = `<!doctype html>
<html>
@@ -256,7 +256,7 @@ function compileUpdate() {
</head>
<body>
<table width="100%"><tr><td width="60%" valign="top">
<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{html .}}</textarea>
<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{printf "%s" . |html}}</textarea>
<div class="hints">
(Shift-Enter to compile and run.)&nbsp;&nbsp;&nbsp;&nbsp;
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke

View File

@@ -92,5 +92,8 @@ process of using cgo. See $GOROOT/misc/cgo/stdio and
$GOROOT/misc/cgo/gmp for examples.
Cgo does not yet work with gccgo.
See "C? Go? Cgo!" for an introduction to using cgo:
http://blog.golang.org/2011/03/c-go-cgo.html
*/
package documentation

View File

@@ -156,13 +156,14 @@ outhist(Biobuf *b)
outzfile(b, p+1);
} else {
// relative name, like dir/file.go
if(h->offset == 0 && pathname && pathname[0] == '/') {
if(h->offset >= 0 && pathname && pathname[0] == '/') {
zfile(b, "/", 1); // leading "/"
outzfile(b, pathname+1);
}
outzfile(b, p);
}
}
}
zhist(b, h->line, h->offset);
}

View File

@@ -126,5 +126,8 @@ one may run godoc as follows:
godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
See "Godoc: documenting Go code" for how to write good comments for godoc:
http://blog.golang.org/2011/03/godoc-documenting-go-code.html
*/
package documentation

View File

@@ -31,6 +31,7 @@ func osopen(f *ast.File) bool {
// Rename O_CREAT to O_CREATE.
if expr, ok := n.(ast.Expr); ok && isPkgDot(expr, "os", "O_CREAT") {
expr.(*ast.SelectorExpr).Sel.Name = "O_CREATE"
fixed = true
return
}

View File

@@ -54,6 +54,29 @@ func f() {
os.OpenFile(a, os.O_SURPRISE|os.O_CREATE, 0666)
_ = os.O_CREATE
}
`,
},
{
Name: "osopen.1",
In: `package main
import (
"os"
)
func f() {
_ = os.O_CREAT
}
`,
Out: `package main
import (
"os"
)
func f() {
_ = os.O_CREATE
}
`,
},
}

View File

@@ -27,6 +27,7 @@ func init() {
}
var urlRenames = []struct{ in, out string }{
{"URL", "URL"},
{"ParseURL", "Parse"},
{"ParseURLReference", "ParseWithReference"},
{"ParseQuery", "ParseQuery"},
@@ -45,7 +46,12 @@ func url(f *ast.File) bool {
fixed := false
// Update URL code.
var skip interface{}
urlWalk := func(n interface{}) {
if n == skip {
skip = nil
return
}
// Is it an identifier?
if ident, ok := n.(*ast.Ident); ok && ident.Name == "url" {
ident.Name = "url_"
@@ -56,6 +62,12 @@ func url(f *ast.File) bool {
fixed = urlDoFields(fn.Params) || fixed
fixed = urlDoFields(fn.Results) || fixed
}
// U{url: ...} is likely a struct field.
if kv, ok := n.(*ast.KeyValueExpr); ok {
if ident, ok := kv.Key.(*ast.Ident); ok && ident.Name == "url" {
skip = ident
}
}
}
// Fix up URL code and add import, at most once.
@@ -63,7 +75,7 @@ func url(f *ast.File) bool {
if fixed {
return
}
walk(f, urlWalk)
walkBeforeAfter(f, urlWalk, nop)
addImport(f, "url")
fixed = true
}

View File

@@ -18,6 +18,7 @@ import (
)
func f() {
var _ http.URL
http.ParseURL(a)
http.ParseURLReference(a)
http.ParseQuery(a)
@@ -33,6 +34,7 @@ func f() {
import "url"
func f() {
var _ url.URL
url.Parse(a)
url.ParseWithReference(a)
url.ParseQuery(a)
@@ -78,10 +80,15 @@ import (
"http"
)
type U struct{ url int }
type M map[int]int
func f() {
http.ParseURL(a)
var url = 23
url, x := 45, y
_ = U{url: url}
_ = M{url + 1: url}
}
func g(url string) string {
@@ -96,10 +103,15 @@ func h() (url string) {
import "url"
type U struct{ url int }
type M map[int]int
func f() {
url.Parse(a)
var url_ = 23
url_, x := 45, y
_ = U{url: url_}
_ = M{url_ + 1: url_}
}
func g(url_ string) string {

View File

@@ -11,3 +11,9 @@ GOFILES=\
make.go\
include ../../Make.cmd
test:
gotest
testshort:
gotest -test.short

View File

@@ -94,8 +94,11 @@ attempt to fetch updates. The -u flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.
When downloading or updating, goinstall first looks for a tag or branch
named "release". If there is one, it uses that version of the code.
When downloading or updating, goinstall looks for a tag with the "go." prefix
that corresponds to the local Go version. For Go "release.r58" it looks for a
tag named "go.r58". For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
If the specific "go.X" tag is not found, it chooses the closest earlier version.
If an appropriate tag is found, goinstall uses that version of the code.
Otherwise it uses the default version selected by the version control
system, typically HEAD for git, tip for Mercurial.

View File

@@ -7,12 +7,15 @@
package main
import (
"bytes"
"exec"
"fmt"
"http"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
)
@@ -36,22 +39,21 @@ func maybeReportToDashboard(path string) {
// a vcs represents a version control system
// like Mercurial, Git, or Subversion.
type vcs struct {
name string
cmd string
metadir string
checkout string
clone string
update string
updateReleaseFlag string
pull string
pullForceFlag string
log string
logLimitFlag string
logReleaseFlag string
check string
protocols []string
suffix string
defaultHosts []host
name string
cmd string
metadir string
checkout string
clone string
update string
updateRevFlag string
pull string
pullForceFlag string
tagList string
tagListRe *regexp.Regexp
check string
protocols []string
suffix string
defaultHosts []host
}
type host struct {
@@ -61,20 +63,18 @@ type host struct {
}
var hg = vcs{
name: "Mercurial",
cmd: "hg",
metadir: ".hg",
checkout: "checkout",
clone: "clone",
update: "update",
updateReleaseFlag: "release",
pull: "pull",
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "-rrelease",
check: "identify",
protocols: []string{"https", "http"},
suffix: ".hg",
name: "Mercurial",
cmd: "hg",
metadir: ".hg",
checkout: "checkout",
clone: "clone",
update: "update",
pull: "pull",
tagList: "tags",
tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
check: "identify",
protocols: []string{"https", "http"},
suffix: ".hg",
defaultHosts: []host{
{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
{regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""},
@@ -82,20 +82,18 @@ var hg = vcs{
}
var git = vcs{
name: "Git",
cmd: "git",
metadir: ".git",
checkout: "checkout",
clone: "clone",
update: "pull",
updateReleaseFlag: "release",
pull: "fetch",
log: "show-ref",
logLimitFlag: "",
logReleaseFlag: "release",
check: "ls-remote",
protocols: []string{"git", "https", "http"},
suffix: ".git",
name: "Git",
cmd: "git",
metadir: ".git",
checkout: "checkout",
clone: "clone",
update: "pull",
pull: "fetch",
tagList: "tag",
tagListRe: regexp.MustCompile("([^\n]+)\n"),
check: "ls-remote",
protocols: []string{"git", "https", "http"},
suffix: ".git",
defaultHosts: []host{
{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/git)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
{regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"},
@@ -103,40 +101,35 @@ var git = vcs{
}
var svn = vcs{
name: "Subversion",
cmd: "svn",
metadir: ".svn",
checkout: "checkout",
clone: "checkout",
update: "update",
updateReleaseFlag: "release",
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "release",
check: "info",
protocols: []string{"https", "http", "svn"},
suffix: ".svn",
name: "Subversion",
cmd: "svn",
metadir: ".svn",
checkout: "checkout",
clone: "checkout",
update: "update",
check: "info",
protocols: []string{"https", "http", "svn"},
suffix: ".svn",
defaultHosts: []host{
{regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""},
},
}
var bzr = vcs{
name: "Bazaar",
cmd: "bzr",
metadir: ".bzr",
checkout: "update",
clone: "branch",
update: "update",
updateReleaseFlag: "-rrelease",
pull: "pull",
pullForceFlag: "--overwrite",
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "-rrelease",
check: "info",
protocols: []string{"https", "http", "bzr"},
suffix: ".bzr",
name: "Bazaar",
cmd: "bzr",
metadir: ".bzr",
checkout: "update",
clone: "branch",
update: "update",
updateRevFlag: "-r",
pull: "pull",
pullForceFlag: "--overwrite",
tagList: "tags",
tagListRe: regexp.MustCompile("([^ ]+)[^\n]+\n"),
check: "info",
protocols: []string{"https", "http", "bzr"},
suffix: ".bzr",
defaultHosts: []host{
{regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""},
},
@@ -240,20 +233,84 @@ func download(pkg, srcDir string) (public bool, err os.Error) {
return
}
// Try to detect if a "release" tag exists. If it does, update
// to the tagged version, otherwise just update the current branch.
// NOTE(_nil): svn will always fail because it is trying to get
// the revision history of a file named "release" instead of
// looking for a commit with a release tag
// updateRepo gets a list of tags in the repository and
// checks out the tag closest to the current runtime.Version.
// If no matching tag is found, it just updates to tip.
func (v *vcs) updateRepo(dst string) os.Error {
if err := quietRun(dst, nil, v.cmd, v.log, v.logLimitFlag, v.logReleaseFlag); err == nil {
if err := run(dst, nil, v.cmd, v.checkout, v.updateReleaseFlag); err != nil {
return err
}
} else if err := run(dst, nil, v.cmd, v.update); err != nil {
if v.tagList == "" || v.tagListRe == nil {
// TODO(adg): fix for svn
return run(dst, nil, v.cmd, v.update)
}
// Get tag list.
stderr := new(bytes.Buffer)
cmd := exec.Command(v.cmd, v.tagList)
cmd.Dir = dst
cmd.Stderr = stderr
b, err := cmd.Output()
if err != nil {
errorf("%s %s: %s\n", v.cmd, v.tagList, stderr)
return err
}
return nil
var tags []string
for _, m := range v.tagListRe.FindAllStringSubmatch(string(b), -1) {
tags = append(tags, m[1])
}
// Only use the tag component of runtime.Version.
ver := strings.Split(runtime.Version(), " ")[0]
// Select tag.
if tag := selectTag(ver, tags); tag != "" {
printf("selecting revision %q\n", tag)
return run(dst, nil, v.cmd, v.checkout, v.updateRevFlag+tag)
}
// No matching tag found, make default selection.
printf("selecting tip\n")
return run(dst, nil, v.cmd, v.update)
}
// selectTag returns the closest matching tag for a given version.
// Closest means the latest one that is not after the current release.
// Version "release.rN" matches tags of the form "go.rN" (N being a decimal).
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
func selectTag(goVersion string, tags []string) (match string) {
const rPrefix = "release.r"
if strings.HasPrefix(goVersion, rPrefix) {
p := "go.r"
v, err := strconv.Atof64(goVersion[len(rPrefix):])
if err != nil {
return ""
}
var matchf float64
for _, t := range tags {
if !strings.HasPrefix(t, p) {
continue
}
tf, err := strconv.Atof64(t[len(p):])
if err != nil {
continue
}
if matchf < tf && tf <= v {
match, matchf = t, tf
}
}
}
const wPrefix = "weekly."
if strings.HasPrefix(goVersion, wPrefix) {
p := "go.weekly."
v := goVersion[len(wPrefix):]
for _, t := range tags {
if !strings.HasPrefix(t, p) {
continue
}
if match < t && t[len(p):] <= v {
match = t
}
}
}
return match
}
// checkoutRepo checks out repo into dst using vcs.

View File

@@ -71,6 +71,13 @@ func errorf(format string, args ...interface{}) {
logf(format, args...)
}
func terrorf(tree *build.Tree, format string, args ...interface{}) {
if tree != nil && tree.Goroot && os.Getenv("GOPATH") == "" {
format = strings.TrimRight(format, "\n") + " ($GOPATH not set)\n"
}
errorf(format, args...)
}
func main() {
flag.Usage = usage
flag.Parse()
@@ -156,7 +163,7 @@ func logPackage(pkg string, tree *build.Tree) (logged bool) {
name := filepath.Join(tree.Path, logfile)
fout, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
logf("%s\n", err)
terrorf(tree, "package log: %s\n", err)
return false
}
fmt.Fprintf(fout, "%s\n", pkg)
@@ -182,6 +189,12 @@ func install(pkg, parent string) {
visit[pkg] = done
}()
// Don't allow trailing '/'
if _, f := filepath.Split(pkg); f == "" {
errorf("%s should not have trailing '/'\n", pkg)
return
}
// Check whether package is local or remote.
// If remote, download or update it.
tree, pkg, err := build.FindTree(pkg)
@@ -209,7 +222,7 @@ func install(pkg, parent string) {
}
}
if err != nil {
errorf("%s: %v\n", pkg, err)
terrorf(tree, "%s: %v\n", pkg, err)
return
}
dir := filepath.Join(tree.SrcDir(), pkg)
@@ -217,11 +230,11 @@ func install(pkg, parent string) {
// Install prerequisites.
dirInfo, err := build.ScanDir(dir, parent == "")
if err != nil {
errorf("%s: %v\n", pkg, err)
terrorf(tree, "%s: %v\n", pkg, err)
return
}
if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 {
errorf("%s: package has no files\n", pkg)
terrorf(tree, "%s: package has no files\n", pkg)
return
}
for _, p := range dirInfo.Imports {
@@ -237,13 +250,13 @@ func install(pkg, parent string) {
if *useMake {
err := domake(dir, pkg, tree, dirInfo.IsCommand())
if err != nil {
errorf("%s: install: %v\n", pkg, err)
terrorf(tree, "%s: install: %v\n", pkg, err)
return
}
} else {
script, err := build.Build(tree, pkg, dirInfo)
if err != nil {
errorf("%s: install: %v\n", pkg, err)
terrorf(tree, "%s: install: %v\n", pkg, err)
return
}
if *nuke {
@@ -257,7 +270,7 @@ func install(pkg, parent string) {
if script.Stale() {
printf("%s: install\n", pkg)
if err := script.Run(); err != nil {
errorf("%s: install: %v\n", pkg, err)
terrorf(tree, "%s: install: %v\n", pkg, err)
return
}
} else {

View File

@@ -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.
package main
import "testing"
var selectTagTestTags = []string{
"go.r58",
"go.r58.1",
"go.r59",
"go.r59.1",
"go.r61",
"go.r61.1",
"go.weekly.2010-01-02",
"go.weekly.2011-10-12",
"go.weekly.2011-10-12.1",
"go.weekly.2011-10-14",
"go.weekly.2011-11-01",
// these should be ignored:
"release.r59",
"release.r59.1",
"release",
"weekly.2011-10-12",
"weekly.2011-10-12.1",
"weekly",
"foo",
"bar",
"go.f00",
"go!r60",
"go.1999-01-01",
}
var selectTagTests = []struct {
version string
selected string
}{
{"release.r57", ""},
{"release.r58.2", "go.r58.1"},
{"release.r59", "go.r59"},
{"release.r59.1", "go.r59.1"},
{"release.r60", "go.r59.1"},
{"release.r60.1", "go.r59.1"},
{"release.r61", "go.r61"},
{"release.r66", "go.r61.1"},
{"weekly.2010-01-01", ""},
{"weekly.2010-01-02", "go.weekly.2010-01-02"},
{"weekly.2010-01-02.1", "go.weekly.2010-01-02"},
{"weekly.2010-01-03", "go.weekly.2010-01-02"},
{"weekly.2011-10-12", "go.weekly.2011-10-12"},
{"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"},
{"weekly.2011-10-13", "go.weekly.2011-10-12.1"},
{"weekly.2011-10-14", "go.weekly.2011-10-14"},
{"weekly.2011-10-14.1", "go.weekly.2011-10-14"},
{"weekly.2011-11-01", "go.weekly.2011-11-01"},
{"weekly.2014-01-01", "go.weekly.2011-11-01"},
{"weekly.3000-01-01", "go.weekly.2011-11-01"},
// faulty versions:
{"release.f00", ""},
{"weekly.1999-01-01", ""},
{"junk", ""},
{"", ""},
}
func TestSelectTag(t *testing.T) {
for _, c := range selectTagTests {
selected := selectTag(c.version, selectTagTestTags)
if selected != c.selected {
t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected)
}
}
}

View File

@@ -1356,7 +1356,7 @@ synthesizemaptypes(DWDie *die)
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
copychildren(dwhs, hash_subtable);
substitutetype(dwhs, "end", defptrto(dwhe));
substitutetype(dwhs, "last", defptrto(dwhe));
substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hash_subtable, DW_AT_byte_size)->value, nil);
@@ -1578,13 +1578,16 @@ addhistfile(char *zentry)
histfile[histfilesize++] = "<eof>";
fname = decodez(zentry);
// print("addhistfile %d: %s\n", histfilesize, fname);
if (fname == 0)
return -1;
// Don't fill with duplicates (check only top one).
if (strcmp(fname, histfile[histfilesize-1]) == 0) {
free(fname);
return histfilesize - 1;
}
histfile[histfilesize++] = fname;
return histfilesize - 1;
}
@@ -1608,11 +1611,13 @@ finddebugruntimepath(void)
}
// Go's runtime C sources are sane, and Go sources nest only 1 level,
// so 16 should be plenty.
// so a handful would be plenty, if it weren't for the fact that line
// directives can push an unlimited number of them.
static struct {
int file;
vlong line;
} includestack[16];
} *includestack;
static int includestacksize;
static int includetop;
static vlong absline;
@@ -1629,17 +1634,15 @@ static Linehist *linehist;
static void
checknesting(void)
{
int i;
if (includetop < 0) {
diag("dwarf: corrupt z stack");
errorexit();
}
if (includetop >= nelem(includestack)) {
diag("dwarf: nesting too deep");
for (i = 0; i < nelem(includestack); i++)
diag("\t%s", histfile[includestack[i].file]);
errorexit();
if (includetop >= includestacksize) {
includestacksize += 1;
includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize);
includestack = realloc(includestack, includestacksize * sizeof *includestack);
}
}
@@ -1669,6 +1672,7 @@ inithist(Auto *a)
// Clear the history.
clearhistfile();
includetop = 0;
checknesting();
includestack[includetop].file = 0;
includestack[includetop].line = -1;
absline = 0;
@@ -1682,10 +1686,10 @@ inithist(Auto *a)
for (; a; a = a->link) {
if (a->type == D_FILE) { // 'z'
int f = addhistfile(a->asym->name);
if (f < 0) { // pop file
if (f < 0) { // pop file
includetop--;
checknesting();
} else if(f != includestack[includetop].file) { // pushed a new file
} else { // pushed a file (potentially same)
includestack[includetop].line += a->aoffset - absline;
includetop++;
checknesting();

View File

@@ -240,7 +240,6 @@ NOTEST+=\
../cmd/cgo\
../cmd/ebnflint\
../cmd/godoc\
../cmd/goinstall\
../cmd/gotest\
../cmd/goyacc\
../cmd/hgpatch\

View File

@@ -221,6 +221,9 @@ In summary, a gob stream looks like
where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream.
See "Gobs of data" for a design discussion of the gob wire format:
http://blog.golang.org/2011/03/gobs-of-data.html
*/
package gob

View File

@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package draw provides image composition functions
// in the style of the Plan 9 graphics library
// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
// and the X Render extension.
// Package draw provides image composition functions.
//
// See "The Go image/draw package" for an introduction to this package:
// http://blog.golang.org/2011/09/go-imagedraw-package.html
package draw
import (

View File

@@ -3,6 +3,9 @@
// license that can be found in the LICENSE file.
// Package image implements a basic 2-D image library.
//
// See "The Go image package" for an introduction to this package:
// http://blog.golang.org/2011/09/go-image-package.html
package image
// Config holds an image's color model and dimensions.

View File

@@ -11,5 +11,6 @@ GOFILES=\
indent.go\
scanner.go\
stream.go\
tags.go\
include ../../Make.pkg

View File

@@ -140,6 +140,7 @@ type decodeState struct {
scan scanner
nextscan scanner // for calls to nextValue
savedError os.Error
tempstr string // scratch space to avoid some allocations
}
// errPhase is used for errors that should not happen unless
@@ -470,6 +471,8 @@ func (d *decodeState) object(v reflect.Value) {
// Figure out field corresponding to key.
var subv reflect.Value
destring := false // whether the value is wrapped in a string to be decoded first
if mv.IsValid() {
elemType := mv.Type().Elem()
if !mapElem.IsValid() {
@@ -486,7 +489,8 @@ func (d *decodeState) object(v reflect.Value) {
if isValidTag(key) {
for i := 0; i < sv.NumField(); i++ {
f = st.Field(i)
if f.Tag.Get("json") == key {
tagName, _ := parseTag(f.Tag.Get("json"))
if tagName == key {
ok = true
break
}
@@ -508,6 +512,8 @@ func (d *decodeState) object(v reflect.Value) {
} else {
subv = sv.FieldByIndex(f.Index)
}
_, opts := parseTag(f.Tag.Get("json"))
destring = opts.Contains("string")
}
}
@@ -520,8 +526,12 @@ func (d *decodeState) object(v reflect.Value) {
}
// Read value.
d.value(subv)
if destring {
d.value(reflect.ValueOf(&d.tempstr))
d.literalStore([]byte(d.tempstr), subv)
} else {
d.value(subv)
}
// Write value back to map;
// if using struct, subv points into struct already.
if mv.IsValid() {
@@ -550,8 +560,12 @@ func (d *decodeState) literal(v reflect.Value) {
// Scan read one byte too far; back up.
d.off--
d.scan.undo(op)
item := d.data[start:d.off]
d.literalStore(d.data[start:d.off], v)
}
// literalStore decodes a literal stored in item into v.
func (d *decodeState) literalStore(item []byte, v reflect.Value) {
// Check for unmarshaler.
wantptr := item[0] == 'n' // null
unmarshaler, pv := d.indirect(v, wantptr)

View File

@@ -262,7 +262,10 @@ type All struct {
Float32 float32
Float64 float64
Foo string `json:"bar"`
Foo string `json:"bar"`
Foo2 string `json:"bar2,dummyopt"`
IntStr int64 `json:",string"`
PBool *bool
PInt *int
@@ -331,6 +334,8 @@ var allValue = All{
Float32: 14.1,
Float64: 15.1,
Foo: "foo",
Foo2: "foo2",
IntStr: 42,
String: "16",
Map: map[string]Small{
"17": {Tag: "tag17"},
@@ -391,6 +396,8 @@ var allValueIndent = `{
"Float32": 14.1,
"Float64": 15.1,
"bar": "foo",
"bar2": "foo2",
"IntStr": "42",
"PBool": null,
"PInt": null,
"PInt8": null,
@@ -481,6 +488,8 @@ var pallValueIndent = `{
"Float32": 0,
"Float64": 0,
"bar": "",
"bar2": "",
"IntStr": "0",
"PBool": true,
"PInt": 2,
"PInt8": 3,

View File

@@ -4,6 +4,9 @@
// Package json implements encoding and decoding of JSON objects as defined in
// RFC 4627.
//
// See "JSON and Go" for an introduction to this package:
// http://blog.golang.org/2011/01/json-and-go.html
package json
import (
@@ -14,7 +17,6 @@ import (
"runtime"
"sort"
"strconv"
"strings"
"unicode"
"utf8"
)
@@ -59,6 +61,12 @@ import (
// // Note the leading comma.
// Field int `json:",omitempty"`
//
// The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. This extra level of encoding is sometimes
// used when communicating with JavaScript programs:
//
// Int64String int64 `json:",string"`
//
// The key name will be used if it's a non-empty string consisting of
// only Unicode letters, digits, dollar signs, hyphens, and underscores.
//
@@ -221,6 +229,12 @@ func isEmptyValue(v reflect.Value) bool {
}
func (e *encodeState) reflectValue(v reflect.Value) {
e.reflectValueQuoted(v, false)
}
// reflectValueQuoted writes the value in v to the output.
// If quoted is true, the serialization is wrapped in a JSON string.
func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
if !v.IsValid() {
e.WriteString("null")
return
@@ -238,26 +252,39 @@ func (e *encodeState) reflectValue(v reflect.Value) {
return
}
writeString := (*encodeState).WriteString
if quoted {
writeString = (*encodeState).string
}
switch v.Kind() {
case reflect.Bool:
x := v.Bool()
if x {
e.WriteString("true")
writeString(e, "true")
} else {
e.WriteString("false")
writeString(e, "false")
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.WriteString(strconv.Itoa64(v.Int()))
writeString(e, strconv.Itoa64(v.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
e.WriteString(strconv.Uitoa64(v.Uint()))
writeString(e, strconv.Uitoa64(v.Uint()))
case reflect.Float32, reflect.Float64:
e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
case reflect.String:
e.string(v.String())
if quoted {
sb, err := Marshal(v.String())
if err != nil {
e.error(err)
}
e.string(string(sb))
} else {
e.string(v.String())
}
case reflect.Struct:
e.WriteByte('{')
@@ -269,17 +296,14 @@ func (e *encodeState) reflectValue(v reflect.Value) {
if f.PkgPath != "" {
continue
}
tag, omitEmpty := f.Name, false
tag, omitEmpty, quoted := f.Name, false, false
if tv := f.Tag.Get("json"); tv != "" {
ss := strings.SplitN(tv, ",", 2)
if isValidTag(ss[0]) {
tag = ss[0]
}
if len(ss) > 1 {
// Currently the only option is omitempty,
// so parsing is trivial.
omitEmpty = ss[1] == "omitempty"
name, opts := parseTag(tv)
if isValidTag(name) {
tag = name
}
omitEmpty = opts.Contains("omitempty")
quoted = opts.Contains("string")
}
fieldValue := v.Field(i)
if omitEmpty && isEmptyValue(fieldValue) {
@@ -292,7 +316,7 @@ func (e *encodeState) reflectValue(v reflect.Value) {
}
e.string(tag)
e.WriteByte(':')
e.reflectValue(fieldValue)
e.reflectValueQuoted(fieldValue, quoted)
}
e.WriteByte('}')
@@ -380,7 +404,8 @@ func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
func (sv stringValues) get(i int) string { return sv[i].String() }
func (e *encodeState) string(s string) {
func (e *encodeState) string(s string) (int, os.Error) {
len0 := e.Len()
e.WriteByte('"')
start := 0
for i := 0; i < len(s); {
@@ -425,4 +450,5 @@ func (e *encodeState) string(s string) {
e.WriteString(s[start:])
}
e.WriteByte('"')
return e.Len() - len0, nil
}

View File

@@ -5,6 +5,8 @@
package json
import (
"bytes"
"reflect"
"testing"
)
@@ -42,3 +44,39 @@ func TestOmitEmpty(t *testing.T) {
t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
}
}
type StringTag struct {
BoolStr bool `json:",string"`
IntStr int64 `json:",string"`
StrStr string `json:",string"`
}
var stringTagExpected = `{
"BoolStr": "true",
"IntStr": "42",
"StrStr": "\"xzbit\""
}`
func TestStringTag(t *testing.T) {
var s StringTag
s.BoolStr = true
s.IntStr = 42
s.StrStr = "xzbit"
got, err := MarshalIndent(&s, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != stringTagExpected {
t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
}
// Verify that it round-trips.
var s2 StringTag
err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if !reflect.DeepEqual(s, s2) {
t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
}
}

44
src/pkg/json/tags.go Normal file
View File

@@ -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.
package json
import (
"strings"
)
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains returns whether checks that a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}

28
src/pkg/json/tags_test.go Normal file
View File

@@ -0,0 +1,28 @@
// 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 json
import (
"testing"
)
func TestTagParsing(t *testing.T) {
name, opts := parseTag("field,foobar,foo")
if name != "field" {
t.Fatalf("name = %q, want field", name)
}
for _, tt := range []struct {
opt string
want bool
}{
{"foobar", true},
{"foo", true},
{"bar", false},
} {
if opts.Contains(tt.opt) != tt.want {
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
}
}
}

View File

@@ -10,6 +10,9 @@
// A call to ValueOf returns a Value representing the run-time data.
// Zero takes a Type and returns a Value representing a zero value
// for that type.
//
// See "The Laws of Reflection" for an introduction to reflection in Go:
// http://blog.golang.org/2011/09/laws-of-reflection.html
package reflect
import (

View File

@@ -54,7 +54,7 @@ struct hash_subtable {
uint8 datasize; /* bytes of client data in an entry */
uint8 max_probes; /* max number of probes when searching */
int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */
struct hash_entry *end; /* points just past end of entry[] */
struct hash_entry *last; /* points to last element of entry[] */
struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
};
@@ -101,7 +101,7 @@ hash_subtable_new (Hmap *h, int32 power, int32 used)
st->datasize = h->datasize;
st->max_probes = max_probes;
st->limit_bytes = limit_bytes;
st->end = HASH_OFFSET (st->entry, bytes);
st->last = HASH_OFFSET (st->entry, bytes) - 1;
memset (st->entry, HASH_NIL_MEMSET, bytes);
return (st);
}
@@ -160,7 +160,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
{
int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize);
struct hash_entry *end_e = st->end;
struct hash_entry *last_e = st->last;
int32 shift = HASH_BITS - (st->power + st->used);
int32 index_mask = (((hash_hash_t)1) << st->power) - 1;
int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize;
@@ -170,10 +170,10 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
int32 bytes;
while (dst_e != src_e) {
if (src_e != end_e) {
if (src_e <= last_e) {
struct hash_entry *cp_e = src_e;
int32 save_dst_i = dst_i;
while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL &&
while (cp_e <= last_e && (hash = cp_e->hash) != HASH_NIL &&
((hash >> shift) & index_mask) <= dst_i) {
cp_e = HASH_OFFSET (cp_e, elemsize);
dst_i++;
@@ -183,7 +183,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
dst_e = HASH_OFFSET (dst_e, bytes);
src_e = cp_e;
src_i += dst_i - save_dst_i;
if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) {
if (src_e <= last_e && (hash = src_e->hash) != HASH_NIL) {
skip = ((hash >> shift) & index_mask) - dst_i;
} else {
skip = src_i - dst_i;
@@ -224,7 +224,7 @@ hash_conv (Hmap *h,
}
de = e;
while (e != st->end &&
while (e <= st->last &&
(e_hash = e->hash) != HASH_NIL &&
(e_hash & HASH_MASK) != HASH_SUBHASH) {
struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize);
@@ -235,14 +235,14 @@ hash_conv (Hmap *h,
de = target_e;
}
if ((hash & prefix_mask) == current ||
(ne != st->end && (e_hash = ne->hash) != HASH_NIL &&
(ne <= st->last && (e_hash = ne->hash) != HASH_NIL &&
(e_hash & prefix_mask) == current)) {
struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
assert (rc == 0);
memcpy(dummy_result, e->data, h->datasize);
e = ne;
while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
assert (rc == 0);
@@ -271,13 +271,13 @@ 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]);
*pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags));
struct hash_entry *end_e = old_st->end;
struct hash_entry *last_e = old_st->last;
struct hash_entry *e;
void *dummy_result;
int32 used = 0;
flags |= HASH_REHASH;
for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) {
for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) {
hash_hash_t hash = e->hash;
if (hash != HASH_NIL) {
int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
@@ -428,13 +428,13 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
ins_e_hash = 0;
/* move ins_e to point at the end of the contiguous block, but
stop if any element can't be moved by one up */
while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL &&
while (ins_e <= st->last && (ins_e_hash = ins_e->hash) != HASH_NIL &&
ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes &&
(ins_e_hash & HASH_MASK) != HASH_SUBHASH) {
ins_e = HASH_OFFSET (ins_e, elemsize);
ins_i++;
}
if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) {
if (e == end_e || ins_e > st->last || ins_e_hash != HASH_NIL) {
e = end_e; /* can't insert; must grow or convert to subtable */
} else { /* make space for element */
memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e);
@@ -477,17 +477,17 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
struct hash_entry *e;
hash_hash_t e_hash;
struct hash_iter_sub *sub = &it->subtable_state[it->i];
struct hash_entry *end;
struct hash_entry *last;
for (;;) {
int32 shift = HASH_BITS - (st->power + used);
int32 index_mask = (1 << st->power) - 1;
int32 i = (last_hash >> shift) & index_mask;
end = st->end;
last = st->last;
e = HASH_OFFSET (st->entry, i * elemsize);
sub->start = st->entry;
sub->end = end;
sub->last = last;
if ((e->hash & HASH_MASK) != HASH_SUBHASH) {
break;
@@ -497,7 +497,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
used += st->power;
st = *(struct hash_subtable **)e->data;
}
while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
e = HASH_OFFSET (e, elemsize);
}
sub->e = e;
@@ -509,7 +509,7 @@ hash_next (struct hash_iter *it)
int32 elemsize = it->elemsize;
struct hash_iter_sub *sub = &it->subtable_state[it->i];
struct hash_entry *e = sub->e;
struct hash_entry *end = sub->end;
struct hash_entry *last = sub->last;
hash_hash_t e_hash = 0;
if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */
@@ -518,7 +518,7 @@ hash_next (struct hash_iter *it)
iter_restart (it, it->h->st, 0);
sub = &it->subtable_state[it->i];
e = sub->e;
end = sub->end;
last = sub->last;
}
if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
@@ -531,16 +531,16 @@ hash_next (struct hash_iter *it)
e = pe;
pe = HASH_OFFSET (pe, -elemsize);
}
while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
e = HASH_OFFSET (e, elemsize);
}
}
for (;;) {
while (e != end && (e_hash = e->hash) == HASH_NIL) {
while (e <= last && (e_hash = e->hash) == HASH_NIL) {
e = HASH_OFFSET (e, elemsize);
}
if (e == end) {
if (e > last) {
if (it->i == 0) {
it->last_hash = HASH_OFFSET (e, -elemsize)->hash;
sub->e = e;
@@ -549,7 +549,7 @@ hash_next (struct hash_iter *it)
it->i--;
sub = &it->subtable_state[it->i];
e = sub->e;
end = sub->end;
last = sub->last;
}
} else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
it->last_hash = e->hash;
@@ -565,7 +565,7 @@ hash_next (struct hash_iter *it)
sub = &it->subtable_state[it->i];
sub->e = e = st->entry;
sub->start = st->entry;
sub->end = end = st->end;
sub->last = last = st->last;
}
}
}
@@ -580,7 +580,7 @@ hash_iter_init (Hmap *h, struct hash_iter *it)
it->last_hash = 0;
it->subtable_state[0].e = h->st->entry;
it->subtable_state[0].start = h->st->entry;
it->subtable_state[0].end = h->st->end;
it->subtable_state[0].last = h->st->last;
}
static void
@@ -588,11 +588,11 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
{
int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
struct hash_entry *e = st->entry;
struct hash_entry *end = st->end;
int32 lslots = (((byte *) end) - (byte *) e) / elemsize;
struct hash_entry *last = st->last;
int32 lslots = (((byte *) (last+1)) - (byte *) e) / elemsize;
int32 lused = 0;
while (e != end) {
while (e <= last) {
hash_hash_t hash = e->hash;
if ((hash & HASH_MASK) == HASH_SUBHASH) {
clean_st (*(struct hash_subtable **)e->data, slots, used);
@@ -627,7 +627,7 @@ hash_visit_internal (struct hash_subtable *st,
int32 shift = HASH_BITS - (used + st->power);
int32 i = 0;
while (e != st->end) {
while (e <= st->last) {
int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1);
if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
(*data_visit) (arg, level, e->data);

View File

@@ -87,7 +87,7 @@ struct hash_iter {
struct hash_iter_sub {
struct hash_entry *e; /* pointer into subtable */
struct hash_entry *start; /* start of subtable */
struct hash_entry *end; /* end of subtable */
struct hash_entry *last; /* last entry in subtable */
} subtable_state[4]; /* Should be large enough unless the hashing is
so bad that many distinct data values hash
to the same hash value. */

View File

@@ -91,8 +91,8 @@ class MapTypePrinter:
def traverse_hash(self, stab):
ptr = stab['entry'].address
end = stab['end']
while ptr < end:
last = stab['last']
while ptr <= last:
v = ptr.dereference()
ptr = ptr + 1
if v['hash'] == 0: continue

View File

@@ -294,7 +294,7 @@ This defines two templates, T1 and T2, and a third T3 that invokes the other two
when it is executed.
The second way to build a template set is to use Set's Add method to add a
parsed template to a set. A template may be bound at most one set. If it's
parsed template to a set. A template may be bound to at most one set. If it's
necessary to have a template in multiple sets, the template definition must be
parsed multiple times to create distinct *Template values.

View File

@@ -196,23 +196,25 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
// mark top of stack before any variables in the body are pushed.
mark := s.mark()
oneIteration := func(index, elem reflect.Value) {
// Set top var (lexically the second if there are two) to the element.
if len(r.Pipe.Decl) > 0 {
s.setVar(1, elem)
}
// Set next var (lexically the first if there are two) to the index.
if len(r.Pipe.Decl) > 1 {
s.setVar(2, index)
}
s.walk(elem, r.List)
s.pop(mark)
}
switch val.Kind() {
case reflect.Array, reflect.Slice:
if val.Len() == 0 {
break
}
for i := 0; i < val.Len(); i++ {
elem := val.Index(i)
// Set top var (lexically the second if there are two) to the element.
if len(r.Pipe.Decl) > 0 {
s.setVar(1, elem)
}
// Set next var (lexically the first if there are two) to the index.
if len(r.Pipe.Decl) > 1 {
s.setVar(2, reflect.ValueOf(i))
}
s.walk(elem, r.List)
s.pop(mark)
oneIteration(reflect.ValueOf(i), val.Index(i))
}
return
case reflect.Map:
@@ -220,17 +222,23 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
break
}
for _, key := range val.MapKeys() {
elem := val.MapIndex(key)
// Set top var (lexically the second if there are two) to the element.
if len(r.Pipe.Decl) > 0 {
s.setVar(1, elem)
oneIteration(key, val.MapIndex(key))
}
return
case reflect.Chan:
if val.IsNil() {
break
}
i := 0
for ; ; i++ {
elem, ok := val.Recv()
if !ok {
break
}
// Set next var (lexically the first if there are two) to the key.
if len(r.Pipe.Decl) > 1 {
s.setVar(2, key)
}
s.walk(elem, r.List)
s.pop(mark)
oneIteration(reflect.ValueOf(i), elem)
}
if i == 0 {
break
}
return
case reflect.Invalid:
@@ -498,7 +506,18 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
s.errorf("invalid value; expected %s", typ)
}
if !value.Type().AssignableTo(typ) {
s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
// Does one dereference or indirection work? We could do more, as we
// do with method receivers, but that gets messy and method receivers
// are much more constrained, so it makes more sense there than here.
// Besides, one is almost always all you need.
switch {
case value.Kind() == reflect.Ptr && value.Elem().Type().AssignableTo(typ):
value = value.Elem()
case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
value = value.Addr()
default:
s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
}
}
return value
}

View File

@@ -391,6 +391,8 @@ var execTests = []execTest{
{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
// Cute examples.
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
@@ -414,6 +416,11 @@ var execTests = []execTest{
{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
// Stringer.
{"bug5", "{{.Str}}", "foozle", tVal, true},
// Args need to be indirected and dereferenced sometimes.
{"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
{"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
{"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
{"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
}
func zeroArgs() string {
@@ -424,9 +431,35 @@ func oneArg(a string) string {
return "oneArg=" + a
}
// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
func count(n int) chan string {
if n == 0 {
return nil
}
c := make(chan string)
go func() {
for i := 0; i < n; i++ {
c <- "abcdefghijklmnop"[i : i+1]
}
close(c)
}()
return c
}
// vfunc takes a *V and a V
func vfunc(V, *V) string {
return "vfunc"
}
func testExecute(execTests []execTest, set *Set, t *testing.T) {
b := new(bytes.Buffer)
funcs := FuncMap{"zeroArgs": zeroArgs, "oneArg": oneArg, "typeOf": typeOf}
funcs := FuncMap{
"count": count,
"oneArg": oneArg,
"typeOf": typeOf,
"vfunc": vfunc,
"zeroArgs": zeroArgs,
}
for _, test := range execTests {
tmpl := New(test.name).Funcs(funcs)
_, err := tmpl.ParseInSet(test.input, set)

View File

@@ -278,53 +278,51 @@ func lexInsideAction(l *lexer) stateFn {
// Either number, quoted string, or identifier.
// Spaces separate and are ignored.
// Pipe symbols separate and are emitted.
for {
if strings.HasPrefix(l.input[l.pos:], rightDelim) {
return lexRightDelim
}
switch r := l.next(); {
case r == eof || r == '\n':
return l.errorf("unclosed action")
case isSpace(r):
l.ignore()
case r == ':':
if l.next() != '=' {
return l.errorf("expected :=")
}
l.emit(itemColonEquals)
case r == '|':
l.emit(itemPipe)
case r == '"':
return lexQuote
case r == '`':
return lexRawQuote
case r == '$':
return lexIdentifier
case r == '\'':
return lexChar
case r == '.':
// special look-ahead for ".field" so we don't break l.backup().
if l.pos < len(l.input) {
r := l.input[l.pos]
if r < '0' || '9' < r {
return lexIdentifier // itemDot comes from the keyword table.
}
}
fallthrough // '.' can start a number.
case r == '+' || r == '-' || ('0' <= r && r <= '9'):
l.backup()
return lexNumber
case isAlphaNumeric(r):
l.backup()
return lexIdentifier
case r <= unicode.MaxASCII && unicode.IsPrint(r):
l.emit(itemChar)
return lexInsideAction
default:
return l.errorf("unrecognized character in action: %#U", r)
}
if strings.HasPrefix(l.input[l.pos:], rightDelim) {
return lexRightDelim
}
return nil
switch r := l.next(); {
case r == eof || r == '\n':
return l.errorf("unclosed action")
case isSpace(r):
l.ignore()
case r == ':':
if l.next() != '=' {
return l.errorf("expected :=")
}
l.emit(itemColonEquals)
case r == '|':
l.emit(itemPipe)
case r == '"':
return lexQuote
case r == '`':
return lexRawQuote
case r == '$':
return lexIdentifier
case r == '\'':
return lexChar
case r == '.':
// special look-ahead for ".field" so we don't break l.backup().
if l.pos < len(l.input) {
r := l.input[l.pos]
if r < '0' || '9' < r {
return lexIdentifier // itemDot comes from the keyword table.
}
}
fallthrough // '.' can start a number.
case r == '+' || r == '-' || ('0' <= r && r <= '9'):
l.backup()
return lexNumber
case isAlphaNumeric(r):
l.backup()
return lexIdentifier
case r <= unicode.MaxASCII && unicode.IsPrint(r):
l.emit(itemChar)
return lexInsideAction
default:
return l.errorf("unrecognized character in action: %#U", r)
}
return lexInsideAction
}
// lexIdentifier scans an alphanumeric or field.

View File

@@ -184,6 +184,20 @@ var lexTests = []lexTest{
tLeft,
{itemError, `bad number syntax: "3k"`},
}},
// Fixed bugs
// Many elements in an action blew the lookahead until
// we made lexInsideAction not loop.
{"long pipeline deadlock", "{{|||||}}", []item{
tLeft,
tPipe,
tPipe,
tPipe,
tPipe,
tPipe,
tRight,
tEOF,
}},
}
// collect gathers the emitted items into a slice.

View File

@@ -35,8 +35,8 @@ const (
NodeBool // A boolean constant.
NodeCommand // An element of a pipeline.
NodeDot // The cursor, dot.
NodeElse // An else action.
NodeEnd // An end action.
nodeElse // An else action. Not added to tree.
nodeEnd // An end action. Not added to tree.
NodeField // A field or method name.
NodeIdentifier // An identifier; always a function name.
NodeIf // An if action.
@@ -356,36 +356,37 @@ func (s *StringNode) String() string {
return fmt.Sprintf("S=%#q", s.Text)
}
// EndNode represents an {{end}} action. It is represented by a nil pointer.
type EndNode bool
// endNode represents an {{end}} action. It is represented by a nil pointer.
// It does not appear in the final parse tree.
type endNode bool
func newEnd() *EndNode {
func newEnd() *endNode {
return nil
}
func (e *EndNode) Type() NodeType {
return NodeEnd
func (e *endNode) Type() NodeType {
return nodeEnd
}
func (e *EndNode) String() string {
func (e *endNode) String() string {
return "{{end}}"
}
// ElseNode represents an {{else}} action.
type ElseNode struct {
// elseNode represents an {{else}} action. Does not appear in the final tree.
type elseNode struct {
NodeType
Line int // The line number in the input.
}
func newElse(line int) *ElseNode {
return &ElseNode{NodeType: NodeElse, Line: line}
func newElse(line int) *elseNode {
return &elseNode{NodeType: nodeElse, Line: line}
}
func (e *ElseNode) Type() NodeType {
return NodeElse
func (e *elseNode) Type() NodeType {
return nodeElse
}
func (e *ElseNode) String() string {
func (e *elseNode) String() string {
return "{{else}}"
}

View File

@@ -173,7 +173,7 @@ func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
for t.peek().typ != itemEOF {
n := t.textOrAction()
switch n.Type() {
case NodeEnd, NodeElse:
case nodeEnd, nodeElse:
return list, n
}
list.append(n)
@@ -278,10 +278,10 @@ func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list,
var next Node
list, next = t.itemList(false)
switch next.Type() {
case NodeEnd: //done
case NodeElse:
case nodeEnd: //done
case nodeElse:
elseList, next = t.itemList(false)
if next.Type() != NodeEnd {
if next.Type() != nodeEnd {
t.errorf("expected end; found %s", next)
}
elseList = elseList

View File

@@ -37,7 +37,7 @@ func Set(text string, funcs ...map[string]interface{}) (tree map[string]*Tree, e
if end == nil {
t.errorf("unexpected EOF in %s", context)
}
if end.Type() != NodeEnd {
if end.Type() != nodeEnd {
t.errorf("unexpected %s in %s", end, context)
}
t.stopParse()

83
test/dwarf/linedirectives.go Executable file
View File

@@ -0,0 +1,83 @@
// $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.
//line foo/bar.y:4
package main
//line foo/bar.y:60
func main() {
//line foo/bar.y:297
f, l := 0, 0
//line yacctab:1
f, l = 1, 1
//line yaccpar:1
f, l = 2, 1
//line foo/bar.y:82
f, l = 3, 82
//line foo/bar.y:90
f, l = 3, 90
//line foo/bar.y:92
f, l = 3, 92
//line foo/bar.y:100
f, l = 3, 100
//line foo/bar.y:104
l = 104
//line foo/bar.y:112
l = 112
//line foo/bar.y:117
l = 117
//line foo/bar.y:121
l = 121
//line foo/bar.y:125
l = 125
//line foo/bar.y:133
l = 133
//line foo/bar.y:146
l = 146
//line foo/bar.y:148
//line foo/bar.y:153
//line foo/bar.y:155
l = 155
//line foo/bar.y:160
//line foo/bar.y:164
//line foo/bar.y:173
//line foo/bar.y:178
//line foo/bar.y:180
//line foo/bar.y:185
//line foo/bar.y:195
//line foo/bar.y:197
//line foo/bar.y:202
//line foo/bar.y:204
//line foo/bar.y:208
//line foo/bar.y:211
//line foo/bar.y:213
//line foo/bar.y:215
//line foo/bar.y:217
//line foo/bar.y:221
//line foo/bar.y:229
//line foo/bar.y:236
//line foo/bar.y:238
//line foo/bar.y:240
//line foo/bar.y:244
//line foo/bar.y:249
//line foo/bar.y:253
//line foo/bar.y:257
//line foo/bar.y:262
//line foo/bar.y:267
//line foo/bar.y:272
if l == f {
//line foo/bar.y:277
panic("aie!")
//line foo/bar.y:281
}
//line foo/bar.y:285
return
//line foo/bar.y:288
//line foo/bar.y:290
}
//line foo/bar.y:293
//line foo/bar.y:295

29
test/dwarf/main.go Normal file
View File

@@ -0,0 +1,29 @@
// $G $D/$F.go $D/z*.go && $L $F.$A && ./$A.out
// 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
func main() {
F1()
F2()
F3()
F4()
F5()
F6()
F7()
F8()
F9()
F10()
F11()
F12()
F13()
F14()
F15()
F16()
F17()
F18()
F19()
F20()
}

5
test/dwarf/z1.go Normal file
View File

@@ -0,0 +1,5 @@
//line x1.go:4
package main
func F1() {}

6
test/dwarf/z10.go Normal file
View File

@@ -0,0 +1,6 @@
//line x10.go:4
package main
func F10() {}

4
test/dwarf/z11.go Normal file
View File

@@ -0,0 +1,4 @@
//line x11.go:4
package main
func F11() {}

4
test/dwarf/z12.go Normal file
View File

@@ -0,0 +1,4 @@
//line x12.go:4
package main
func F12() {}

4
test/dwarf/z13.go Normal file
View File

@@ -0,0 +1,4 @@
//line x13.go:4
package main
func F13() {}

4
test/dwarf/z14.go Normal file
View File

@@ -0,0 +1,4 @@
//line x14.go:4
package main
func F14() {}

4
test/dwarf/z15.go Normal file
View File

@@ -0,0 +1,4 @@
//line x15.go:4
package main
func F15() {}

4
test/dwarf/z16.go Normal file
View File

@@ -0,0 +1,4 @@
//line x16.go:4
package main
func F16() {}

4
test/dwarf/z17.go Normal file
View File

@@ -0,0 +1,4 @@
//line x17.go:4
package main
func F17() {}

5
test/dwarf/z18.go Normal file
View File

@@ -0,0 +1,5 @@
//line x18.go:4
package main
func F18() {}

4
test/dwarf/z19.go Normal file
View File

@@ -0,0 +1,4 @@
//line x19.go:4
package main
func F19() {}

4
test/dwarf/z2.go Normal file
View File

@@ -0,0 +1,4 @@
//line x2.go:4
package main
func F2() {}

4
test/dwarf/z20.go Normal file
View File

@@ -0,0 +1,4 @@
//line x20.go:4
package main
func F20() {}

4
test/dwarf/z3.go Normal file
View File

@@ -0,0 +1,4 @@
//line x3.go:4
package main
func F3() {}

4
test/dwarf/z4.go Normal file
View File

@@ -0,0 +1,4 @@
//line x4.go:4
package main
func F4() {}

4
test/dwarf/z5.go Normal file
View File

@@ -0,0 +1,4 @@
//line x5.go:4
package main
func F5() {}

4
test/dwarf/z6.go Normal file
View File

@@ -0,0 +1,4 @@
//line x6.go:4
package main
func F6() {}

4
test/dwarf/z7.go Normal file
View File

@@ -0,0 +1,4 @@
//line x7.go:4
package main
func F7() {}

4
test/dwarf/z8.go Normal file
View File

@@ -0,0 +1,4 @@
//line x8.go:4
package main
func F8() {}

4
test/dwarf/z9.go Normal file
View File

@@ -0,0 +1,4 @@
//line x9.go:4
package main
func F9() {}

View File

@@ -124,6 +124,8 @@ panic: interface conversion: *main.S is not main.I2: missing method Name
== syntax/
== dwarf/
== fixedbugs/
=========== fixedbugs/bug027.go

View File

@@ -53,7 +53,7 @@ filterout() {
grep '^'"$2"'$' $1 >/dev/null
}
for dir in . ken chan interface nilptr syntax fixedbugs bugs
for dir in . ken chan interface nilptr syntax dwarf fixedbugs bugs
do
echo
echo '==' $dir'/'