func (p *parser) parseAttr(modifiers *[]query.Modifier) (*tokenizer.Token, error) {
	ident := p.expect(tokenizer.Identifier)
	if ident == nil {
		return nil, p.currentError()
	}
	if token := p.expect(tokenizer.OpenParen); token == nil {
		if err := isValidAttribute(ident.Raw); err != nil {
			return nil, err
		}
		return ident, nil
	}
	attribute, err := p.parseAttr(modifiers)
	if err != nil {
		return nil, err
	}
	if attribute == nil {
		return nil, p.currentError()
	}
	if err := isValidAttribute(attribute.Raw); err != nil {
		return nil, err
	}
	modifier := query.Modifier{
		Name:      strings.ToUpper(ident.Raw),
		Arguments: make([]string, 0),
	}
	for {
		if token := p.expect(tokenizer.Identifier); token != nil {
			modifier.Arguments = append(modifier.Arguments, token.Raw)
			continue
		}
		if token := p.expect(tokenizer.Comma); token != nil {
			continue
		}
		if token := p.expect(tokenizer.CloseParen); token != nil {
			*modifiers = append(*modifiers, modifier)
			return attribute, nil
		}
	}
}
parseAttr recursively parses an attribute's modifiers and returns the
associated attribute.
package parser
import (
	"strings"
	"github.com/kashav/fsql/query"
	"github.com/kashav/fsql/tokenizer"
)
var allAttributes = []string{"mode", "size", "time", "hash", "name"}
func isValidAttribute(attribute string) error {
	for _, valid := range allAttributes {
		if attribute == valid {
			return nil
		}
	}
	return &ErrUnknownToken{attribute}
}
func (p *parser) parseAttrs(attributes *[]string, modifiers *map[string][]query.Modifier) error {
	for {
		ident := p.expect(tokenizer.Identifier)
		if ident == nil {
			return p.currentError()
		}
		if ident.Raw == "*" || ident.Raw == "all" {
			*attributes = allAttributes
		} else {
			p.current = ident
			attrModifiers := make([]query.Modifier, 0)
			attribute, err := p.parseAttr(&attrModifiers)
			if err != nil {
				return err
			}
			*attributes = append(*attributes, attribute.Raw)
			(*modifiers)[attribute.Raw] = attrModifiers
		}
		if p.expect(tokenizer.Comma) == nil {
			break
		}
	}
	return nil
}