The parser needs to find the end of the s/// operator to find the flags before it even tries to parse the replacement expression as code. That means the lexer points to the end of the substitution operator when the heredoc is first encountered. That is why the parser looks after the substitution for the heredoc body, as shown in Re^2: Can't include a HEREDOC within RHS of a Regex.