I was surprised to discover that -graph- throws an error when the title (or various other strings) has a comma inside straight double quotes. This looks a lot like a bug to me, but I didn't find it by searching, and I can't believe such a simple thing wouldn't have been found already. Am I using compound quotes incorrectly?

Code:
sysuse auto, clear
graph bar rep78,  title(`" Quoth he, ‘Alas  poor Yorick!’ "') // no error with curly single
graph bar rep78,  title(`" Quoth he, “Alas  poor Yorick!” "') // no error with curly double
graph bar rep78,  title(`" Quoth he, 'Alas  poor Yorick!' "') // no error with straight single
graph bar rep78,  title(`" Quoth he, "Alas  poor Yorick!" "') // no error with straight double
graph bar rep78,  title(`" Quoth he, ‘Alas, poor Yorick!’ "') // no error with comma inside curly single
graph bar rep78,  title(`" Quoth he, “Alas, poor Yorick!” "') // no error with comma inside curly double
graph bar rep78,  title(`" Quoth he, 'Alas, poor Yorick!' "') // no error with comma inside straight single
graph bar rep78,  title(`" Quoth he, "Alas, poor Yorick!" "') // error with comma inside straight double
graph bar rep78, xtitle(`" Quoth he, "Alas, poor Yorick!" "') // error with xtitle
graph bar rep78, ytitle(`" Quoth he, "Alas, poor Yorick!" "') // error with ytitle
graph bar rep78,   note(`" Quoth he, "Alas, poor Yorick!" "') // error with note, etc…
The errors vary, but the one with title() is

Code:
too few quotes
r(132);
A trace shows a bad interaction between _parse and a subsequent if comparison.

Code:
              --------------------------------------------------------------------------------------------------------------------------------------------------------------- begin _fr_title_parse_and_log ---
              - gettoken log 0 : 0
              - gettoken obj 0 : 0
              - gettoken ttype 0 : 0
              - gettoken parsenm 0 : 0
              - gettoken scm_entry 0 : 0
              - local 0 , `0'
              = local 0 ,  title(`" Quoth he, "Alas, poor Yorick!" "')
              - syntax [ , `parsenm'(string asis) * ]
              = syntax [ , Title(string asis) * ]
              - local rest `"`options'"'
              = local rest `""'
              - while `"``ttype''"' != `""' {
              = while `"`" Quoth he, "Alas, poor Yorick!" "'"' != `""' {
              - local rest `"`options'"'
              = local rest `""'
              - _parse comma curlines 0 : `ttype'
              = _parse comma curlines 0 : title
              - syntax [ , NOSPAN SPAN PREFIX SUFFIX POSition(string) RING(string) STYle(string) * ]
              - if `"`curlines'"' != `""' {
              = if `"`" Quoth he, "Alas"' != `""' {
too few quotes
                if "`suffix'" != "" {
                local lines `"`lines' `curlines'"'
                if "`prefix'" != "" {
                di as text "option prefix ignored, " "may not be combined with suffix"
                }
                }
                else {
                if "`prefix'" != "" {
                local lines `"`curlines' `lines'"'
                }
                else {
                local lines `"`curlines'"'
                }
                }
                }
              ----------------------------------------------------------------------------------------------------------------------------------------------------------------- end _fr_title_parse_and_log ---
The error looks to me like it would be in _parse comma:

_parse comma lhs rhs : lin

Description of _parse comma

_parse comma looks for the first unbound comma in lin and splits the string into lhs and
rhs. Both lhs and rhs are trimmed of leading and trailing blanks. The first character of
rhs will be comma if lin contained an unbound comma.

Unbound in the above is a comma outside of quotes, parentheses, or brackets.
So I tried isolating it:

Code:
cap program drop parsebug
program define parsebug
    syntax [ , Title(string asis) * ]
    di `"Original string is ❚`title'❚"'
    _parse comma part1 part2 : title
    di `"It is parsed into ❚`part1'❚`part2'❚"'
    if `"`part1'"' != `""' {
        di "Part1 is not empty"
    }
end
parsebug, title(`" Quoth he, ‘Alas  poor Yorick!’ "') // no error
parsebug, title(`" Quoth he, “Alas  poor Yorick!” "') // no error
parsebug, title(`" Quoth he, 'Alas  poor Yorick!' "') // no error
parsebug, title(`" Quoth he, "Alas  poor Yorick!" "') // no error
parsebug, title(`" Quoth he, ‘Alas, poor Yorick!’ "') // no error
parsebug, title(`" Quoth he, “Alas, poor Yorick!” "') // no error
parsebug, title(`" Quoth he, 'Alas, poor Yorick!' "') // no error
parsebug, title(`" Quoth he, "Alas, poor Yorick!" "') // error
In the last instance, _parse finds a comma that it doesn't find in the earlier instance:

Code:
. parsebug, title(`" Quoth he, ‘Alas  poor Yorick!’ "') // no error
Original string is ❚`" Quoth he, ‘Alas  poor Yorick!’ "'❚
It is parsed into ❚`" Quoth he, ‘Alas  poor Yorick!’ "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, “Alas  poor Yorick!” "') // no error
Original string is ❚`" Quoth he, “Alas  poor Yorick!” "'❚
It is parsed into ❚`" Quoth he, “Alas  poor Yorick!” "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, 'Alas  poor Yorick!' "') // no error
Original string is ❚`" Quoth he, 'Alas  poor Yorick!' "'❚
It is parsed into ❚`" Quoth he, 'Alas  poor Yorick!' "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, "Alas  poor Yorick!" "') // no error
Original string is ❚`" Quoth he, "Alas  poor Yorick!" "'❚
It is parsed into ❚`" Quoth he, "Alas  poor Yorick!" "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, ‘Alas, poor Yorick!’ "') // no error
Original string is ❚`" Quoth he, ‘Alas, poor Yorick!’ "'❚
It is parsed into ❚`" Quoth he, ‘Alas, poor Yorick!’ "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, “Alas, poor Yorick!” "') // no error
Original string is ❚`" Quoth he, “Alas, poor Yorick!” "'❚
It is parsed into ❚`" Quoth he, “Alas, poor Yorick!” "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, 'Alas, poor Yorick!' "') // no error
Original string is ❚`" Quoth he, 'Alas, poor Yorick!' "'❚
It is parsed into ❚`" Quoth he, 'Alas, poor Yorick!' "'❚❚
Part1 is not empty

. parsebug, title(`" Quoth he, "Alas, poor Yorick!" "') // error
Original string is ❚`" Quoth he, "Alas, poor Yorick!" "'❚
It is parsed into ❚`" Quoth he, "Alas❚, poor Yorick!" "'❚
too few quotes
r(132);
Firstly, I think _parse comma should not be finding that comma, because I think it is a bound comma.

Secondly, I think _fr_title_parse_and_log and related programs should sanitize the string so quotes in the string don't cause the comparison to fail.

Do those two conclusions seem correct (and I should escalate to support), or am I thinking about this wrong?