hcl: support heredocs [GH-6]
This commit is contained in:
parent
8a779f6e41
commit
26239b8eab
@ -37,7 +37,7 @@ func TestDecode_interface(t *testing.T) {
|
||||
{
|
||||
"multiline_bad.hcl",
|
||||
false,
|
||||
map[string]interface{}{"foo": "bar\nbaz"},
|
||||
map[string]interface{}{"foo": "bar\nbaz\n"},
|
||||
},
|
||||
{
|
||||
"multiline.json",
|
||||
|
88
hcl/lex.go
88
hcl/lex.go
@ -94,6 +94,8 @@ func (x *hclLex) Lex(yylval *hclSymType) int {
|
||||
return RIGHTBRACE
|
||||
case '"':
|
||||
return x.lexString(yylval)
|
||||
case '<':
|
||||
return x.lexHeredoc(yylval)
|
||||
default:
|
||||
x.backup()
|
||||
return x.lexId(yylval)
|
||||
@ -191,6 +193,86 @@ func (x *hclLex) lexId(yylval *hclSymType) int {
|
||||
return IDENTIFIER
|
||||
}
|
||||
|
||||
// lexHeredoc extracts a string from the input in heredoc format
|
||||
func (x *hclLex) lexHeredoc(yylval *hclSymType) int {
|
||||
if x.next() != '<' {
|
||||
x.createErr("Heredoc must start with <<")
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
// Now determine the marker
|
||||
var buf bytes.Buffer
|
||||
for {
|
||||
c := x.next()
|
||||
if c == lexEOF {
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
// Newline signals the end of the marker
|
||||
if c == '\n' {
|
||||
break
|
||||
}
|
||||
|
||||
if _, err := buf.WriteRune(c); err != nil {
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
|
||||
marker := buf.String()
|
||||
if marker == "" {
|
||||
x.createErr("Heredoc must have a marker, e.g. <<FOO")
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
check := true
|
||||
buf.Reset()
|
||||
for {
|
||||
c := x.next()
|
||||
|
||||
// If we're checking, then check to see if we see the marker
|
||||
if check {
|
||||
check = false
|
||||
|
||||
var cs []rune
|
||||
for _, r := range marker {
|
||||
if r != c {
|
||||
break
|
||||
}
|
||||
|
||||
cs = append(cs, c)
|
||||
c = x.next()
|
||||
}
|
||||
if len(cs) == len(marker) {
|
||||
break
|
||||
}
|
||||
|
||||
if len(cs) > 0 {
|
||||
for _, c := range cs {
|
||||
if _, err := buf.WriteRune(c); err != nil {
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c == lexEOF {
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
// If we hit a newline, then reset to check
|
||||
if c == '\n' {
|
||||
check = true
|
||||
}
|
||||
|
||||
if _, err := buf.WriteRune(c); err != nil {
|
||||
return lexEOF
|
||||
}
|
||||
}
|
||||
|
||||
yylval.str = buf.String()
|
||||
return STRING
|
||||
}
|
||||
|
||||
// lexNumber lexes out a number
|
||||
func (x *hclLex) lexNumber(yylval *hclSymType) int {
|
||||
var b bytes.Buffer
|
||||
@ -238,6 +320,12 @@ func (x *hclLex) lexString(yylval *hclSymType) int {
|
||||
break
|
||||
}
|
||||
|
||||
// If we hit a newline, then its an error
|
||||
if c == '\n' {
|
||||
x.createErr(fmt.Sprintf("Newline before string closed"))
|
||||
return lexEOF
|
||||
}
|
||||
|
||||
// If we're starting into variable, mark it
|
||||
if braces == 0 && c == '$' && x.peek() == '{' {
|
||||
braces += 1
|
||||
|
@ -1,2 +1,4 @@
|
||||
foo = "bar
|
||||
baz"
|
||||
foo = <<EOF
|
||||
bar
|
||||
baz
|
||||
EOF
|
||||
|
Loading…
Reference in New Issue
Block a user