Clean up Dispenser and filename handling a bit

This commit is contained in:
Matthew Holt 2019-08-21 15:23:00 -06:00
parent 59910923d1
commit 8420a2f250
No known key found for this signature in database
GPG key ID: 2A349DD577D586A5
5 changed files with 33 additions and 47 deletions

View file

@ -24,19 +24,16 @@ import (
// except that it can do so with some notion of structure. An empty // except that it can do so with some notion of structure. An empty
// Dispenser is invalid; call NewDispenser to make a proper instance. // Dispenser is invalid; call NewDispenser to make a proper instance.
type Dispenser struct { type Dispenser struct {
filename string tokens []Token
tokens []Token cursor int
cursor int nesting int
nesting int
} }
// NewDispenser returns a Dispenser filled with the given tokens. // NewDispenser returns a Dispenser filled with the given tokens.
// TODO: Get rid of the filename argument; it seems pointless here func NewDispenser(tokens []Token) *Dispenser {
func NewDispenser(filename string, tokens []Token) *Dispenser {
return &Dispenser{ return &Dispenser{
filename: filename, tokens: tokens,
tokens: tokens, cursor: -1,
cursor: -1,
} }
} }
@ -170,8 +167,8 @@ func (d *Dispenser) Val() string {
return d.tokens[d.cursor].Text return d.tokens[d.cursor].Text
} }
// Line gets the line number of the current token. If there is no token // Line gets the line number of the current token.
// loaded, it returns 0. // If there is no token loaded, it returns 0.
func (d *Dispenser) Line() int { func (d *Dispenser) Line() int {
if d.cursor < 0 || d.cursor >= len(d.tokens) { if d.cursor < 0 || d.cursor >= len(d.tokens) {
return 0 return 0
@ -179,16 +176,12 @@ func (d *Dispenser) Line() int {
return d.tokens[d.cursor].Line return d.tokens[d.cursor].Line
} }
// File gets the filename of the current token. If there is no token loaded, // File gets the filename where the current token originated.
// it returns the filename originally given when parsing started.
func (d *Dispenser) File() string { func (d *Dispenser) File() string {
if d.cursor < 0 || d.cursor >= len(d.tokens) { if d.cursor < 0 || d.cursor >= len(d.tokens) {
return d.filename return ""
} }
if tokenFilename := d.tokens[d.cursor].File; tokenFilename != "" { return d.tokens[d.cursor].File
return tokenFilename
}
return d.filename
} }
// Args is a convenience function that loads the next arguments // Args is a convenience function that loads the next arguments
@ -240,28 +233,22 @@ func (d *Dispenser) NewFromNextTokens() *Dispenser {
} else { } else {
d.cursor-- d.cursor--
} }
return NewDispenser(d.filename, tkns) return NewDispenser(tkns)
} }
// Token returns the current token. // Token returns the current token.
func (d *Dispenser) Token() Token { func (d *Dispenser) Token() Token {
return d.TokenAt(d.cursor) if d.cursor < 0 || d.cursor >= len(d.tokens) {
}
func (d *Dispenser) TokenAt(cursor int) Token {
if cursor < 0 || cursor >= len(d.tokens) {
return Token{} return Token{}
} }
return d.tokens[cursor] return d.tokens[d.cursor]
}
// Cursor returns the current cursor (token index).
func (d *Dispenser) Cursor() int {
return d.cursor
} }
// Reset sets d's cursor to the beginning, as
// if this was a new and unused dispenser.
func (d *Dispenser) Reset() { func (d *Dispenser) Reset() {
d.cursor = -1 d.cursor = -1
d.nesting = 0
} }
// ArgErr returns an argument error, meaning that another // ArgErr returns an argument error, meaning that another

View file

@ -308,9 +308,9 @@ func TestDispenser_ArgErr_Err(t *testing.T) {
} }
func newTestDispenser(input string) *Dispenser { func newTestDispenser(input string) *Dispenser {
tokens, err := allTokens(strings.NewReader(input)) tokens, err := allTokens("Testfile", strings.NewReader(input))
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
log.Fatalf("getting all tokens from input: %v", err) log.Fatalf("getting all tokens from input: %v", err)
} }
return NewDispenser("Testfile", tokens) return NewDispenser(tokens)
} }

View file

