Skip to content

Commit

Permalink
std/rand: Add. (#184)
Browse files Browse the repository at this point in the history
* std/rand: Add.

* wdte: Update some dependencies.
  • Loading branch information
DeedleFake committed Jun 24, 2019
1 parent c270fe0 commit 6bb9870
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 6 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ module github.com/DeedleFake/wdte
require (
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/peterh/liner v1.1.0
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 // indirect
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 // indirect
)
13 changes: 9 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/peterh/liner v1.1.0 h1:f+aAedNJA6uk7+6rXsYBnhdo4Xux7ESLe+kcuVUF5os=
github.com/peterh/liner v1.1.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 h1:FDfvYgoVsA7TTZSbgiqjAbfPbK47CNHdWl3h/PJtii0=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
139 changes: 139 additions & 0 deletions std/rand/rand.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Package rand provides functions for generating and dealing with
// random numbers.
package rand

import (
crand "crypto/rand"
"encoding/binary"
"math/rand"

"github.com/DeedleFake/wdte"
"github.com/DeedleFake/wdte/auto"
"github.com/DeedleFake/wdte/std"
"github.com/DeedleFake/wdte/std/stream"
)

// A Source is a WDTE function that can create successive random
// numbers.
type Source interface {
wdte.Func

// Next returns the next random number from the generator.
Next() wdte.Number
}

// Next is a WDTE function with the following signature:
//
// next source
//
// It creates and returns the next random number from the given
// source.
func Next(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("next")

if len(args) == 0 {
return wdte.GoFunc(Next)
}

r := args[0].Call(frame).(Source)
return r.Next()
}

type source struct {
rand *rand.Rand
}

func (s *source) Call(frame wdte.Frame, args ...wdte.Func) wdte.Func {
return s
}

func (s *source) Next() wdte.Number {
return wdte.Number(s.rand.Float64())
}

func (s *source) Reflect(name string) bool {
return name == "Source"
}

func (s *source) String() string {
return "<source>"
}

// Gen is a WDTE function with the following signature:
//
// gen seed
//
// It returns a new Source that starts with the given seed.
func Gen(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("gen")

if len(args) == 0 {
return wdte.GoFunc(Gen)
}

seed := args[0].Call(frame).(wdte.Number)
return &source{rand: rand.New(rand.NewSource(int64(seed)))}
}

type urand struct{}

func (urand) Int63() int64 {
var r uint64
err := binary.Read(crand.Reader, binary.LittleEndian, &r)
if err != nil {
panic(err)
}
return int64(r &^ (0x1 << 63))
}

func (urand) Seed(int64) {}

// UGen is a WDTE function with the following signature:
//
// ugen
//
// It returns a Source that creates numbers from the operating
// system's cryptographic random number generator.
func UGen(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("ugen")
return &source{rand: rand.New(urand{})}
}

// Stream is a WDTE function with the following signature:
//
// stream source num
//
// It returns a Stream that yields the given number of random numbers
// from the provided Source.
func Stream(frame wdte.Frame, args ...wdte.Func) wdte.Func {
frame = frame.Sub("stream")

if len(args) < 2 {
return auto.SaveArgsReverse(wdte.GoFunc(Stream), args...)
}

r := args[0].Call(frame).(Source)
rem := int(args[1].Call(frame).(wdte.Number))

return stream.NextFunc(func(frame wdte.Frame) (wdte.Func, bool) {
if rem <= 0 {
return nil, false
}
rem--

return r.Next(), true
})
}

// Scope is a scope containing the functions in this package.
var Scope = wdte.S().Map(map[wdte.ID]wdte.Func{
"gen": wdte.GoFunc(Gen),
"ugen": wdte.GoFunc(UGen),

"next": wdte.GoFunc(Next),
"stream": wdte.GoFunc(Stream),
})

func init() {
std.Register("rand", Scope)
}
17 changes: 17 additions & 0 deletions wdte_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"io"
"math"
"math/rand"
"reflect"
"strings"
"testing"
Expand All @@ -14,6 +15,7 @@ import (
_ "github.com/DeedleFake/wdte/std/arrays"
wdteio "github.com/DeedleFake/wdte/std/io"
_ "github.com/DeedleFake/wdte/std/math"
_ "github.com/DeedleFake/wdte/std/rand"
_ "github.com/DeedleFake/wdte/std/stream"
_ "github.com/DeedleFake/wdte/std/strings"
)
Expand Down Expand Up @@ -801,6 +803,21 @@ func TestArrays(t *testing.T) {
})
}

func TestRand(t *testing.T) {
runTests(t, []test{
{
name: "Simple",
script: `let m => import 'math'; let rand => import 'rand'; rand.gen 1 -> rand.next -> * 100 -> m.floor;`,
ret: wdte.Number(math.Floor(rand.New(rand.NewSource(1)).Float64() * 100)),
},
{
name: "Stream",
script: `let s => import 'stream'; let m => import 'math'; let rand => import 'rand'; rand.gen 1 -> rand.stream 3 -> s.map (* 100) -> s.map m.floor -> s.collect;`,
ret: wdte.Array{wdte.Number(60), wdte.Number(94), wdte.Number(66)},
},
})
}

type pieceReader struct {
pieces []io.Reader
i int
Expand Down

0 comments on commit 6bb9870

Please sign in to comment.