Skip to content

Commit

Permalink
parse: allow default value expression starting with operators (#42)
Browse files Browse the repository at this point in the history
Fixes #41
  • Loading branch information
neiser authored Feb 3, 2023
1 parent dffd717 commit 4932428
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 13 deletions.
35 changes: 23 additions & 12 deletions parse/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -172,7 +172,7 @@ Loop:
}
l.subsDepth++
l.emit(itemLeftDelim)
return lexSubstitution
return lexSubstitutionOperator
case isAlphaNumeric(r):
return lexVariable
}
Expand Down Expand Up @@ -204,24 +204,20 @@ 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--
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
case r == '+':
l.emit(itemPlus)
case r == '-':
Expand All @@ -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)
}
Expand Down
24 changes: 23 additions & 1 deletion parse/lex_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package parse

import (
"testing"
"strings"
"testing"
)

type lexTest struct {
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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},

Expand Down

0 comments on commit 4932428

Please sign in to comment.