diff --git a/parse/lex.go b/parse/lex.go index 263b528..a772abc 100644 --- a/parse/lex.go +++ b/parse/lex.go @@ -123,8 +123,8 @@ func (l *lexer) nextItem() item { // lex creates a new scanner for the input string. func lex(input string, noDigit bool) *lexer { l := &lexer{ - input: input, - items: make(chan item), + input: input, + items: make(chan item), noDigit: noDigit, } go l.run() @@ -172,7 +172,7 @@ Loop: } l.subsDepth++ l.emit(itemLeftDelim) - return lexSubstitution + return lexSubstitutionOperator case isAlphaNumeric(r): return lexVariable } @@ -204,13 +204,13 @@ func lexVariable(l *lexer) stateFn { } l.emit(itemVariable) if l.subsDepth > 0 { - return lexSubstitution + return lexSubstitutionOperator } return lexText } -// lexSubstitution scans the elements inside substitution delimiters. -func lexSubstitution(l *lexer) stateFn { +// lexSubstitutionOperator scans a starting substitution operator (if any) and continues with lexSubstitution +func lexSubstitutionOperator(l *lexer) stateFn { switch r := l.next(); { case r == '}': l.subsDepth-- @@ -218,10 +218,6 @@ func lexSubstitution(l *lexer) stateFn { return lexText case r == eof || isEndOfLine(r): return l.errorf("closing brace expected") - case isAlphaNumeric(r) && strings.HasPrefix(l.input[l.lastPos:], "${"): - fallthrough - case r == '$': - return lexVariable case r == '+': l.emit(itemPlus) case r == '-': @@ -236,9 +232,24 @@ func lexSubstitution(l *lexer) stateFn { l.emit(itemColonEquals) case '+': l.emit(itemColonPlus) - default: - l.emit(itemText) } + } + return lexSubstitution +} + +// lexSubstitution scans the elements inside substitution delimiters. +func lexSubstitution(l *lexer) stateFn { + switch r := l.next(); { + case r == '}': + l.subsDepth-- + l.emit(itemRightDelim) + return lexText + case r == eof || isEndOfLine(r): + return l.errorf("closing brace expected") + case isAlphaNumeric(r) && strings.HasPrefix(l.input[l.lastPos:], "${"): + fallthrough + case r == '$': + return lexVariable default: l.emit(itemText) } diff --git a/parse/lex_test.go b/parse/lex_test.go index 86c4f21..06401a7 100644 --- a/parse/lex_test.go +++ b/parse/lex_test.go @@ -1,8 +1,8 @@ package parse import ( - "testing" "strings" + "testing" ) type lexTest struct { @@ -76,6 +76,28 @@ var lexTests = []lexTest{ {itemText, 0, " foo"}, tEOF, }}, + {"substitution-leading-dash-1", "bar ${BAR:--1} foo", []item{ + {itemText, 0, "bar "}, + tLeft, + {itemVariable, 0, "BAR"}, + tColDash, + {itemText, 0, "-"}, + {itemText, 0, "1"}, + tRight, + {itemText, 0, " foo"}, + tEOF, + }}, + {"substitution-leading-dash-2", "bar ${BAR:=-1} foo", []item{ + {itemText, 0, "bar "}, + tLeft, + {itemVariable, 0, "BAR"}, + tColEquals, + {itemText, 0, "-"}, + {itemText, 0, "1"}, + tRight, + {itemText, 0, " foo"}, + tEOF, + }}, {"closing brace error", "hello-${world", []item{ {itemText, 0, "hello-"}, tLeft, diff --git a/parse/parse_test.go b/parse/parse_test.go index eeb44a4..30a89f0 100644 --- a/parse/parse_test.go +++ b/parse/parse_test.go @@ -63,6 +63,12 @@ var parseTests = []parseTest{ {"issue #1", "${hello:=wo_rld} ${foo:=bar_baz}", "wo_rld bar_baz", errNone}, {"issue #2", "name: ${NAME:=foo_qux}, key: ${EMPTY:=baz_bar}", "name: foo_qux, key: baz_bar", errNone}, {"gh-issue-8", "prop=${HOME_URL-http://localhost:8080}", "prop=http://localhost:8080", errNone}, + // operators as leading values + {"gh-issue-41-1", "${NOTSET--1}", "-1", errNone}, + {"gh-issue-41-2", "${NOTSET:--1}", "-1", errNone}, + {"gh-issue-41-3", "${NOTSET=-1}", "-1", errNone}, + {"gh-issue-41-4", "${NOTSET:==1}", "=1", errNone}, + // bad substitution {"closing brace expected", "hello ${", "", errAll},