From c5fffb4ac2631f0b41a8e13b62925b9dc8346cb9 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Fri, 18 Mar 2022 17:08:23 -0400 Subject: caddyfile: Support for raw token values; improve `map`, `expression` (#4643) * caddyfile: Support for raw token values, improve `map`, `expression` * Applied code review comments * Rename RawVal to ValRaw Co-authored-by: Matthew Holt --- caddyconfig/caddyfile/dispenser.go | 63 ++++++++++++++++++++++++++++++++++++++ caddyconfig/caddyfile/lexer.go | 12 +++++--- 2 files changed, 70 insertions(+), 5 deletions(-) (limited to 'caddyconfig') diff --git a/caddyconfig/caddyfile/dispenser.go b/caddyconfig/caddyfile/dispenser.go index 23f6ead..fbe71ad 100755 --- a/caddyconfig/caddyfile/dispenser.go +++ b/caddyconfig/caddyfile/dispenser.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "log" + "strconv" "strings" ) @@ -201,6 +202,43 @@ func (d *Dispenser) Val() string { return d.tokens[d.cursor].Text } +// ValRaw gets the raw text of the current token (including quotes). +// If there is no token loaded, it returns empty string. +func (d *Dispenser) ValRaw() string { + if d.cursor < 0 || d.cursor >= len(d.tokens) { + return "" + } + quote := d.tokens[d.cursor].wasQuoted + if quote > 0 { + return string(quote) + d.tokens[d.cursor].Text + string(quote) // string literal + } + return d.tokens[d.cursor].Text +} + +// ScalarVal gets value of the current token, converted to the closest +// scalar type. If there is no token loaded, it returns nil. +func (d *Dispenser) ScalarVal() interface{} { + if d.cursor < 0 || d.cursor >= len(d.tokens) { + return nil + } + quote := d.tokens[d.cursor].wasQuoted + text := d.tokens[d.cursor].Text + + if quote > 0 { + return text // string literal + } + if num, err := strconv.Atoi(text); err == nil { + return num + } + if num, err := strconv.ParseFloat(text, 64); err == nil { + return num + } + if bool, err := strconv.ParseBool(text); err == nil { + return bool + } + return text +} + // Line gets the line number of the current token. // If there is no token loaded, it returns 0. func (d *Dispenser) Line() int { @@ -249,6 +287,19 @@ func (d *Dispenser) AllArgs(targets ...*string) bool { return true } +// CountRemainingArgs counts the amount of remaining arguments +// (tokens on the same line) without consuming the tokens. +func (d *Dispenser) CountRemainingArgs() int { + count := 0 + for d.NextArg() { + count++ + } + for i := 0; i < count; i++ { + d.Prev() + } + return count +} + // RemainingArgs loads any more arguments (tokens on the same line) // into a slice and returns them. Open curly brace tokens also indicate // the end of arguments, and the curly brace is not included in @@ -261,6 +312,18 @@ func (d *Dispenser) RemainingArgs() []string { return args } +// RemainingArgsRaw loads any more arguments (tokens on the same line, +// retaining quotes) into a slice and returns them. Open curly brace +// tokens also indicate the end of arguments, and the curly brace is +// not included in the return value nor is it loaded. +func (d *Dispenser) RemainingArgsRaw() []string { + var args []string + for d.NextArg() { + args = append(args, d.ValRaw()) + } + return args +} + // NewFromNextSegment 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 diff --git a/caddyconfig/caddyfile/lexer.go b/caddyconfig/caddyfile/lexer.go index 968277f..4a23524 100755 --- a/caddyconfig/caddyfile/lexer.go +++ b/caddyconfig/caddyfile/lexer.go @@ -38,6 +38,7 @@ type ( File string Line int Text string + wasQuoted rune // enclosing quote character, if any inSnippet bool snippetName string } @@ -78,8 +79,9 @@ func (l *lexer) next() bool { var val []rune var comment, quoted, btQuoted, escaped bool - makeToken := func() bool { + makeToken := func(quoted rune) bool { l.token.Text = string(val) + l.token.wasQuoted = quoted return true } @@ -87,7 +89,7 @@ func (l *lexer) next() bool { ch, _, err := l.reader.ReadRune() if err != nil { if len(val) > 0 { - return makeToken() + return makeToken(0) } if err == io.EOF { return false @@ -110,10 +112,10 @@ func (l *lexer) next() bool { escaped = false } else { if quoted && ch == '"' { - return makeToken() + return makeToken('"') } if btQuoted && ch == '`' { - return makeToken() + return makeToken('`') } } if ch == '\n' { @@ -139,7 +141,7 @@ func (l *lexer) next() bool { comment = false } if len(val) > 0 { - return makeToken() + return makeToken(0) } continue } -- cgit v1.2.3