string: add GoString method

This allows you to say fmt.Sprintf("%#v", s) to get the unquoted
string.

Change-Id: I013aaec0110c34a89f1c6a234a917a0009c27697
diff --git a/value.go b/value.go
index 237e55f..921bb60 100644
--- a/value.go
+++ b/value.go
@@ -403,9 +403,16 @@
 // but strings are not directly iterable. Instead, iterate
 // over the result of calling one of these four methods:
 // codepoints, codepoint_ords, elems, elem_ords.
+//
+// Warning: the contract of the Value interface's String method is that
+// it returns the value printed in Skylark notation,
+// so s.String() or fmt.Sprintf("%s", s) returns a quoted string.
+// Use string(s) or s.GoString() or fmt.Sprintf("%#v", s) to obtain the raw contents
+// of a Skylark string as a Go string.
 type String string
 
 func (s String) String() string        { return strconv.Quote(string(s)) }
+func (s String) GoString() string      { return string(s) }
 func (s String) Type() string          { return "string" }
 func (s String) Freeze()               {} // immutable
 func (s String) Truth() Bool           { return len(s) > 0 }
@@ -622,7 +629,7 @@
 func (d *Dict) AttrNames() []string             { return builtinAttrNames(dictMethods) }
 
 // Set is an backwards-compatibility alias for SetKey.
-func (d *Dict) Set(k, v Value) error { return d.SetKey(k, v)}
+func (d *Dict) Set(k, v Value) error { return d.SetKey(k, v) }
 
 func (x *Dict) CompareSameType(op syntax.Token, y_ Value, depth int) (bool, error) {
 	y := y_.(*Dict)
diff --git a/value_test.go b/value_test.go
index 6b24432..b1fddae 100644
--- a/value_test.go
+++ b/value_test.go
@@ -2,17 +2,41 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+package skylark_test
+
 // This file defines tests of the Value API.
-package skylark
 
 import (
+	"fmt"
 	"testing"
+
+	"github.com/google/skylark"
 )
 
+func TestStringMethod(t *testing.T) {
+	s := skylark.String("hello")
+	for i, test := range [][2]string{
+		// quoted string:
+		{s.String(), `"hello"`},
+		{fmt.Sprintf("%s", s), `"hello"`},
+		{fmt.Sprintf("%+s", s), `"hello"`},
+		{fmt.Sprintf("%v", s), `"hello"`},
+		{fmt.Sprintf("%+v", s), `"hello"`},
+		// unquoted:
+		{s.GoString(), `hello`},
+		{fmt.Sprintf("%#v", s), `hello`},
+	} {
+		got, want := test[0], test[1]
+		if got != want {
+			t.Errorf("#%d: got <<%s>>, want <<%s>>", i, got, want)
+		}
+	}
+}
+
 func TestListAppend(t *testing.T) {
-	l := NewList(nil)
-	l.Append(String("hello"))
-	res, ok := AsString(l.Index(0))
+	l := skylark.NewList(nil)
+	l.Append(skylark.String("hello"))
+	res, ok := skylark.AsString(l.Index(0))
 	if !ok {
 		t.Errorf("failed list.Append() got: %s, want: skylark.String", l.Index(0).Type())
 	}