diff --git a/lexers/r/raku.go b/lexers/r/raku.go index 5c4fea3..349cb98 100644 --- a/lexers/r/raku.go +++ b/lexers/r/raku.go @@ -513,14 +513,24 @@ func rakuRules() Rules { adverbre := regexp.MustCompile(`:to\b|:heredoc\b`) var heredocTerminator []rune + var endHeredocPos int if adverbre.MatchString(string(adverbs)) { - heredocTerminator = text[state.Pos:endPos] - if len(heredocTerminator) > 0 { - endHeredocPos := indexAt(text[endPos:], heredocTerminator, 0) + if endPos != len(text) { + heredocTerminator = text[state.Pos:endPos] nChars = len(heredocTerminator) - endPos += endHeredocPos } else { - endPos = len(text) + endPos = state.Pos + 1 + heredocTerminator = []rune{} + nChars = 0 + } + + if nChars > 0 { + endHeredocPos = indexAt(text[endPos:], heredocTerminator, 0) + if endHeredocPos > -1 { + endPos += endHeredocPos + } else { + endPos = len(text) + } } } @@ -532,7 +542,7 @@ func rakuRules() Rules { case rakuQuote: if len(heredocTerminator) > 0 { // Length of heredoc terminator + closing chars + `;` - heredocFristPunctuationLen := len(heredocTerminator) + len(openingChars) + 1 + heredocFristPunctuationLen := nChars + len(openingChars) + 1 state.NamedGroups[`opening_delimiters`] = string(openingChars) + string(text[state.Pos:state.Pos+heredocFristPunctuationLen]) @@ -540,10 +550,14 @@ func rakuRules() Rules { state.NamedGroups[`value`] = string(text[state.Pos+heredocFristPunctuationLen : endPos]) - state.NamedGroups[`closing_delimiters`] = string(heredocTerminator) + if endHeredocPos > -1 { + state.NamedGroups[`closing_delimiters`] = string(heredocTerminator) + } } else { state.NamedGroups[`value`] = textBetweenBrackets - state.NamedGroups[`closing_delimiters`] = string(closingChars) + if nChars > 0 { + state.NamedGroups[`closing_delimiters`] = string(closingChars) + } } default: state.Groups = []string{state.Groups[0] + string(text[state.Pos:endPos+nChars])} diff --git a/lexers/testdata/raku.actual b/lexers/testdata/raku/raku.actual similarity index 100% rename from lexers/testdata/raku.actual rename to lexers/testdata/raku/raku.actual diff --git a/lexers/testdata/raku.expected b/lexers/testdata/raku/raku.expected similarity index 100% rename from lexers/testdata/raku.expected rename to lexers/testdata/raku/raku.expected diff --git a/lexers/testdata/raku/unterminated_heredoc.actual b/lexers/testdata/raku/unterminated_heredoc.actual new file mode 100644 index 0000000..319757c --- /dev/null +++ b/lexers/testdata/raku/unterminated_heredoc.actual @@ -0,0 +1,8 @@ +say q:to//; + +say 'something'; + +# Unterminated heredoc +say q:to/Foo/; + +say 'something'; diff --git a/lexers/testdata/raku/unterminated_heredoc.expected b/lexers/testdata/raku/unterminated_heredoc.expected new file mode 100644 index 0000000..8f915f8 --- /dev/null +++ b/lexers/testdata/raku/unterminated_heredoc.expected @@ -0,0 +1,23 @@ +[ + {"type":"NameBuiltin","value":"say"}, + {"type":"Text","value":" "}, + {"type":"Keyword","value":"q"}, + {"type":"LiteralStringAffix","value":":to"}, + {"type":"Punctuation","value":"//"}, + {"type":"LiteralString","value":";"}, + {"type":"Text","value":"\n\n"}, + {"type":"NameBuiltin","value":"say"}, + {"type":"Text","value":" "}, + {"type":"Punctuation","value":"'"}, + {"type":"LiteralStringSingle","value":"something"}, + {"type":"Punctuation","value":"';"}, + {"type":"Text","value":"\n\n"}, + {"type":"CommentSingle","value":"# Unterminated heredoc"}, + {"type":"Text","value":"\n"}, + {"type":"NameBuiltin","value":"say"}, + {"type":"Text","value":" "}, + {"type":"Keyword","value":"q"}, + {"type":"LiteralStringAffix","value":":to"}, + {"type":"Punctuation","value":"/Foo/;"}, + {"type":"LiteralString","value":"\n\nsay 'something';\n"} +]