cue: generate and add builtins
Change-Id: Icecfdae9a52d30374e5b6111e62efcf23b89aadd
diff --git a/cue/ast_test.go b/cue/ast_test.go
index 4fe6367..1f6ae18 100644
--- a/cue/ast_test.go
+++ b/cue/ast_test.go
@@ -19,6 +19,8 @@
"testing"
"cuelang.org/go/cue/errors"
+ "cuelang.org/go/cue/parser"
+ "cuelang.org/go/cue/token"
)
func TestCompile(t *testing.T) {
@@ -287,3 +289,70 @@
})
}
}
+
+func TestEval(t *testing.T) {
+ testCases := []struct {
+ in string
+ expr string
+ out string
+ }{{
+ in: `
+ hello: "Hello"
+ world: "World"
+ `,
+ expr: `"\(hello), \(world)!"`,
+ out: `"Hello, World!"`,
+ }, {
+ in: `
+ a: { b: 2, c: 3 }
+ z: 1
+ `,
+ expr: `a.b + a.c + z`,
+ out: `6`,
+ }, {
+ in: `
+ a: { b: 2, c: 3 }
+ `,
+ expr: `{ d: a.b + a.c }`,
+ out: `<0>{d: 5}`,
+ }, {
+ in: `
+ a: "Hello World!"
+ `,
+ expr: `strings.ToUpper(a)`,
+ out: `"HELLO WORLD!"`,
+ }, {
+ in: `
+ a: 0x8
+ b: 0x1`,
+ expr: `bits.Or(a, b)`, // package shorthand
+ out: `9`,
+ }, {
+ in: `
+ a: 0x8
+ b: 0x1`,
+ expr: `math.Or(a, b)`,
+ out: `_|_(<0>.Or:undefined field "Or")`,
+ }, {
+ in: `a: 0x8`,
+ expr: `mathematics.Abs(a)`,
+ out: `_|_(reference "mathematics" not found)`,
+ }}
+ for _, tc := range testCases {
+ t.Run("", func(t *testing.T) {
+ ctx, inst, errs := compileInstance(t, tc.in)
+ if errs != nil {
+ t.Fatal(errs)
+ }
+ expr, err := parser.ParseExpr(token.NewFileSet(), "<test>", tc.expr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ evaluated := inst.evalExpr(ctx, expr)
+ v := testResolve(ctx, evaluated, evalFull)
+ if got := debugStr(ctx, v); got != tc.out {
+ t.Errorf("output differs:\ngot %q\nwant %q", got, tc.out)
+ }
+ })
+ }
+}
diff --git a/cue/builtin.go b/cue/builtin.go
index 3aab148..daaaae0 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:generate go run gen.go
+
package cue
import (
diff --git a/cue/builtin_test.go b/cue/builtin_test.go
index 9befd60..c35c9bb 100644
--- a/cue/builtin_test.go
+++ b/cue/builtin_test.go
@@ -15,8 +15,10 @@
package cue
import (
+ "fmt"
"math/big"
"reflect"
+ "strings"
"testing"
"cuelang.org/go/cue/ast"
@@ -125,3 +127,111 @@
})
}
}
+
+func TestBuiltins(t *testing.T) {
+ test := func(pkg, expr string) []*bimport {
+ return []*bimport{&bimport{"",
+ []string{fmt.Sprintf("import %q\n(%s)", pkg, expr)},
+ }}
+ }
+ testExpr := func(expr string) []*bimport {
+ return []*bimport{&bimport{"",
+ []string{fmt.Sprintf("(%s)", expr)},
+ }}
+ }
+ testCases := []struct {
+ instances []*bimport
+ emit string
+ }{{
+ test("math", "math.Pi"),
+ `3.14159265358979323846264338327950288419716939937510582097494459`,
+ }, {
+ test("math", "math.Floor(math.Pi)"),
+ `3`,
+ }, {
+ test("math", "math.Pi(3)"),
+ `_|_(<0>.Pi:cannot call non-function 3.14159265358979323846264338327950288419716939937510582097494459 (type float))`,
+ }, {
+ test("math", "math.Floor(3, 5)"),
+ `_|_(<0>.Floor (3,5):number of arguments does not match (1 vs 2))`,
+ }, {
+ test("math", `math.Floor("foo")`),
+ `_|_(<0>.Floor ("foo"):argument 1 requires type number, found string)`,
+ }, {
+ test("encoding/hex", `hex.Encode("foo")`),
+ `"666f6f"`,
+ }, {
+ test("encoding/hex", `hex.Decode(hex.Encode("foo"))`),
+ `'foo'`,
+ }, {
+ test("encoding/hex", `hex.Decode("foo")`),
+ `_|_(<0>.Decode ("foo"):call error: encoding/hex: invalid byte: U+006F 'o')`,
+ }, {
+ test("strconv", `strconv.FormatUint(64, 16)`),
+ `"40"`,
+ }, {
+ // Find a better alternative, as this call should go.
+ test("strconv", `strconv.FormatFloat(3.02, 300, 4, 64)`),
+ `_|_(<0>.FormatFloat (3.02,300,4,64):argument 1 out of range: has 9 > 8 bits)`,
+ }, {
+ // Find a better alternative, as this call should go.
+ test("strconv", `strconv.FormatFloat(3.02, -1, 4, 64)`),
+ `_|_(<0>.FormatFloat (3.02,-1,4,64):argument 1 must be a positive integer)`,
+ }, {
+ // Find a better alternative, as this call should go.
+ test("strconv", `strconv.FormatFloat(3.02, 1.0, 4, 64)`),
+ `_|_(<0>.FormatFloat (3.02,1.0,4,64):argument 2 requires type int, found float)`,
+ }, {
+ // Panics
+ test("math", `math.Jacobi(1000, 2000)`),
+ `_|_(<0>.Jacobi (1000,2000):call error: big: invalid 2nd argument to Int.Jacobi: need odd integer but got 2000)`,
+ }, {
+ test("math", `math.Jacobi(1000, 201)`),
+ `1`,
+ }, {
+ test("math", `math.Asin(2.0e400)`),
+ `_|_(<0>.Asin (2.0e+400):invalid argument 0: cue: value was rounded up)`,
+ }, {
+ test("encoding/csv", `csv.Decode("1,2,3\n4,5,6")`),
+ `[["1","2","3"],["4","5","6"]]`,
+ }, {
+ test("strconv", `strconv.FormatBool(true)`),
+ `"true"`,
+ }, {
+ test("strings", `strings.Join(["Hello", "World!"], " ")`),
+ `"Hello World!"`,
+ }, {
+ test("strings", `strings.Join([1, 2], " ")`),
+ `_|_(<0>.Join ([1,2]," "):list element 1: not of right kind (number vs string))`,
+ }, {
+ test("math/bits", `bits.Or(0x8, 0x1)`),
+ `9`,
+ }, {
+ testExpr(`len({})`),
+ `0`,
+ }, {
+ testExpr(`len({a: 1, b: 2, <foo>: int, _c: 3})`),
+ `2`,
+ }, {
+ testExpr(`len([1, 2, 3])`),
+ `3`,
+ }, {
+ testExpr(`len("foo")`),
+ `3`,
+ }, {
+ testExpr(`len('f\x20\x20')`),
+ `3`,
+ }}
+ for _, tc := range testCases {
+ t.Run("", func(t *testing.T) {
+ insts := Build(makeInstances(tc.instances))
+ if err := insts[0].Err; err != nil {
+ t.Fatal(err)
+ }
+ got := strings.TrimSpace(fmt.Sprintf("%s\n", insts[0].Value()))
+ if got != tc.emit {
+ t.Errorf("\n got: %s\nwant: %s", got, tc.emit)
+ }
+ })
+ }
+}
diff --git a/cue/builtins.go b/cue/builtins.go
new file mode 100644
index 0000000..b7c920f
--- /dev/null
+++ b/cue/builtins.go
@@ -0,0 +1,1841 @@
+// Code generated by go generate. DO NOT EDIT.
+
+package cue
+
+import (
+ "bytes"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "cuelang.org/go/cue/parser"
+ "cuelang.org/go/cue/token"
+ "cuelang.org/go/internal/third_party/yaml"
+ "encoding/csv"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ goyaml "github.com/ghodss/yaml"
+ "html"
+ "io"
+ "math"
+ "math/big"
+ "math/bits"
+ "path"
+ "regexp"
+ "strconv"
+ "strings"
+ "text/tabwriter"
+ "text/template"
+ "unicode"
+)
+
+func init() {
+ initBuiltins(builtinPackages)
+}
+
+var _ io.Reader
+
+var split = path.Split
+
+var pathClean = path.Clean
+
+var pathExt = path.Ext
+
+var pathBase = path.Base
+
+var pathIsAbs = path.IsAbs
+
+var pathDir = path.Dir
+
+var builtinPackages = map[string][]*builtin{
+ "": []*builtin{{}},
+ "crypto/md5": []*builtin{{
+ Name: "Size",
+ Const: intFromGo("16"),
+ }, {
+ Name: "BlockSize",
+ Const: intFromGo("64"),
+ }, {
+ Name: "Sum",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return md5.Sum(data)
+ }()
+ },
+ }},
+ "crypto/sha1": []*builtin{{
+ Name: "Size",
+ Const: intFromGo("20"),
+ }, {
+ Name: "BlockSize",
+ Const: intFromGo("64"),
+ }, {
+ Name: "Sum",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha1.Sum(data)
+ }()
+ },
+ }},
+ "crypto/sha256": []*builtin{{
+ Name: "Size",
+ Const: intFromGo("32"),
+ }, {
+ Name: "Size224",
+ Const: intFromGo("28"),
+ }, {
+ Name: "BlockSize",
+ Const: intFromGo("64"),
+ }, {
+ Name: "Sum256",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha256.Sum256(data)
+ }()
+ },
+ }, {
+ Name: "Sum224",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha256.Sum224(data)
+ }()
+ },
+ }},
+ "crypto/sha512": []*builtin{{
+ Name: "Size",
+ Const: intFromGo("64"),
+ }, {
+ Name: "Size224",
+ Const: intFromGo("28"),
+ }, {
+ Name: "Size256",
+ Const: intFromGo("32"),
+ }, {
+ Name: "Size384",
+ Const: intFromGo("48"),
+ }, {
+ Name: "BlockSize",
+ Const: intFromGo("128"),
+ }, {
+ Name: "Sum512",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha512.Sum512(data)
+ }()
+ },
+ }, {
+ Name: "Sum384",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha512.Sum384(data)
+ }()
+ },
+ }, {
+ Name: "Sum512_224",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha512.Sum512_224(data)
+ }()
+ },
+ }, {
+ Name: "Sum512_256",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return sha512.Sum512_256(data)
+ }()
+ },
+ }},
+ "encoding/csv": []*builtin{{
+ Name: "Encode",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ x := c.value(0)
+ c.ret, c.err = func() (interface{}, 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
+ }()
+ },
+ }, {
+ Name: "Decode",
+ Params: []kind{stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ r := c.reader(0)
+ c.ret, c.err = func() (interface{}, error) {
+ return csv.NewReader(r).ReadAll()
+ }()
+ },
+ }},
+ "encoding/hex": []*builtin{{
+ Name: "EncodedLen",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ n := c.int(0)
+ c.ret = func() interface{} {
+ return hex.EncodedLen(n)
+ }()
+ },
+ }, {
+ Name: "DecodedLen",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.int(0)
+ c.ret = func() interface{} {
+ return hex.DecodedLen(x)
+ }()
+ },
+ }, {
+ Name: "Decode",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret, c.err = func() (interface{}, error) {
+ return hex.DecodeString(s)
+ }()
+ },
+ }, {
+ Name: "Dump",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return hex.Dump(data)
+ }()
+ },
+ }, {
+ Name: "Encode",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ src := c.bytes(0)
+ c.ret = func() interface{} {
+ return hex.EncodeToString(src)
+ }()
+ },
+ }},
+ "encoding/json": []*builtin{{
+ Name: "Valid",
+ Params: []kind{stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret = func() interface{} {
+ return json.Valid(data)
+ }()
+ },
+ }, {
+ Name: "Compact",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ src := c.bytes(0)
+ c.ret, c.err = func() (interface{}, error) {
+ dst := bytes.Buffer{}
+ if err := json.Compact(&dst, src); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+ }()
+ },
+ }, {
+ Name: "Indent",
+ Params: []kind{stringKind, stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ src, prefix, indent := c.bytes(0), c.string(1), c.string(2)
+ c.ret, c.err = func() (interface{}, error) {
+ dst := bytes.Buffer{}
+ if err := json.Indent(&dst, src, prefix, indent); err != nil {
+ return "", err
+ }
+ return dst.String(), nil
+ }()
+ },
+ }, {
+ Name: "HTMLEscape",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ src := c.bytes(0)
+ c.ret = func() interface{} {
+ dst := &bytes.Buffer{}
+ json.HTMLEscape(dst, src)
+ return dst.String()
+ }()
+ },
+ }, {
+ Name: "Marshal",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ v := c.value(0)
+ c.ret, c.err = func() (interface{}, error) {
+ b, err := json.Marshal(v)
+ return string(b), err
+ }()
+ },
+ }, {
+ Name: "MarshalStream",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ v := c.value(0)
+ c.ret, c.err = func() (interface{}, error) {
+
+ 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
+ }()
+ },
+ }, {
+ Name: "Unmarshal",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ b := c.bytes(0)
+ c.ret, c.err = func() (interface{}, 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 {
+
+ return nil, fmt.Errorf("json: could not parse JSON: %v", err)
+ }
+ return FromExpr(fset, expr)
+ }()
+ },
+ }},
+ "encoding/yaml": []*builtin{{
+ Name: "Marshal",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ v := c.value(0)
+ c.ret, c.err = func() (interface{}, error) {
+ b, err := goyaml.Marshal(v)
+ return string(b), err
+ }()
+ },
+ }, {
+ Name: "MarshalStream",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ v := c.value(0)
+ c.ret, c.err = func() (interface{}, error) {
+
+ 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
+ }()
+ },
+ }, {
+ Name: "Unmarshal",
+ Params: []kind{stringKind},
+ Result: topKind,
+ Func: func(c *callCtxt) {
+ data := c.bytes(0)
+ c.ret, c.err = func() (interface{}, error) {
+ fset := token.NewFileSet()
+ expr, err := yaml.Unmarshal(fset, "", data)
+ if err != nil {
+ return nil, err
+ }
+ return FromExpr(fset, expr)
+ }()
+ },
+ }},
+ "html": []*builtin{{
+ Name: "Escape",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return html.EscapeString(s)
+ }()
+ },
+ }, {
+ Name: "Unescape",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return html.UnescapeString(s)
+ }()
+ },
+ }},
+ "list": []*builtin{{}},
+ "math": []*builtin{{
+ Name: "MaxExp",
+ Const: intFromGo("2147483647"),
+ }, {
+ Name: "MinExp",
+ Const: intFromGo("-2147483648"),
+ }, {
+ Name: "MaxPrec",
+ Const: intFromGo("4294967295"),
+ }, {
+ Name: "ToNearestEven",
+ Const: intFromGo("0"),
+ }, {
+ Name: "ToNearestAway",
+ Const: intFromGo("1"),
+ }, {
+ Name: "ToZero",
+ Const: intFromGo("2"),
+ }, {
+ Name: "AwayFromZero",
+ Const: intFromGo("3"),
+ }, {
+ Name: "ToNegativeInf",
+ Const: intFromGo("4"),
+ }, {
+ Name: "ToPositiveInf",
+ Const: intFromGo("5"),
+ }, {
+ Name: "Below",
+ Const: intFromGo("-1"),
+ }, {
+ Name: "Exact",
+ Const: intFromGo("0"),
+ }, {
+ Name: "Above",
+ Const: intFromGo("1"),
+ }, {
+ Name: "Jacobi",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x, y := c.bigInt(0), c.bigInt(1)
+ c.ret = func() interface{} {
+ return big.Jacobi(x, y)
+ }()
+ },
+ }, {
+ Name: "MaxBase",
+ Const: intFromGo("62"),
+ }, {
+ Name: "Floor",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Floor(x)
+ }()
+ },
+ }, {
+ Name: "Ceil",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Ceil(x)
+ }()
+ },
+ }, {
+ Name: "Trunc",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Trunc(x)
+ }()
+ },
+ }, {
+ Name: "Round",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Round(x)
+ }()
+ },
+ }, {
+ Name: "RoundToEven",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.RoundToEven(x)
+ }()
+ },
+ }, {
+ Name: "Abs",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Abs(x)
+ }()
+ },
+ }, {
+ Name: "Acosh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Acosh(x)
+ }()
+ },
+ }, {
+ Name: "Asin",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Asin(x)
+ }()
+ },
+ }, {
+ Name: "Acos",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Acos(x)
+ }()
+ },
+ }, {
+ Name: "Asinh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Asinh(x)
+ }()
+ },
+ }, {
+ Name: "Atan",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Atan(x)
+ }()
+ },
+ }, {
+ Name: "Atan2",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ y, x := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Atan2(y, x)
+ }()
+ },
+ }, {
+ Name: "Atanh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Atanh(x)
+ }()
+ },
+ }, {
+ Name: "Cbrt",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Cbrt(x)
+ }()
+ },
+ }, {
+ Name: "E",
+ Const: floatFromGo("2.71828182845904523536028747135266249775724709369995957496696763"),
+ }, {
+ Name: "Pi",
+ Const: floatFromGo("3.14159265358979323846264338327950288419716939937510582097494459"),
+ }, {
+ Name: "Phi",
+ Const: floatFromGo("1.61803398874989484820458683436563811772030917980576286213544861"),
+ }, {
+ Name: "Sqrt2",
+ Const: floatFromGo("1.41421356237309504880168872420969807856967187537694807317667974"),
+ }, {
+ Name: "SqrtE",
+ Const: floatFromGo("1.64872127070012814684865078781416357165377610071014801157507931"),
+ }, {
+ Name: "SqrtPi",
+ Const: floatFromGo("1.77245385090551602729816748334114518279754945612238712821380779"),
+ }, {
+ Name: "SqrtPhi",
+ Const: floatFromGo("1.27201964951406896425242246173749149171560804184009624861664038"),
+ }, {
+ Name: "Ln2",
+ Const: floatFromGo("0.693147180559945309417232121458176568075500134360255254120680009"),
+ }, {
+ Name: "Log2E",
+ Const: floatFromGo("1.442695040888963407359924681001892137426645954152985934135449408"),
+ }, {
+ Name: "Ln10",
+ Const: floatFromGo("2.3025850929940456840179914546843642076011014886287729760333278"),
+ }, {
+ Name: "Log10E",
+ Const: floatFromGo("0.43429448190325182765112891891660508229439700580366656611445378"),
+ }, {
+ Name: "Copysign",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x, y := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Copysign(x, y)
+ }()
+ },
+ }, {
+ Name: "Dim",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x, y := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Dim(x, y)
+ }()
+ },
+ }, {
+ Name: "Erf",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Erf(x)
+ }()
+ },
+ }, {
+ Name: "Erfc",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Erfc(x)
+ }()
+ },
+ }, {
+ Name: "Erfinv",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Erfinv(x)
+ }()
+ },
+ }, {
+ Name: "Erfcinv",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Erfcinv(x)
+ }()
+ },
+ }, {
+ Name: "Exp",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Exp(x)
+ }()
+ },
+ }, {
+ Name: "Exp2",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Exp2(x)
+ }()
+ },
+ }, {
+ Name: "Expm1",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Expm1(x)
+ }()
+ },
+ }, {
+ Name: "Gamma",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Gamma(x)
+ }()
+ },
+ }, {
+ Name: "Hypot",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ p, q := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Hypot(p, q)
+ }()
+ },
+ }, {
+ Name: "J0",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.J0(x)
+ }()
+ },
+ }, {
+ Name: "Y0",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Y0(x)
+ }()
+ },
+ }, {
+ Name: "J1",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.J1(x)
+ }()
+ },
+ }, {
+ Name: "Y1",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Y1(x)
+ }()
+ },
+ }, {
+ Name: "Jn",
+ Params: []kind{intKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ n, x := c.int(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Jn(n, x)
+ }()
+ },
+ }, {
+ Name: "Yn",
+ Params: []kind{intKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ n, x := c.int(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Yn(n, x)
+ }()
+ },
+ }, {
+ Name: "Ldexp",
+ Params: []kind{numKind, intKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ frac, exp := c.float64(0), c.int(1)
+ c.ret = func() interface{} {
+ return math.Ldexp(frac, exp)
+ }()
+ },
+ }, {
+ Name: "Log",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Log(x)
+ }()
+ },
+ }, {
+ Name: "Log10",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Log10(x)
+ }()
+ },
+ }, {
+ Name: "Log2",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Log2(x)
+ }()
+ },
+ }, {
+ Name: "Log1p",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Log1p(x)
+ }()
+ },
+ }, {
+ Name: "Logb",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Logb(x)
+ }()
+ },
+ }, {
+ Name: "Ilogb",
+ Params: []kind{numKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Ilogb(x)
+ }()
+ },
+ }, {
+ Name: "Mod",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x, y := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Mod(x, y)
+ }()
+ },
+ }, {
+ Name: "Pow",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x, y := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Pow(x, y)
+ }()
+ },
+ }, {
+ Name: "Pow10",
+ Params: []kind{intKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ n := c.int(0)
+ c.ret = func() interface{} {
+ return math.Pow10(n)
+ }()
+ },
+ }, {
+ Name: "Remainder",
+ Params: []kind{numKind, numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x, y := c.float64(0), c.float64(1)
+ c.ret = func() interface{} {
+ return math.Remainder(x, y)
+ }()
+ },
+ }, {
+ Name: "Signbit",
+ Params: []kind{numKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Signbit(x)
+ }()
+ },
+ }, {
+ Name: "Cos",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Cos(x)
+ }()
+ },
+ }, {
+ Name: "Sin",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Sin(x)
+ }()
+ },
+ }, {
+ Name: "Sinh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Sinh(x)
+ }()
+ },
+ }, {
+ Name: "Cosh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Cosh(x)
+ }()
+ },
+ }, {
+ Name: "Sqrt",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Sqrt(x)
+ }()
+ },
+ }, {
+ Name: "Tan",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Tan(x)
+ }()
+ },
+ }, {
+ Name: "Tanh",
+ Params: []kind{numKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ x := c.float64(0)
+ c.ret = func() interface{} {
+ return math.Tanh(x)
+ }()
+ },
+ }},
+ "math/bits": []*builtin{{
+ Name: "And",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ a, b := c.bigInt(0), c.bigInt(1)
+ c.ret = func() interface{} {
+ 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
+ }()
+ },
+ }, {
+ Name: "Or",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ a, b := c.bigInt(0), c.bigInt(1)
+ c.ret = func() interface{} {
+ 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
+ }()
+ },
+ }, {
+ Name: "Xor",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ a, b := c.bigInt(0), c.bigInt(1)
+ c.ret = func() interface{} {
+ 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
+ }()
+ },
+ }, {
+ Name: "Clear",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ a, b := c.bigInt(0), c.bigInt(1)
+ c.ret = func() interface{} {
+ 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
+ }()
+ },
+ }, {
+ Name: "OnesCount",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.uint64(0)
+ c.ret = func() interface{} {
+ return bits.OnesCount64(x)
+ }()
+ },
+ }, {
+ Name: "RotateLeft",
+ Params: []kind{intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x, k := c.uint64(0), c.int(1)
+ c.ret = func() interface{} {
+ return bits.RotateLeft64(x, k)
+ }()
+ },
+ }, {
+ Name: "Reverse",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.uint64(0)
+ c.ret = func() interface{} {
+ return bits.Reverse64(x)
+ }()
+ },
+ }, {
+ Name: "ReverseBytes",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.uint64(0)
+ c.ret = func() interface{} {
+ return bits.ReverseBytes64(x)
+ }()
+ },
+ }, {
+ Name: "Len",
+ Params: []kind{intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ x := c.uint64(0)
+ c.ret = func() interface{} {
+ return bits.Len64(x)
+ }()
+ },
+ }},
+ "path": []*builtin{{
+ Name: "Split",
+ Params: []kind{stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ file, dir := split(path)
+ return []string{file, dir}
+ }()
+ },
+ }, {
+ Name: "Match",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ pattern, name := c.string(0), c.string(1)
+ c.ret, c.err = func() (interface{}, error) {
+ return path.Match(pattern, name)
+ }()
+ },
+ }, {
+ Name: "Clean",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ return pathClean(path)
+ }()
+ },
+ }, {
+ Name: "Ext",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ return pathExt(path)
+ }()
+ },
+ }, {
+ Name: "Base",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ return pathBase(path)
+ }()
+ },
+ }, {
+ Name: "IsAbs",
+ Params: []kind{stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ return pathIsAbs(path)
+ }()
+ },
+ }, {
+ Name: "Dir",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ path := c.string(0)
+ c.ret = func() interface{} {
+ return pathDir(path)
+ }()
+ },
+ }},
+ "regexp": []*builtin{{
+ Name: "Match",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ pattern, s := c.string(0), c.string(1)
+ c.ret, c.err = func() (interface{}, error) {
+ return regexp.MatchString(pattern, s)
+ }()
+ },
+ }, {
+ Name: "QuoteMeta",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return regexp.QuoteMeta(s)
+ }()
+ },
+ }},
+ "runtime": []*builtin{{
+ Name: "Path",
+ Params: []kind{},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ c.ret = func() interface{} {
+ return ""
+ }()
+ },
+ }},
+ "strconv": []*builtin{{
+ Name: "Unquote",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret, c.err = func() (interface{}, error) {
+ return Unquote(s)
+ }()
+ },
+ }, {
+ Name: "ParseBool",
+ Params: []kind{stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ str := c.string(0)
+ c.ret, c.err = func() (interface{}, error) {
+ return strconv.ParseBool(str)
+ }()
+ },
+ }, {
+ Name: "FormatBool",
+ Params: []kind{boolKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ b := c.bool(0)
+ c.ret = func() interface{} {
+ return strconv.FormatBool(b)
+ }()
+ },
+ }, {
+ Name: "ParseFloat",
+ Params: []kind{stringKind, intKind},
+ Result: numKind,
+ Func: func(c *callCtxt) {
+ s, bitSize := c.string(0), c.int(1)
+ c.ret, c.err = func() (interface{}, error) {
+ return strconv.ParseFloat(s, bitSize)
+ }()
+ },
+ }, {
+ Name: "IntSize",
+ Const: intFromGo("64"),
+ }, {
+ Name: "ParseUint",
+ Params: []kind{stringKind, intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, base, bitSize := c.string(0), c.int(1), c.int(2)
+ c.ret, c.err = func() (interface{}, error) {
+ return strconv.ParseUint(s, base, bitSize)
+ }()
+ },
+ }, {
+ Name: "ParseInt",
+ Params: []kind{stringKind, intKind, intKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, base, bitSize := c.string(0), c.int(1), c.int(2)
+ c.ret, c.err = func() (interface{}, error) {
+ return strconv.ParseInt(s, base, bitSize)
+ }()
+ },
+ }, {
+ Name: "Atoi",
+ Params: []kind{stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret, c.err = func() (interface{}, error) {
+ return strconv.Atoi(s)
+ }()
+ },
+ }, {
+ Name: "FormatFloat",
+ Params: []kind{numKind, intKind, intKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ f, fmt, prec, bitSize := c.float64(0), c.byte(1), c.int(2), c.int(3)
+ c.ret = func() interface{} {
+ return strconv.FormatFloat(f, fmt, prec, bitSize)
+ }()
+ },
+ }, {
+ Name: "FormatUint",
+ Params: []kind{intKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ i, base := c.uint64(0), c.int(1)
+ c.ret = func() interface{} {
+ return strconv.FormatUint(i, base)
+ }()
+ },
+ }, {
+ Name: "FormatInt",
+ Params: []kind{intKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ i, base := c.int64(0), c.int(1)
+ c.ret = func() interface{} {
+ return strconv.FormatInt(i, base)
+ }()
+ },
+ }, {
+ Name: "Quote",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strconv.Quote(s)
+ }()
+ },
+ }, {
+ Name: "QuoteToASCII",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strconv.QuoteToASCII(s)
+ }()
+ },
+ }, {
+ Name: "QuoteToGraphic",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strconv.QuoteToGraphic(s)
+ }()
+ },
+ }, {
+ Name: "QuoteRune",
+ Params: []kind{intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ r := c.rune(0)
+ c.ret = func() interface{} {
+ return strconv.QuoteRune(r)
+ }()
+ },
+ }, {
+ Name: "QuoteRuneToASCII",
+ Params: []kind{intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ r := c.rune(0)
+ c.ret = func() interface{} {
+ return strconv.QuoteRuneToASCII(r)
+ }()
+ },
+ }, {
+ Name: "QuoteRuneToGraphic",
+ Params: []kind{intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ r := c.rune(0)
+ c.ret = func() interface{} {
+ return strconv.QuoteRuneToGraphic(r)
+ }()
+ },
+ }, {
+ Name: "CanBackquote",
+ Params: []kind{stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strconv.CanBackquote(s)
+ }()
+ },
+ }, {
+ Name: "IsPrint",
+ Params: []kind{intKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ r := c.rune(0)
+ c.ret = func() interface{} {
+ return strconv.IsPrint(r)
+ }()
+ },
+ }, {
+ Name: "IsGraphic",
+ Params: []kind{intKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ r := c.rune(0)
+ c.ret = func() interface{} {
+ return strconv.IsGraphic(r)
+ }()
+ },
+ }},
+ "strings": []*builtin{{
+ Name: "ToTitle",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+
+ prev := ' '
+ return strings.Map(
+ func(r rune) rune {
+ if unicode.IsSpace(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+ }()
+ },
+ }, {
+ Name: "ToCamel",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+
+ prev := ' '
+ return strings.Map(
+ func(r rune) rune {
+ if unicode.IsSpace(prev) {
+ prev = r
+ return unicode.ToLower(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+ }()
+ },
+ }, {
+ Name: "Compare",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ a, b := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Compare(a, b)
+ }()
+ },
+ }, {
+ Name: "Count",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, substr := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Count(s, substr)
+ }()
+ },
+ }, {
+ Name: "Contains",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ s, substr := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Contains(s, substr)
+ }()
+ },
+ }, {
+ Name: "ContainsAny",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ s, chars := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.ContainsAny(s, chars)
+ }()
+ },
+ }, {
+ Name: "LastIndex",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, substr := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.LastIndex(s, substr)
+ }()
+ },
+ }, {
+ Name: "IndexAny",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, chars := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.IndexAny(s, chars)
+ }()
+ },
+ }, {
+ Name: "LastIndexAny",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, chars := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.LastIndexAny(s, chars)
+ }()
+ },
+ }, {
+ Name: "SplitN",
+ Params: []kind{stringKind, stringKind, intKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s, sep, n := c.string(0), c.string(1), c.int(2)
+ c.ret = func() interface{} {
+ return strings.SplitN(s, sep, n)
+ }()
+ },
+ }, {
+ Name: "SplitAfterN",
+ Params: []kind{stringKind, stringKind, intKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s, sep, n := c.string(0), c.string(1), c.int(2)
+ c.ret = func() interface{} {
+ return strings.SplitAfterN(s, sep, n)
+ }()
+ },
+ }, {
+ Name: "Split",
+ Params: []kind{stringKind, stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s, sep := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Split(s, sep)
+ }()
+ },
+ }, {
+ Name: "SplitAfter",
+ Params: []kind{stringKind, stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s, sep := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.SplitAfter(s, sep)
+ }()
+ },
+ }, {
+ Name: "Fields",
+ Params: []kind{stringKind},
+ Result: listKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strings.Fields(s)
+ }()
+ },
+ }, {
+ Name: "Join",
+ Params: []kind{listKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ a, sep := c.strList(0), c.string(1)
+ if c.do() {
+ c.ret = func() interface{} {
+ return strings.Join(a, sep)
+ }()
+ }
+ },
+ }, {
+ Name: "HasPrefix",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ s, prefix := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.HasPrefix(s, prefix)
+ }()
+ },
+ }, {
+ Name: "HasSuffix",
+ Params: []kind{stringKind, stringKind},
+ Result: boolKind,
+ Func: func(c *callCtxt) {
+ s, suffix := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.HasSuffix(s, suffix)
+ }()
+ },
+ }, {
+ Name: "Repeat",
+ Params: []kind{stringKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, count := c.string(0), c.int(1)
+ c.ret = func() interface{} {
+ return strings.Repeat(s, count)
+ }()
+ },
+ }, {
+ Name: "ToUpper",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strings.ToUpper(s)
+ }()
+ },
+ }, {
+ Name: "ToLower",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strings.ToLower(s)
+ }()
+ },
+ }, {
+ Name: "Trim",
+ Params: []kind{stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, cutset := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Trim(s, cutset)
+ }()
+ },
+ }, {
+ Name: "TrimLeft",
+ Params: []kind{stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, cutset := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.TrimLeft(s, cutset)
+ }()
+ },
+ }, {
+ Name: "TrimRight",
+ Params: []kind{stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, cutset := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.TrimRight(s, cutset)
+ }()
+ },
+ }, {
+ Name: "TrimSpace",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return strings.TrimSpace(s)
+ }()
+ },
+ }, {
+ Name: "TrimPrefix",
+ Params: []kind{stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, prefix := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.TrimPrefix(s, prefix)
+ }()
+ },
+ }, {
+ Name: "TrimSuffix",
+ Params: []kind{stringKind, stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, suffix := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.TrimSuffix(s, suffix)
+ }()
+ },
+ }, {
+ Name: "Replace",
+ Params: []kind{stringKind, stringKind, stringKind, intKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s, old, new, n := c.string(0), c.string(1), c.string(2), c.int(3)
+ c.ret = func() interface{} {
+ return strings.Replace(s, old, new, n)
+ }()
+ },
+ }, {
+ Name: "Index",
+ Params: []kind{stringKind, stringKind},
+ Result: intKind,
+ Func: func(c *callCtxt) {
+ s, substr := c.string(0), c.string(1)
+ c.ret = func() interface{} {
+ return strings.Index(s, substr)
+ }()
+ },
+ }},
+ "text/tabwriter": []*builtin{{
+ Name: "Write",
+ Params: []kind{topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ data := c.value(0)
+ c.ret, c.err = func() (interface{}, 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
+ }()
+ },
+ }},
+ "text/template": []*builtin{{
+ Name: "Execute",
+ Params: []kind{stringKind, topKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ templ, data := c.string(0), c.value(1)
+ c.ret, c.err = func() (interface{}, 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
+ }()
+ },
+ }, {
+ Name: "HTMLEscape",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return template.HTMLEscapeString(s)
+ }()
+ },
+ }, {
+ Name: "JSEscape",
+ Params: []kind{stringKind},
+ Result: stringKind,
+ Func: func(c *callCtxt) {
+ s := c.string(0)
+ c.ret = func() interface{} {
+ return template.JSEscapeString(s)
+ }()
+ },
+ }},
+}
diff --git a/cue/export_test.go b/cue/export_test.go
index 9eda831..1b8701a 100644
--- a/cue/export_test.go
+++ b/cue/export_test.go
@@ -145,6 +145,14 @@
a: 0..10
b: "Count: \(a) times"
}`),
+ }, {
+ raw: true,
+ in: `{ a: "", b: len(a) }`,
+ out: unindent(`
+ {
+ a: ""
+ b: len(a)
+ }`),
}}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
diff --git a/cue/gen.go b/cue/gen.go
new file mode 100644
index 0000000..7effb9a
--- /dev/null
+++ b/cue/gen.go
@@ -0,0 +1,400 @@
+// 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.
+
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/constant"
+ "go/format"
+ "go/parser"
+ "go/printer"
+ "go/token"
+ "io"
+ "io/ioutil"
+ "log"
+ "math/big"
+ "os"
+ "path"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+const prefix = "../pkg/"
+
+const header = `// Code generated by go generate. DO NOT EDIT.
+
+package cue
+
+`
+
+const initFunc = `
+func init() {
+ initBuiltins(builtinPackages)
+}
+
+var _ io.Reader
+`
+
+func main() {
+ flag.Parse()
+ log.SetFlags(log.Lshortfile)
+ log.SetOutput(os.Stdout)
+
+ g := generator{
+ w: &bytes.Buffer{},
+ decls: &bytes.Buffer{},
+ fset: token.NewFileSet(),
+ }
+
+ fmt.Fprintln(g.w, "var builtinPackages = map[string][]*builtin{")
+ filepath.Walk(prefix, func(dir string, info os.FileInfo, err error) error {
+ if err != nil {
+ log.Fatal(err)
+ }
+ if info.Name() == "testdata" {
+ return filepath.SkipDir
+ }
+ if info.IsDir() {
+ g.processDir(dir)
+ }
+ return nil
+ })
+ fmt.Fprintln(g.w, "}")
+
+ w := &bytes.Buffer{}
+ fmt.Fprintln(w, header)
+
+ m := map[string]*ast.ImportSpec{}
+ keys := []string{}
+ for _, spec := range g.imports {
+ if spec.Path.Value == `"cuelang.org/go/cue"` {
+ // Don't add this package.
+ continue
+ }
+ if prev, ok := m[spec.Path.Value]; ok {
+ if importName(prev) != importName(spec) {
+ log.Fatalf("inconsistent name for import %s: %q != %q",
+ spec.Path.Value, importName(prev), importName(spec))
+ }
+ continue
+ }
+ m[spec.Path.Value] = spec
+ keys = append(keys, spec.Path.Value)
+ }
+ fmt.Fprintln(w, "import (")
+ sort.Strings(keys)
+ for _, k := range keys {
+ printer.Fprint(w, g.fset, m[k])
+ fmt.Fprintln(w)
+ }
+ fmt.Fprintln(w, ")")
+ fmt.Fprintln(w, initFunc)
+ io.Copy(w, g.decls)
+ io.Copy(w, g.w)
+
+ b, err := format.Source(w.Bytes())
+ if err != nil {
+ b = w.Bytes() // write the unformatted source
+ }
+ // TODO: do this in a more principled way. The best is probably to
+ // put all builtins in a separate package.
+ b = bytes.Replace(b, []byte("cue."), []byte(""), -1)
+
+ if err := ioutil.WriteFile("builtins.go", b, 0644); err != nil {
+ log.Fatal(err)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+type generator struct {
+ w *bytes.Buffer
+ decls *bytes.Buffer
+ fset *token.FileSet
+ defaultPkg string
+ first bool
+ iota int
+
+ imports []*ast.ImportSpec
+}
+
+func (g *generator) processDir(dir string) {
+ args, err := filepath.Glob(filepath.Join(dir, "*.go"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if len(args) == 0 {
+ return
+ }
+ pkg := dir[len(prefix):]
+ fmt.Fprintf(g.w, "%q: []*builtin{{\n", pkg)
+ defer fmt.Fprintf(g.w, "}},\n")
+ g.first = true
+ for _, filename := range args {
+ g.process(filename)
+ }
+}
+
+func (g *generator) sep() {
+ if g.first {
+ g.first = false
+ return
+ }
+ fmt.Fprintln(g.w, "}, {")
+}
+
+func importName(s *ast.ImportSpec) string {
+ if s.Name != nil {
+ return s.Name.Name
+ }
+ pkg, err := strconv.Unquote(s.Path.Value)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return path.Base(pkg)
+}
+
+func (g *generator) process(filename string) {
+ f, err := parser.ParseFile(g.fset, filename, nil, parser.ParseComments)
+ if err != nil {
+ log.Fatal(err)
+ }
+ g.defaultPkg = ""
+
+ for _, d := range f.Decls {
+ switch x := d.(type) {
+ case *ast.GenDecl:
+ switch x.Tok {
+ case token.CONST:
+ for _, spec := range x.Specs {
+ g.genConst(spec.(*ast.ValueSpec))
+ }
+ case token.IMPORT:
+ for _, s := range x.Specs {
+ spec := s.(*ast.ImportSpec)
+ g.imports = append(g.imports, spec)
+ }
+ if g.defaultPkg == "" {
+ g.defaultPkg = importName(x.Specs[0].(*ast.ImportSpec))
+ }
+ case token.VAR:
+ for _, spec := range x.Specs {
+ if ast.IsExported(spec.(*ast.ValueSpec).Names[0].Name) {
+ log.Fatal("var declarations not supported")
+ }
+ }
+ printer.Fprint(g.decls, g.fset, x)
+ fmt.Fprint(g.decls, "\n\n")
+ continue
+ case token.TYPE:
+ for _, spec := range x.Specs {
+ if ast.IsExported(spec.(*ast.TypeSpec).Name.Name) {
+ log.Fatal("type declarations not supported")
+ }
+ }
+ printer.Fprint(g.decls, g.fset, x)
+ fmt.Fprint(g.decls, "\n\n")
+ continue
+ default:
+ log.Fatalf("unexpected spec of type %s", x.Tok)
+ }
+ case *ast.FuncDecl:
+ g.genFun(x)
+ }
+ }
+}
+
+func (g *generator) genConst(spec *ast.ValueSpec) {
+ name := spec.Names[0].Name
+ value := ""
+ switch v := g.toValue(spec.Values[0]); v.Kind() {
+ case constant.Bool:
+ value = fmt.Sprintf("&boolList{b: %q}", v.String())
+ case constant.String:
+ value = fmt.Sprintf("&stringLit{str: %q}", v.ExactString())
+ case constant.Int:
+ value = fmt.Sprintf("intFromGo(%q)", v.ExactString())
+ case constant.Float:
+ var rat big.Rat
+ rat.SetString(v.ExactString())
+ var float big.Float
+ float.SetRat(&rat)
+ value = fmt.Sprintf("floatFromGo(%q)", float.Text('g', -1))
+ default:
+ fmt.Printf("Dropped entry %s.%s (%T: %v)\n", g.defaultPkg, name, v.Kind(), v.ExactString())
+ return
+ }
+ g.sep()
+ fmt.Fprintf(g.w, "Name: %q,\n Const: %s,\n", name, value)
+}
+
+func (g *generator) toValue(x ast.Expr) constant.Value {
+ switch x := x.(type) {
+ case *ast.BasicLit:
+ return constant.MakeFromLiteral(x.Value, x.Kind, 0)
+ case *ast.BinaryExpr:
+ return constant.BinaryOp(g.toValue(x.X), x.Op, g.toValue(x.Y))
+ case *ast.UnaryExpr:
+ return constant.UnaryOp(x.Op, g.toValue(x.X), 0)
+ default:
+ log.Fatalf("%s: unsupported expression type %T: %#v", g.defaultPkg, x, x)
+ }
+ return constant.MakeUnknown()
+}
+
+func (g *generator) genFun(x *ast.FuncDecl) {
+ if x.Body == nil {
+ return
+ }
+ types := []string{}
+ if x.Type.Results != nil {
+ for _, f := range x.Type.Results.List {
+ if len(f.Names) > 0 {
+ for range f.Names {
+ types = append(types, g.goKind(f.Type))
+ }
+ } else {
+ types = append(types, g.goKind(f.Type))
+ }
+ }
+ }
+ if n := len(types); n != 1 && (n != 2 || types[1] != "error") {
+ fmt.Printf("Dropped func %s.%s: must have one return value or a value and an error %v\n", g.defaultPkg, x.Name.Name, types)
+ }
+
+ g.sep()
+ fmt.Fprintf(g.w, "Name: %q,\n", x.Name.Name)
+
+ args := []string{}
+ vals := []string{}
+ kind := []string{}
+ omitCheck := true
+ for _, f := range x.Type.Params.List {
+ for _, name := range f.Names {
+ typ := g.goKind(f.Type)
+ argKind, ground := g.goToCUE(f.Type)
+ if !ground {
+ omitCheck = false
+ }
+ vals = append(vals, fmt.Sprintf("c.%s(%d)", typ, len(args)))
+ args = append(args, name.Name)
+ kind = append(kind, argKind)
+ }
+ }
+
+ fmt.Fprintf(g.w, "Params: []kind{%s},\n", strings.Join(kind, ", "))
+ result, _ := g.goToCUE(x.Type.Results.List[0].Type)
+ fmt.Fprintf(g.w, "Result: %s,\n", result)
+ argList := strings.Join(args, ", ")
+ valList := strings.Join(vals, ", ")
+ init := ""
+ if len(args) > 0 {
+ init = fmt.Sprintf("%s := %s", argList, valList)
+ }
+
+ fmt.Fprintf(g.w, "Func: func(c *callCtxt) {")
+ defer fmt.Fprintln(g.w, "},")
+ fmt.Fprintln(g.w)
+ if init != "" {
+ fmt.Fprintln(g.w, init)
+ }
+ if !omitCheck {
+ fmt.Fprintln(g.w, "if c.do() {")
+ defer fmt.Fprintln(g.w, "}")
+ }
+ if len(types) == 1 {
+ fmt.Fprint(g.w, "c.ret = func() interface{} ")
+ } else {
+ fmt.Fprint(g.w, "c.ret, c.err = func() (interface{}, error) ")
+ }
+ printer.Fprint(g.w, g.fset, x.Body)
+ fmt.Fprintln(g.w, "()")
+}
+
+func (g *generator) goKind(expr ast.Expr) string {
+ if star, isStar := expr.(*ast.StarExpr); isStar {
+ expr = star.X
+ }
+ w := &bytes.Buffer{}
+ printer.Fprint(w, g.fset, expr)
+ switch str := w.String(); str {
+ case "big.Int":
+ return "bigInt"
+ case "big.Float":
+ return "bigFloat"
+ case "big.Rat":
+ return "bigRat"
+ case "cue.Value":
+ return "value"
+ case "cue.List":
+ return "list"
+ case "[]string":
+ return "strList"
+ case "[]byte":
+ return "bytes"
+ case "io.Reader":
+ return "reader"
+ default:
+ return str
+ }
+}
+
+func (g *generator) goToCUE(expr ast.Expr) (cueKind string, omitCheck bool) {
+ // TODO: detect list and structs types for return values.
+ omitCheck = true
+ switch k := g.goKind(expr); k {
+ case "error":
+ cueKind += "bottomKind"
+ case "bool":
+ cueKind += "boolKind"
+ case "string", "bytes", "reader":
+ cueKind += "stringKind"
+ case "int", "int8", "int16", "int32", "rune", "int64",
+ "uint", "byte", "uint8", "uint16", "uint32", "uint64",
+ "bigInt":
+ cueKind += "intKind"
+ case "float64", "bigRat", "bigFloat":
+ cueKind += "numKind"
+ case "list":
+ cueKind += "listKind"
+ case "strList":
+ omitCheck = false
+ cueKind += "listKind"
+ case "value":
+ // Must use callCtxt.value method for these types and resolve manually.
+ cueKind += "topKind" // TODO: can be more precise
+ default:
+ switch {
+ case strings.HasPrefix(k, "[]"):
+ cueKind += "listKind"
+ case strings.HasPrefix(k, "map["):
+ cueKind += "structKind"
+ default:
+ // log.Println("Unknown type:", k)
+ // Must use callCtxt.value method for these types and resolve manually.
+ cueKind += "topKind" // TODO: can be more precise
+ omitCheck = false
+ }
+ }
+ return cueKind, omitCheck
+}
diff --git a/pkg/math/manual.go b/pkg/math/manual.go
new file mode 100644
index 0000000..493f8c5
--- /dev/null
+++ b/pkg/math/manual.go
@@ -0,0 +1,69 @@
+// 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 math
+
+import "math"
+
+// TODO: use apd
+
+// Floor returns the greatest integer value less than or equal to x.
+//
+// Special cases are:
+// Floor(±0) = ±0
+// Floor(±Inf) = ±Inf
+// Floor(NaN) = NaN
+func Floor(x float64) float64 {
+ return math.Floor(x)
+}
+
+// Ceil returns the least integer value greater than or equal to x.
+//
+// Special cases are:
+// Ceil(±0) = ±0
+// Ceil(±Inf) = ±Inf
+// Ceil(NaN) = NaN
+func Ceil(x float64) float64 {
+ return math.Ceil(x)
+}
+
+// Trunc returns the integer value of x.
+//
+// Special cases are:
+// Trunc(±0) = ±0
+// Trunc(±Inf) = ±Inf
+// Trunc(NaN) = NaN
+func Trunc(x float64) float64 {
+ return math.Trunc(x)
+}
+
+// Round returns the nearest integer, rounding half away from zero.
+//
+// Special cases are:
+// Round(±0) = ±0
+// Round(±Inf) = ±Inf
+// Round(NaN) = NaN
+func Round(x float64) float64 {
+ return math.Round(x)
+}
+
+// RoundToEven returns the nearest integer, rounding ties to even.
+//
+// Special cases are:
+// RoundToEven(±0) = ±0
+// RoundToEven(±Inf) = ±Inf
+// RoundToEven(NaN) = NaN
+func RoundToEven(x float64) float64 {
+ return math.RoundToEven(x)
+}