/
grammar.go
71 lines (65 loc) · 1.46 KB
/
grammar.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package grammar
import (
"bufio"
"bytes"
"io"
"math/rand"
"time"
"unicode"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
type Grammar struct {
data map[string][][]string
start string
}
func (g Grammar) Execute(w io.Writer) (int, error) {
return g.execOne(w, g.start)
}
func (g Grammar) execOne(w io.Writer, s string) (int, error) {
result, ok := g.data[s]
if !ok {
toWrite := make([]byte, len(s)+1)
copy(toWrite, s)
toWrite[len(toWrite)-1] = ' '
return w.Write(toWrite)
}
count := 0
for _, piece := range result[rand.Intn(len(result))] {
c, err := g.execOne(w, piece)
count += c
if err != nil {
return count, err
}
}
return count, nil
}
func New(r io.Reader) (*Grammar, error) {
buf := bufio.NewReader(r)
g := &Grammar{data: make(map[string][][]string)}
start, err := buf.Peek(80)
if err != nil {
return nil, err
}
g.start = string(bytes.Fields(start)[0])
line, err := buf.ReadSlice('.')
for ; err == nil; line, err = buf.ReadSlice('.') {
splat := bytes.Fields(line) // First field is left side, last is ".".
stringified := make([]string, len(splat)-2)
for i, word := range splat[1 : len(splat)-1] {
stringified[i] = string(word)
}
key := string(splat[0])
g.data[key] = append(g.data[key], stringified)
}
if err != io.EOF {
return g, err
}
for _, c := range line { // leftovers
if !unicode.IsSpace(rune(c)) { // i.e. there's something after the last '.':
return g, io.ErrUnexpectedEOF
}
}
return g, nil
}