diff options
author | Matthew Holt <mholt@users.noreply.github.com> | 2019-09-10 19:21:52 -0600 |
---|---|---|
committer | Matthew Holt <mholt@users.noreply.github.com> | 2019-09-10 19:21:52 -0600 |
commit | 2459c292a4d6fb0552eb9be3cecd955093ed853b (patch) | |
tree | 5f10e9c5d8e9250e83f7282e8d57d386cb54e8a6 /caddyconfig/caddyfile | |
parent | 0cf592fa2e0d2fff8e9379095bbe17f7c8cbd4f2 (diff) |
caddyfile: Improve Dispenser.NextBlock() to support nesting
Diffstat (limited to 'caddyconfig/caddyfile')
-rwxr-xr-x | caddyconfig/caddyfile/dispenser.go | 75 | ||||
-rwxr-xr-x | caddyconfig/caddyfile/dispenser_test.go | 2 |
2 files changed, 55 insertions, 22 deletions
diff --git a/caddyconfig/caddyfile/dispenser.go b/caddyconfig/caddyfile/dispenser.go index 938c985..de67ee1 100755 --- a/caddyconfig/caddyfile/dispenser.go +++ b/caddyconfig/caddyfile/dispenser.go @@ -123,18 +123,39 @@ func (d *Dispenser) NextLine() bool { // NextBlock can be used as the condition of a for loop // to load the next token as long as it opens a block or -// is already in a block. It returns true if a token was -// loaded, or false when the block's closing curly brace -// was loaded and thus the block ended. Nested blocks are -// not supported. -func (d *Dispenser) NextBlock() bool { - if d.nesting > 0 { - d.Next() +// is already in a block nested more than initialNestingLevel. +// In other words, a loop over NextBlock() will iterate +// all tokens in the block assuming the next token is an +// open curly brace, until the matching closing brace. +// The open and closing brace tokens for the outer-most +// block will be consumed internally and omitted from +// the iteration. +// +// Proper use of this method looks like this: +// +// for nesting := d.Nesting(); d.NextBlock(nesting); { +// } +// +// However, in simple cases where it is known that the +// Dispenser is new and has not already traversed state +// by a loop over NextBlock(), this will do: +// +// for d.NextBlock(0) { +// } +// +// As with other token parsing logic, a loop over +// NextBlock() should be contained within a loop over +// Next(), as it is usually prudent to skip the initial +// token. +func (d *Dispenser) NextBlock(initialNestingLevel int) bool { + if d.nesting > initialNestingLevel { + if !d.Next() { + return false // should be EOF error + } if d.Val() == "}" { d.nesting-- - return false } - return true + return d.nesting > initialNestingLevel } if !d.nextOnSameLine() { // block must open on same line return false @@ -143,19 +164,18 @@ func (d *Dispenser) NextBlock() bool { d.cursor-- // roll back if not opening brace return false } - d.Next() + d.Next() // consume open curly brace if d.Val() == "}" { - // open and then closed right away - return false + return false // open and then closed right away } d.nesting++ return true } -// Nested returns true if the token is currently nested -// inside a block (i.e. an open curly brace was consumed). -func (d *Dispenser) Nested() bool { - return d.nesting > 0 +// Nesting returns the current nesting level. Necessary +// if using NextBlock() +func (d *Dispenser) Nesting() int { + return d.nesting } // Val gets the text of the current token. If there is no token @@ -230,19 +250,32 @@ func (d *Dispenser) RemainingArgs() []string { // NewFromNextTokens returns a new dispenser with a copy of // the tokens from the current token until the end of the // "directive" whether that be to the end of the line or -// the end of a block that starts at the end of the line. +// the end of a block that starts at the end of the line; +// in other words, until the end of the segment. func (d *Dispenser) NewFromNextTokens() *Dispenser { tkns := []Token{d.Token()} for d.NextArg() { tkns = append(tkns, d.Token()) } - for d.NextBlock() { - for d.Nested() { + var openedBlock bool + for nesting := d.Nesting(); d.NextBlock(nesting); { + if !openedBlock { + // because NextBlock() consumes the initial open + // curly brace, we rewind here to append it, since + // our case is special in that we want to include + // all the tokens including surrounding curly braces + // for a new dispenser to have + d.Prev() tkns = append(tkns, d.Token()) - d.NextBlock() + d.Next() + openedBlock = true } + tkns = append(tkns, d.Token()) + } + if openedBlock { + // include closing brace accordingly + tkns = append(tkns, d.Token()) } - tkns = append(tkns, d.Token()) return NewDispenser(tkns) } diff --git a/caddyconfig/caddyfile/dispenser_test.go b/caddyconfig/caddyfile/dispenser_test.go index 07fbbee..494db36 100755 --- a/caddyconfig/caddyfile/dispenser_test.go +++ b/caddyconfig/caddyfile/dispenser_test.go @@ -148,7 +148,7 @@ func TestDispenser_NextBlock(t *testing.T) { d := newTestDispenser(input) assertNextBlock := func(shouldLoad bool, expectedCursor, expectedNesting int) { - if loaded := d.NextBlock(); loaded != shouldLoad { + if loaded := d.NextBlock(0); loaded != shouldLoad { t.Errorf("NextBlock(): Should return %v but got %v", shouldLoad, loaded) } if d.cursor != expectedCursor { |