cue/parser: factor out source reading into internal package

Change-Id: If592e5d2d8e5191cf8ad8d4a4bfdc5d7e91acebf
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2340
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/parser/error_test.go b/cue/parser/error_test.go
index 628c9c6..0118acb 100644
--- a/cue/parser/error_test.go
+++ b/cue/parser/error_test.go
@@ -42,6 +42,7 @@
 	"cuelang.org/go/cue/errors"
 	"cuelang.org/go/cue/scanner"
 	"cuelang.org/go/cue/token"
+	"cuelang.org/go/internal/source"
 )
 
 const testdata = "testdata"
@@ -148,7 +149,7 @@
 
 func checkErrors(t *testing.T, filename string, input interface{}) {
 	t.Helper()
-	src, err := readSource(filename, input)
+	src, err := source.Read(filename, input)
 	if err != nil {
 		t.Error(err)
 		return
diff --git a/cue/parser/interface.go b/cue/parser/interface.go
index 1c37728..980cb2e 100644
--- a/cue/parser/interface.go
+++ b/cue/parser/interface.go
@@ -17,43 +17,11 @@
 package parser
 
 import (
-	"bytes"
-	"fmt"
-	"io"
-	"io/ioutil"
-
 	"cuelang.org/go/cue/ast"
 	"cuelang.org/go/cue/token"
+	"cuelang.org/go/internal/source"
 )
 
-// If src != nil, readSource converts src to a []byte if possible;
-// otherwise it returns an error. If src == nil, readSource returns
-// the result of reading the file specified by filename.
-//
-func readSource(filename string, src interface{}) ([]byte, error) {
-	if src != nil {
-		switch s := src.(type) {
-		case string:
-			return []byte(s), nil
-		case []byte:
-			return s, nil
-		case *bytes.Buffer:
-			// is io.Reader, but src is already available in []byte form
-			if s != nil {
-				return s.Bytes(), nil
-			}
-		case io.Reader:
-			var buf bytes.Buffer
-			if _, err := io.Copy(&buf, s); err != nil {
-				return nil, err
-			}
-			return buf.Bytes(), nil
-		}
-		return nil, fmt.Errorf("invalid source type %T", src)
-	}
-	return ioutil.ReadFile(filename)
-}
-
 // Option specifies a parse option.
 type Option func(p *parser)
 
@@ -137,7 +105,7 @@
 func ParseFile(filename string, src interface{}, mode ...Option) (f *ast.File, err error) {
 
 	// get source
-	text, err := readSource(filename, src)
+	text, err := source.Read(filename, src)
 	if err != nil {
 		return nil, err
 	}
@@ -181,7 +149,7 @@
 // be nil.
 func ParseExpr(filename string, src interface{}, mode ...Option) (ast.Expr, error) {
 	// get source
-	text, err := readSource(filename, src)
+	text, err := source.Read(filename, src)
 	if err != nil {
 		return nil, err
 	}
diff --git a/cue/parser/interface_test.go b/cue/parser/interface_test.go
index 371f162..197eeda 100644
--- a/cue/parser/interface_test.go
+++ b/cue/parser/interface_test.go
@@ -19,6 +19,7 @@
 	"testing"
 
 	"cuelang.org/go/cue/ast"
+	"cuelang.org/go/internal/source"
 )
 
 func Test_readSource(t *testing.T) {
@@ -35,7 +36,7 @@
 		// TODO: Add test cases.
 	}
 	for _, tt := range tests {
-		got, err := readSource(tt.args.filename, tt.args.src)
+		got, err := source.Read(tt.args.filename, tt.args.src)
 		if (err != nil) != tt.wantErr {
 			t.Errorf("%q. readSource() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 			continue
diff --git a/internal/source/source.go b/internal/source/source.go
new file mode 100644
index 0000000..3844844
--- /dev/null
+++ b/internal/source/source.go
@@ -0,0 +1,53 @@
+// Copyright 2019 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package source contains utility functions that standardize reading source
+// bytes across cue packages.
+package source
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+)
+
+// Read loads the source bytes for the given arguments. If src != nil,
+// Read converts src to a []byte if possible; otherwise it returns an
+// error. If src == nil, readSource returns the result of reading the file
+// specified by filename.
+//
+func Read(filename string, src interface{}) ([]byte, error) {
+	if src != nil {
+		switch s := src.(type) {
+		case string:
+			return []byte(s), nil
+		case []byte:
+			return s, nil
+		case *bytes.Buffer:
+			// is io.Reader, but src is already available in []byte form
+			if s != nil {
+				return s.Bytes(), nil
+			}
+		case io.Reader:
+			var buf bytes.Buffer
+			if _, err := io.Copy(&buf, s); err != nil {
+				return nil, err
+			}
+			return buf.Bytes(), nil
+		}
+		return nil, fmt.Errorf("invalid source type %T", src)
+	}
+	return ioutil.ReadFile(filename)
+}