@ -29,18 +29,18 @@ import (
// an error. If you do not want to check for valid directives, // an error. If you do not want to check for valid directives,
// pass in nil instead. // pass in nil instead.
func Parse(filename string, input io.Reader) ([]ServerBlock, error) { func Parse(filename string, input io.Reader) ([]ServerBlock, error) {
tokens, err := allTokens(input) tokens, err := allTokens(filename, input)
if err != nil { if err != nil {
return nil, err return nil, err
} }
p := parser{Dispenser: NewDispenser(filename, tokens)} p := parser{Dispenser: NewDispenser(tokens)}
return p.parseAll() return p.parseAll()
} }
// allTokens lexes the entire input, but does not parse it. // allTokens lexes the entire input, but does not parse it.
// It returns all the tokens from the input, unstructured // It returns all the tokens from the input, unstructured
// and in order. // and in order.
func allTokens(input io.Reader) ([]Token, error) { func allTokens(filename string, input io.Reader) ([]Token, error) {
l := new(lexer) l := new(lexer)
err := l.load(input) err := l.load(input)
if err != nil { if err != nil {
@ -48,6 +48,7 @@ func allTokens(input io.Reader) ([]Token, error) {
} }
var tokens []Token var tokens []Token
for l.next() { for l.next() {
l.token.File = filename
tokens = append(tokens, l.token) tokens = append(tokens, l.token)
} }
return tokens, nil return tokens, nil
@ -265,7 +266,7 @@ func (p *parser) doImport() error {
// list of matching filenames // list of matching filenames
absFile, err := filepath.Abs(p.Dispenser.File()) absFile, err := filepath.Abs(p.Dispenser.File())
if err != nil { if err != nil {
return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err) return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.File(), err)
} }
var matches []string var matches []string
@ -327,7 +328,7 @@ func (p *parser) doSingleImport(importFile string) ([]Token, error) {
return nil, p.Errf("Could not import %s: is a directory", importFile) return nil, p.Errf("Could not import %s: is a directory", importFile)
} }
importedTokens, err := allTokens(file) importedTokens, err := allTokens(importFile, file)
if err != nil { if err != nil {
return nil, p.Errf("Could not read tokens while importing %s: %v", importFile, err) return nil, p.Errf("Could not read tokens while importing %s: %v", importFile, err)
} }
@ -336,7 +337,7 @@ func (p *parser) doSingleImport(importFile string) ([]Token, error) {
// (we use full, absolute path to avoid bugs: issue #1892) // (we use full, absolute path to avoid bugs: issue #1892)
filename, err := filepath.Abs(importFile) filename, err := filepath.Abs(importFile)
if err != nil { if err != nil {
return nil, p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err) return nil, p.Errf("Failed to get absolute path of file: %s: %v", importFile, err)
} }
for i := 0; i < len(importedTokens); i++ { for i := 0; i < len(importedTokens); i++ {
importedTokens[i].File = filename importedTokens[i].File = filename
@ -497,7 +498,7 @@ func (sb ServerBlock) DispenseDirective(dir string) *Dispenser {
tokens = append(tokens, seg...) tokens = append(tokens, seg...)
} }
} }
return NewDispenser("", tokens) return NewDispenser(tokens)
} }
// Segment is a list of tokens which begins with a directive // Segment is a list of tokens which begins with a directive
@ -513,9 +514,3 @@ func (s Segment) Directive() string {
} }
return "" return ""
} }
// NewDispenser returns a dispenser for this
// segment's tokens.
func (s Segment) NewDispenser() *Dispenser {
return NewDispenser("", s)
}

View file

@ -27,7 +27,7 @@ import (
func TestAllTokens(t *testing.T) { func TestAllTokens(t *testing.T) {
input := strings.NewReader("a b c\nd e") input := strings.NewReader("a b c\nd e")
expected := []string{"a", "b", "c", "d", "e"} expected := []string{"a", "b", "c", "d", "e"}
tokens, err := allTokens(input) tokens, err := allTokens("TestAllTokens", input)
if err != nil { if err != nil {
t.Fatalf("Expected no error, got %v", err) t.Fatalf("Expected no error, got %v", err)

View file

@ -38,6 +38,10 @@ func init() {
type ServerType struct { type ServerType struct {
} }
// TODO: customize directive ordering
// TODO: hide caddyfile when serving static files
// Setup makes a config from the tokens. // Setup makes a config from the tokens.
func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock, func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
options map[string]string) (*caddy.Config, []caddyconfig.Warning, error) { options map[string]string) (*caddy.Config, []caddyconfig.Warning, error) {
@ -88,7 +92,7 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock,
} }
if dirFunc, ok := registeredDirectives[dir]; ok { if dirFunc, ok := registeredDirectives[dir]; ok {
results, err := dirFunc(Helper{ results, err := dirFunc(Helper{
Dispenser: segment.NewDispenser(), Dispenser: caddyfile.NewDispenser(segment),
warnings: &warnings, warnings: &warnings,
matcherDefs: matcherDefs, matcherDefs: matcherDefs,
}) })