1
0
Fork 0

One buffer fits all

This commit is contained in:
Gregory Eremin 2015-02-23 20:07:19 +07:00
parent 75ff8bf4d5
commit fc170098e9
8 changed files with 70 additions and 85 deletions

50
buffer/buffer.go Normal file
View File

@ -0,0 +1,50 @@
package buffer
import (
"bufio"
"bytes"
"io"
)
type (
Buffer struct {
input *bufio.Reader
ready chan rune
}
)
func NewBytesBuffer(b []byte) *Buffer {
return NewReaderBuffer(bytes.NewReader(b))
}
func NewReaderBuffer(rd io.Reader) *Buffer {
return New(bufio.NewReader(rd))
}
func New(input *bufio.Reader) *Buffer {
b := &Buffer{
input: input,
ready: make(chan rune, 100),
}
go b.stream()
return b
}
func (b *Buffer) Next() rune {
if next, ok := <-b.ready; ok {
return next
} else {
return 0
}
}
func (b *Buffer) stream() {
for {
if r, _, err := b.input.ReadRune(); err != nil {
close(b.ready)
break
} else {
b.ready <- r
}
}
}

View File

@ -1,7 +0,0 @@
package buffer
type (
Bufferer interface {
Next() rune
}
)

View File

@ -1,34 +0,0 @@
package buffer
import (
"bytes"
"unicode/utf8"
)
type (
BytesBuffer struct {
input []byte
size uint64
pos uint64
}
)
func NewBytesBuffer(input []byte) *BytesBuffer {
return &BytesBuffer{
input: input,
size: uint64(len(input)),
}
}
func (b *BytesBuffer) Next() rune {
var buf bytes.Buffer
for b.pos < b.size {
buf.WriteByte(b.input[b.pos])
b.pos++
if ok := utf8.FullRune(buf.Bytes()); ok {
r, _ := utf8.DecodeRune(buf.Bytes())
return r
}
}
return 0
}

View File

@ -1,37 +0,0 @@
package buffer
import (
"bytes"
"io"
"unicode/utf8"
)
type (
StreamBuffer struct {
input io.Reader
}
)
func NewStreamBuffer(input io.Reader) *StreamBuffer {
return &StreamBuffer{
input: input,
}
}
func (b *StreamBuffer) Next() rune {
var (
buf bytes.Buffer
)
for {
rbuf := make([]byte, 1)
if n, err := b.input.Read(rbuf); n != 1 || err != nil {
return 0
}
buf.Write(rbuf)
if ok := utf8.FullRune(buf.Bytes()); ok {
r, _ := utf8.DecodeRune(buf.Bytes())
return r
}
}
return 0
}

View File

@ -12,7 +12,7 @@ import (
type ( type (
// Holds the state of the scanner // Holds the state of the scanner
Lexer struct { Lexer struct {
input buffer.Bufferer input *buffer.Buffer
stack []rune // Lexer stack stack []rune // Lexer stack
pos int // Current stack position pos int // Current stack position
lineNum int // Line number lineNum int // Line number
@ -59,10 +59,10 @@ const (
) )
// Creates a new scanner for the input buffer // Creates a new scanner for the input buffer
func New(input buffer.Bufferer) *Lexer { func New(input *buffer.Buffer) *Lexer {
return &Lexer{ return &Lexer{
input: input, input: input,
items: make(chan Item), items: make(chan Item, 100),
lineNum: 1, lineNum: 1,
colNum: 0, colNum: 0,
} }

View File

@ -152,8 +152,8 @@ func compare(t *testing.T, reality, expectations []Item) {
} }
} }
func lex(json string) []Item { func lex(jstr string) []Item {
buf := buffer.NewBytesBuffer([]byte(json)) buf := buffer.NewBytesBuffer([]byte(jstr))
lex := New(buf) lex := New(buf)
go lex.Run() go lex.Run()

15
main.go
View File

@ -6,6 +6,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/davecheney/profile"
"github.com/localhots/punk/buffer" "github.com/localhots/punk/buffer"
"github.com/localhots/punk/parser" "github.com/localhots/punk/parser"
) )
@ -14,8 +15,11 @@ func main() {
var ( var (
sel string sel string
verbose bool verbose bool
prof string
) )
flag.StringVar(&sel, "s", "", "Selector") flag.StringVar(&sel, "s", "", "Selector")
flag.StringVar(&prof, "prof", "", "Performance profiling output")
flag.BoolVar(&verbose, "v", false, "Verbose parsing") flag.BoolVar(&verbose, "v", false, "Verbose parsing")
flag.Parse() flag.Parse()
@ -24,15 +28,24 @@ func main() {
os.Exit(1) os.Exit(1)
} }
if prof != "" {
defer profile.Start(&profile.Config{
CPUProfile: true,
ProfilePath: prof,
}).Stop()
}
sels := strings.Split(sel, " ") sels := strings.Split(sel, " ")
if len(sel) == 0 { if len(sel) == 0 {
sels = []string{} sels = []string{}
} }
buf := buffer.NewStreamBuffer(os.Stdin)
buf := buffer.NewReaderBuffer(os.Stdin)
pars := parser.New(buf, sels) pars := parser.New(buf, sels)
if verbose { if verbose {
pars.Debug() pars.Debug()
} }
res := pars.ParseStream() res := pars.ParseStream()
for { for {
if m, ok := <-res; ok { if m, ok := <-res; ok {

View File

@ -25,7 +25,7 @@ type (
) )
// Creates a new parser // Creates a new parser
func New(buf buffer.Bufferer, sels []string) *Parser { func New(buf *buffer.Buffer, sels []string) *Parser {
return &Parser{ return &Parser{
lex: lexer.New(buf), lex: lexer.New(buf),
ctx: &context{ ctx: &context{