diff --git a/decoder_test.go b/decoder_test.go index 12276e2..25e87fb 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -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", diff --git a/hcl/lex.go b/hcl/lex.go index ba1d6f7..90b9bc0 100644 --- a/hcl/lex.go +++ b/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. < 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 diff --git a/test-fixtures/multiline_bad.hcl b/test-fixtures/multiline_bad.hcl index 7ef0cb0..f883bd7 100644 --- a/test-fixtures/multiline_bad.hcl +++ b/test-fixtures/multiline_bad.hcl @@ -1,2 +1,4 @@ -foo = "bar -baz" +foo = <