pkg: added some manually crafted builtins
Change-Id: I1e5d8b987b2fbd2605a9ff5853dc3b1e7eb9b620
diff --git a/pkg/encoding/csv/manual.go b/pkg/encoding/csv/manual.go
new file mode 100644
index 0000000..1e2338c
--- /dev/null
+++ b/pkg/encoding/csv/manual.go
@@ -0,0 +1,60 @@
+// Copyright 2018 The 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 csv
+
+import (
+ "bytes"
+ "encoding/csv"
+ "io"
+
+ "cuelang.org/go/cue"
+)
+
+// Encode encode the given list of lists to CSV.
+func Encode(x cue.Value) (string, error) {
+ buf := &bytes.Buffer{}
+ w := csv.NewWriter(buf)
+ iter, err := x.List()
+ if err != nil {
+ return "", err
+ }
+ for iter.Next() {
+ row, err := iter.Value().List()
+ if err != nil {
+ return "", err
+ }
+ a := []string{}
+ for row.Next() {
+ col := row.Value()
+ if str, err := col.String(); err == nil {
+ a = append(a, str)
+ } else {
+ b, err := col.MarshalJSON()
+ if err != nil {
+ return "", err
+ }
+ a = append(a, string(b))
+ }
+ }
+ w.Write(a)
+ }
+ w.Flush()
+ return buf.String(), nil
+}
+
+// Decode reads in a csv into a list of lists.
+func Decode(r io.Reader) ([][]string, error) {
+ return csv.NewReader(r).ReadAll()
+}
diff --git a/pkg/encoding/hex/manual.go b/pkg/encoding/hex/manual.go
new file mode 100644
index 0000000..9f1ca55
--- /dev/null
+++ b/pkg/encoding/hex/manual.go
@@ -0,0 +1,22 @@
+// Copyright 2018 The 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 hex
+
+import "encoding/hex"
+
+// Encode returns the hexadecimal encoding of src.
+func Encode(src []byte) string {
+ return hex.EncodeToString(src)
+}
diff --git a/pkg/encoding/json/manual.go b/pkg/encoding/json/manual.go
new file mode 100644
index 0000000..9b2d324
--- /dev/null
+++ b/pkg/encoding/json/manual.go
@@ -0,0 +1,104 @@
+// Copyright 2018 The 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 json
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/cue/parser"
+ "cuelang.org/go/cue/token"
+)
+
+// Compact generates the JSON-encoded src with insignificant space characters
+// elided.
+func Compact(src []byte) (string, error) {
+ dst := bytes.Buffer{}
+ if err := json.Compact(&dst, src); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+}
+
+// Indent creates an indented form of the JSON-encoded src.
+// Each element in a JSON object or array begins on a new,
+// indented line beginning with prefix followed by one or more
+// copies of indent according to the indentation nesting.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, to make it easier to embed inside other formatted JSON data.
+// Although leading space characters (space, tab, carriage return, newline)
+// at the beginning of src are dropped, trailing space characters
+// at the end of src are preserved and copied to dst.
+// For example, if src has no trailing spaces, neither will dst;
+// if src ends in a trailing newline, so will dst.
+func Indent(src []byte, prefix, indent string) (string, error) {
+ dst := bytes.Buffer{}
+ if err := json.Indent(&dst, src, prefix, indent); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+}
+
+// HTMLEscape returns the JSON-encoded src with <, >, &, U+2028 and
+// U+2029 characters inside string literals changed to \u003c, \u003e, \u0026,
+// \u2028, \u2029 so that the JSON will be safe to embed inside HTML <script>
+// tags. For historical reasons, web browsers don't honor standard HTML escaping
+// within <script> tags, so an alternative JSON encoding must be used.
+func HTMLEscape(src []byte) string {
+ dst := &bytes.Buffer{}
+ json.HTMLEscape(dst, src)
+ return dst.String()
+}
+
+// Marshal returns the JSON encoding of v.
+func Marshal(v cue.Value) (string, error) {
+ b, err := json.Marshal(v)
+ return string(b), err
+}
+
+// MarshalStream turns a list into a stream of JSON objects.
+func MarshalStream(v cue.Value) (string, error) {
+ // TODO: return an io.Reader and allow asynchronous processing.
+ iter, err := v.List()
+ if err != nil {
+ return "", err
+ }
+ buf := &bytes.Buffer{}
+ for iter.Next() {
+ b, err := json.Marshal(iter.Value())
+ if err != nil {
+ return "", err
+ }
+ buf.Write(b)
+ buf.WriteByte('\n')
+ }
+ return buf.String(), nil
+}
+
+// Unmarshal parses the JSON-encoded data.
+func Unmarshal(b []byte) (*cue.Instance, error) {
+ if !json.Valid(b) {
+ return nil, fmt.Errorf("json: invalid JSON")
+ }
+ fset := token.NewFileSet()
+ expr, err := parser.ParseExpr(fset, "json", b)
+ if err != nil {
+ // NOTE: should never happen.
+ return nil, fmt.Errorf("json: could not parse JSON: %v", err)
+ }
+ return cue.FromExpr(fset, expr)
+}
diff --git a/pkg/encoding/yaml/manual.go b/pkg/encoding/yaml/manual.go
new file mode 100644
index 0000000..c4e609a
--- /dev/null
+++ b/pkg/encoding/yaml/manual.go
@@ -0,0 +1,61 @@
+// Copyright 2018 The 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 yaml
+
+import (
+ "bytes"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/cue/token"
+ "cuelang.org/go/internal/third_party/yaml"
+ goyaml "github.com/ghodss/yaml"
+)
+
+// Marshal returns the YAML encoding of v.
+func Marshal(v cue.Value) (string, error) {
+ b, err := goyaml.Marshal(v)
+ return string(b), err
+}
+
+// MarshalStream returns the YAML encoding of v.
+func MarshalStream(v cue.Value) (string, error) {
+ // TODO: return an io.Reader and allow asynchronous processing.
+ iter, err := v.List()
+ if err != nil {
+ return "", err
+ }
+ buf := &bytes.Buffer{}
+ for i := 0; iter.Next(); i++ {
+ if i > 0 {
+ buf.WriteString("---\n")
+ }
+ b, err := goyaml.Marshal(iter.Value())
+ if err != nil {
+ return "", err
+ }
+ buf.Write(b)
+ }
+ return buf.String(), nil
+}
+
+// Unmarshal parses the YAML to a CUE instance.
+func Unmarshal(data []byte) (*cue.Instance, error) {
+ fset := token.NewFileSet()
+ expr, err := yaml.Unmarshal(fset, "", data)
+ if err != nil {
+ return nil, err
+ }
+ return cue.FromExpr(fset, expr)
+}
diff --git a/pkg/math/bits/manual.go b/pkg/math/bits/manual.go
new file mode 100644
index 0000000..f7376a6
--- /dev/null
+++ b/pkg/math/bits/manual.go
@@ -0,0 +1,129 @@
+// Copyright 2018 The 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.
+
+// Copyright 2018 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 bits
+
+import (
+ "math/big"
+ "math/bits"
+)
+
+// And returns the bitwise and of a and b (a & b in Go).
+//
+func And(a, b *big.Int) *big.Int {
+ wa := a.Bits()
+ wb := b.Bits()
+ n := len(wa)
+ if len(wb) < n {
+ n = len(wb)
+ }
+ w := make([]big.Word, n)
+ for i := range w {
+ w[i] = wa[i] & wb[i]
+ }
+ i := &big.Int{}
+ i.SetBits(w)
+ return i
+}
+
+// Or returns the bitwise or of a and b (a | b in Go).
+//
+func Or(a, b *big.Int) *big.Int {
+ wa := a.Bits()
+ wb := b.Bits()
+ var w []big.Word
+ n := len(wa)
+ if len(wa) > len(wb) {
+ w = append(w, wa...)
+ n = len(wb)
+ } else {
+ w = append(w, wb...)
+ }
+ for i := 0; i < n; i++ {
+ w[i] = wa[i] | wb[i]
+ }
+ i := &big.Int{}
+ i.SetBits(w)
+ return i
+}
+
+// Xor returns the bitwise xor of a and b (a ^ b in Go).
+//
+func Xor(a, b *big.Int) *big.Int {
+ wa := a.Bits()
+ wb := b.Bits()
+ var w []big.Word
+ n := len(wa)
+ if len(wa) > len(wb) {
+ w = append(w, wa...)
+ n = len(wb)
+ } else {
+ w = append(w, wb...)
+ }
+ for i := 0; i < n; i++ {
+ w[i] = wa[i] ^ wb[i]
+ }
+ i := &big.Int{}
+ i.SetBits(w)
+ return i
+}
+
+// Clear returns the bitwise and not of a and b (a &^ b in Go).
+//
+func Clear(a, b *big.Int) *big.Int {
+ wa := a.Bits()
+ wb := b.Bits()
+ w := append([]big.Word(nil), wa...)
+ for i, m := range wb {
+ if i >= len(w) {
+ break
+ }
+ w[i] = wa[i] &^ m
+ }
+ i := &big.Int{}
+ i.SetBits(w)
+ return i
+}
+
+// TODO: ShiftLeft, maybe trailing and leading zeros
+
+// OnesCount returns the number of one bits ("population count") in x.
+func OnesCount(x uint64) int {
+ return bits.OnesCount64(x)
+}
+
+// RotateLeft returns the value of x rotated left by (k mod UintSize) bits.
+// To rotate x right by k bits, call RotateLeft(x, -k).
+func RotateLeft(x uint64, k int) uint64 {
+ return bits.RotateLeft64(x, k)
+}
+
+// Reverse returns the value of x with its bits in reversed order.
+func Reverse(x uint64) uint64 {
+ return bits.Reverse64(x)
+}
+
+// ReverseBytes returns the value of x with its bytes in reversed order.
+func ReverseBytes(x uint64) uint64 {
+ return bits.ReverseBytes64(x)
+}
+
+// Len returns the minimum number of bits required to represent x; the result is 0 for x == 0.
+func Len(x uint64) int {
+ return bits.Len64(x)
+}
diff --git a/pkg/path/manual.go b/pkg/path/manual.go
new file mode 100644
index 0000000..99525a7
--- /dev/null
+++ b/pkg/path/manual.go
@@ -0,0 +1,28 @@
+// Copyright 2018 The 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 path
+
+import "path"
+
+var split = path.Split
+
+// Split splits path immediately following the final slash and returns them as
+// the list [dir, file], separating it into a directory and file name component.
+// If there is no slash in path, Split returns an empty dir and file set to
+// path. The returned values have the property that path = dir+file.
+func Split(path string) []string {
+ file, dir := split(path)
+ return []string{file, dir}
+}
diff --git a/pkg/strconv/manual.go b/pkg/strconv/manual.go
new file mode 100644
index 0000000..e179ad4
--- /dev/null
+++ b/pkg/strconv/manual.go
@@ -0,0 +1,24 @@
+// Copyright 2018 The 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 strconv
+
+// Unquote interprets s as a single-quoted, double-quoted,
+// or backquoted CUE string literal, returning the string value
+// that s quotes.
+func Unquote(s string) (string, error) {
+ return Unquote(s)
+}
+
+// TODO: replace parsing functions with parsing to apd
diff --git a/pkg/strings/manual.go b/pkg/strings/manual.go
new file mode 100644
index 0000000..7018115
--- /dev/null
+++ b/pkg/strings/manual.go
@@ -0,0 +1,58 @@
+// Copyright 2018 The 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 strings
+
+import (
+ "strings"
+ "unicode"
+)
+
+// ToTitle returns a copy of the string s with all Unicode letters that begin
+// words mapped to their title case.
+func ToTitle(s string) string {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return strings.Map(
+ func(r rune) rune {
+ if unicode.IsSpace(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// ToCamel returns a copy of the string s with all Unicode letters that begin
+// words mapped to lower case.
+func ToCamel(s string) string {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return strings.Map(
+ func(r rune) rune {
+ if unicode.IsSpace(prev) {
+ prev = r
+ return unicode.ToLower(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
diff --git a/pkg/text/tabwriter/manual.go b/pkg/text/tabwriter/manual.go
new file mode 100644
index 0000000..b031a5b
--- /dev/null
+++ b/pkg/text/tabwriter/manual.go
@@ -0,0 +1,38 @@
+// Copyright 2018 The 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 tabwriter
+
+import (
+ "bytes"
+ "text/tabwriter"
+
+ "cuelang.org/go/cue"
+)
+
+// Write formats text in columns. See golang.org/pkg/text/tabwriter for more
+// info.
+func Write(data cue.Value) (string, error) {
+ buf := &bytes.Buffer{}
+ tw := tabwriter.NewWriter(buf, 0, 4, 1, ' ', 0)
+ b, err := data.Bytes()
+ if err != nil {
+ return "", err
+ }
+ _, err = tw.Write(b)
+ if err != nil {
+ return "", err
+ }
+ return buf.String(), err
+}
diff --git a/pkg/text/template/manual.go b/pkg/text/template/manual.go
new file mode 100644
index 0000000..3895917
--- /dev/null
+++ b/pkg/text/template/manual.go
@@ -0,0 +1,35 @@
+// Copyright 2018 The 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 template
+
+import (
+ "bytes"
+ "text/template"
+
+ "cuelang.org/go/cue"
+)
+
+// Execute executes a Go-style template.
+func Execute(templ string, data cue.Value) (string, error) {
+ t, err := template.New("").Parse(templ)
+ if err != nil {
+ return "", err
+ }
+ buf := &bytes.Buffer{}
+ if err := t.Execute(buf, data); err != nil {
+ return "", err
+ }
+ return buf.String(), nil
+}