Support for namelists. Fixes #3.
This commit is contained in:
parent
e343ba3689
commit
8cb7110099
2 changed files with 46 additions and 2 deletions
30
expand.go
30
expand.go
|
|
@ -3,6 +3,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
@ -136,18 +137,45 @@ func expandSigil(input string, vars map[string][]string) ([]string, int) {
|
||||||
c, w := utf8.DecodeRuneInString(input)
|
c, w := utf8.DecodeRuneInString(input)
|
||||||
var offset int
|
var offset int
|
||||||
var varname string
|
var varname string
|
||||||
|
var namelist_pattern = regexp.MustCompile(`^\s*([^:]+)\s*:\s*([^%]*)%([^=]*)\s*=\s*([^%]*)%([^%]*)\s*`)
|
||||||
|
|
||||||
// escaping of "$" with "$$"
|
// escaping of "$" with "$$"
|
||||||
if c == '$' {
|
if c == '$' {
|
||||||
return []string{"$"}, 2
|
return []string{"$"}, 2
|
||||||
|
// match bracketed expansions: ${foo}, or ${foo:a%b=c%d}
|
||||||
} else if c == '{' {
|
} else if c == '{' {
|
||||||
j := strings.IndexRune(input[w:], '}')
|
j := strings.IndexRune(input[w:], '}')
|
||||||
if j < 0 {
|
if j < 0 {
|
||||||
return []string{"$" + input}, len(input)
|
return []string{"$" + input}, len(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
varname = input[w : w+j]
|
varname = input[w : w+j]
|
||||||
offset = w + j + 1
|
offset = w + j + 1
|
||||||
|
|
||||||
|
// is this a namelist?
|
||||||
|
mat := namelist_pattern.FindStringSubmatch(varname)
|
||||||
|
if mat != nil && isValidVarName(mat[1]) {
|
||||||
|
// ${varname:a%b=c%d}
|
||||||
|
varname = mat[1]
|
||||||
|
a, b, c, d := mat[2], mat[3], mat[4], mat[5]
|
||||||
|
values, ok := vars[varname]
|
||||||
|
if !ok {
|
||||||
|
return []string{}, offset
|
||||||
|
}
|
||||||
|
|
||||||
|
pat := regexp.MustCompile(strings.Join([]string{`^\Q`, a, `\E(.*)\Q`, b, `\E$`}, ""))
|
||||||
|
expanded_values := make([]string, len(values))
|
||||||
|
for i, value := range values {
|
||||||
|
value_match := pat.FindStringSubmatch(value)
|
||||||
|
if value_match != nil {
|
||||||
|
expanded_values[i] = strings.Join([]string{c, value_match[1], d}, "")
|
||||||
|
} else {
|
||||||
|
expanded_values[i] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expanded_values, offset
|
||||||
|
}
|
||||||
|
// bare variables: $foo
|
||||||
} else {
|
} else {
|
||||||
// try to match a variable name
|
// try to match a variable name
|
||||||
i := 0
|
i := 0
|
||||||
|
|
|
||||||
18
lex.go
18
lex.go
|
|
@ -11,7 +11,7 @@ type tokenType int
|
||||||
const eof rune = '\000'
|
const eof rune = '\000'
|
||||||
|
|
||||||
// Rune's that cannot be part of a bare (unquoted) string.
|
// Rune's that cannot be part of a bare (unquoted) string.
|
||||||
const nonBareRunes = " \t\n\r\\=:#'\""
|
const nonBareRunes = " \t\n\r\\=:#'\"$"
|
||||||
|
|
||||||
// Return true if the string contains whitespace only.
|
// Return true if the string contains whitespace only.
|
||||||
func onlyWhitespace(s string) bool {
|
func onlyWhitespace(s string) bool {
|
||||||
|
|
@ -383,6 +383,14 @@ func lexBareWord(l *lexer) lexerStateFun {
|
||||||
l.next()
|
l.next()
|
||||||
return lexBareWord
|
return lexBareWord
|
||||||
}
|
}
|
||||||
|
} else if c == '$' {
|
||||||
|
c1 := l.peekN(1)
|
||||||
|
if c1 == '{' {
|
||||||
|
return lexBracketExpansion
|
||||||
|
} else {
|
||||||
|
l.next()
|
||||||
|
return lexBareWord
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.start < l.pos {
|
if l.start < l.pos {
|
||||||
|
|
@ -391,3 +399,11 @@ func lexBareWord(l *lexer) lexerStateFun {
|
||||||
|
|
||||||
return lexTopLevel
|
return lexTopLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lexBracketExpansion(l *lexer) lexerStateFun {
|
||||||
|
l.next() // '$'
|
||||||
|
l.next() // '{'
|
||||||
|
l.acceptUntil("}")
|
||||||
|
l.next() // '}'
|
||||||
|
return lexBareWord
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue