diff options
| -rw-r--r-- | conf/parser.go | 95 | ||||
| -rw-r--r-- | conf/scanner.go | 49 | ||||
| -rw-r--r-- | stasher.cfg | 1 | 
3 files changed, 132 insertions, 13 deletions
diff --git a/conf/parser.go b/conf/parser.go index 4f58713..3d584f6 100644 --- a/conf/parser.go +++ b/conf/parser.go @@ -1,8 +1,12 @@  // grammar of the config file  // +// Notes: We parse exactly three modules ("input", "filter", "output") +// in our configuration. Each module consists of two name-object pairs +// that are nested. We don't want to allow limitless recursion here. +//  // config = module module module -// module = name object -// name = 'input' | 'filter' | 'etc.' +// module = name object name object +// name = 'input' | 'filter' | 'output' | etc.  // object = '{' keyvalue | keyvalue | ... '}'  // keyvalue = statement '=>' value  // statement = name | if @@ -17,8 +21,8 @@ import (  	"os"  ) -// Having a Config to Manager function could be nice? -// Or we could just return a Manager from here. +// Having a Config to Manager function could be nice?  Or we could just +// return a Manager from here which may be even better...  type Config struct {  } @@ -44,6 +48,13 @@ func NewConfig(r io.Reader) *Config {  }  func (p *parser) startparsing() { +	p.module("input") + +	p.module("filter") + +} + +func (p *parser) advanceOneToken(place string) {  	var err error  	p.last = p.cur @@ -56,8 +67,82 @@ func (p *parser) startparsing() {  	fmt.Fprintf(os.Stderr, "Error: tokentype: %v, token: %q, err: %v\n", p.cur.Type, p.cur.Lit, err)  } -func (p *parser) module(name string) { +func (p *parser) module(firstname string) { +	p.advanceOneToken("module") + +	fmt.Fprintf(os.Stderr, "tokentype: %d, token: %q\n", p.cur.Type, p.cur.Lit) + +	if p.cur.Lit != firstname { +		fmt.Fprintf(os.Stderr, "error when parsing module. We were expecting name %q but got %q at line %d offset %d.\n", firstname, p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} + +	p.advanceOneToken("module") +	if p.cur.Type != ObjectOpen { +		fmt.Fprintf(os.Stderr, "error when parsing module. We were expecting an opening bracket but got %q at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} + +	p.advanceOneToken("module") +	if p.cur.Type != Name { +		fmt.Fprintf(os.Stderr, "error when parsing module. We were expecting another name but got %q at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} +	p.object() + +	p.advanceOneToken("module") +	if p.cur.Lit[0] != '}' { +		fmt.Fprintf(os.Stderr, "error when parsing module. Was expecting a closing bracket but got %s at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} +  }  func (p *parser) object() { +	p.advanceOneToken("object") + +	if p.cur.Lit[0] != '{' { +		fmt.Fprintf(os.Stderr, "error when parsing object. Was expecting an opening bracket but got %s at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} +	// hack to deal with case where there is no white space between +	// the delimiters. +	if p.cur.Lit == "{}" { +		return +	} + +	for { +		more := p.keyvalue() +		if !more { +			break +		} +	} +} + +func (p *parser) keyvalue() bool { +	p.advanceOneToken("keyvalue") + +	fmt.Fprintf(os.Stderr, "keyvalue: tokentype: %d, token: %q\n", p.cur.Type, p.cur.Lit) +	if p.cur.Type != Literal { +		fmt.Fprintf(os.Stderr, "error when parsing keyvalue. Was expecting a name but got %q at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} + +	p.advanceOneToken("keyvalue") +	if p.cur.Lit != "=>" { +		fmt.Fprintf(os.Stderr, "error when parsing keyvalue. Was expecting a '=>' but got %q at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} + +	p.advanceOneToken("keyvalue") +	if p.cur.Type != Literal && p.cur.Type != Name { +		fmt.Fprintf(os.Stderr, "error when parsing keyvalue. Was expecting a literal or a name but got %q at line %d offset %d.\n", p.cur.Lit, p.cur.LineNr, p.cur.Offset) +	} + +	tok, err := p.s.Peek() +	if err != nil { +		fmt.Fprintf(os.Stderr, "error when parsing keyvalue. Got an error when checking if there are more keyvalues: %v.\n", err) +		return false +	} + +	fmt.Fprintf(os.Stderr, "peeked %q (type %d) at line %d offset %d.\n", tok.Lit, tok.Type, tok.LineNr, tok.Offset) +	if tok.Type == ObjectClose { +		p.advanceOneToken("keyvaluelast") +		return false +	} + +	return true  } diff --git a/conf/scanner.go b/conf/scanner.go index 54546aa..975a8e4 100644 --- a/conf/scanner.go +++ b/conf/scanner.go @@ -14,15 +14,19 @@ type tokentype int  const (  	Name tokentype = iota  	Literal -	DeliOpen -	DeliClose +	ListOpen +	ListClose +	ObjectOpen +	ObjectClose +	EmptyList +	EmptyObject  	Nothing  	IfStatement  )  var tokentypestrings []string = []string{Name: "Name", Literal: "Literal", -	DeliOpen: "Opening delimiter", DeliClose: "Closing delimiter", -	Nothing: "Nothing", IfStatement: "If statement"} +	ListOpen: "List Open", ListClose: "List Close", ObjectOpen: "Object Open", +	ObjectClose: "Object Close", Nothing: "Nothing", IfStatement: "If statement"}  func (tt tokentype) String() string {  	return tokentypestrings[tt] @@ -39,6 +43,8 @@ type scanner struct {  	data    []byte  	offset  int  	curline int + +	peeked *token  }  func newScanner(r io.Reader) *scanner { @@ -58,18 +64,36 @@ func newScanner(r io.Reader) *scanner {  }  func getTokenType(s []byte) tokentype { -	return Nothing +	switch s[0] { +	case '"', '\'': +		return Literal +	case '[': +		return ListOpen +	case ']': +		return ListClose +	case '{': +		return ObjectOpen +	case '}': +		return ObjectClose +	} + +	return Name  }  func (s *scanner) Scan() (token, error) {  	processed := 0  	tokenstarted := false  	oldline := s.curline +	if s.peeked != nil { +		ret := *s.peeked +		s.peeked = nil +		return ret, nil +	}  	for {  		r, rlen := utf8.DecodeRune(s.data[s.offset+processed:])  		if r == utf8.RuneError {  			if rlen == 1 { -				return token{}, fmt.Errorf("found invalid UTF8 at offset %d, before: %s", s.offset, s.data[s.offset]) +				return token{}, fmt.Errorf("found invalid UTF8 at offset %d, before: %s", s.offset, string(s.data[s.offset]))  			} else if rlen == 0 {  				return token{}, io.EOF  			} @@ -105,6 +129,15 @@ func (s *scanner) Scan() (token, error) {  	return ret, nil  } -func (s *scanner) peek() (tokentype, string, error) { -	return Nothing, "", nil +func (s *scanner) Peek() (token, error) { +	if s.peeked != nil { +		return *s.peeked, nil +	} + +	tok, err := s.Scan() +	if err != nil { +		return token{}, err +	} +	s.peeked = &tok +	return tok, nil  } diff --git a/stasher.cfg b/stasher.cfg index e0df958..d0fe9c1 100644 --- a/stasher.cfg +++ b/stasher.cfg @@ -5,6 +5,7 @@ input {  filter {  	http {  		"F" => "localhost:9200" +		"G" => "localhost:9201"  	}   }  | 
