diff --git a/parser.go b/parser.go index 8ba6b8b..afdeecb 100644 --- a/parser.go +++ b/parser.go @@ -2536,13 +2536,16 @@ func (p *Parser) methodName() string { return t.Lit } switch t.Type { - // Operator methods called explicitly: 1.+(2), a.<=>(b), obj.&(x), … + // Operator methods called explicitly: 1.+(2), a.<=>(b), obj.&(x), … Each + // operator token names the method by its own spelling ("+", "<=>", "&", …). case token.SPACESHIP, token.LT, token.GT, token.LE, token.GE, token.EQ, token.EQQ, token.NEQ, token.SHOVEL, token.RSHIFT, token.PLUS, token.MINUS, token.STAR, token.SLASH, token.PERCENT, token.POW, - token.AMPER, token.PIPE, token.CARET, token.TILDE, token.MATCH, token.NMATCH, token.BANG, - token.XSTRING: - // XSTRING here is an empty backtick literal `` produced when `` ` `` names the - // backtick method (`def \`(cmd); end`, `obj.\``). + token.AMPER, token.PIPE, token.CARET, token.TILDE, token.MATCH, token.NMATCH, token.BANG: + p.advance() + return t.Type.String() + case token.XSTRING: + // An empty backtick literal `` produced when `` ` `` names the backtick + // method (`def \`(cmd); end`, `obj.\``). p.advance() return "`" } diff --git a/round4_features_test.go b/round4_features_test.go index 7b7ee3e..0107350 100644 --- a/round4_features_test.go +++ b/round4_features_test.go @@ -188,6 +188,45 @@ func TestUnicodeIdentifiers(t *testing.T) { parsesOK(t, "p ?é\n") } +// TestOperatorMethodName asserts that an explicitly-called operator method +// (`recv.OP(arg)`) names the method by the operator's own spelling — not the +// backtick “ ` “ that only the empty-XSTRING backtick-method case yields. +func TestOperatorMethodName(t *testing.T) { + cases := []struct{ src, name string }{ + {"1.+(2)", "+"}, + {"1.-(2)", "-"}, + {"1.*(2)", "*"}, + {"1.**(2)", "**"}, + {"a.<=>(b)", "<=>"}, + {"a.<(b)", "<"}, + {"a.>(b)", ">"}, + {"a.<=(b)", "<="}, + {"a.>=(b)", ">="}, + {"a.==(b)", "=="}, + {"a.===(b)", "==="}, + {"a.!=(b)", "!="}, + {"a.<<(b)", "<<"}, + {"a.>>(b)", ">>"}, + {"a.&(b)", "&"}, + {"a.|(b)", "|"}, + {"a.^(b)", "^"}, + {"a.=~(b)", "=~"}, + {"a.!~(b)", "!~"}, + {"a.~", "~"}, + {"a.!", "!"}, + {"a.``(c)", "`"}, // the backtick method (empty XSTRING literal), still "`" + } + for _, c := range cases { + call, ok := parseOne(t, c.src).(*ast.Call) + if !ok { + t.Fatalf("Parse(%q): top node = %T, want *ast.Call", c.src, parseOne(t, c.src)) + } + if call.Name != c.name { + t.Errorf("Parse(%q): method name = %q, want %q", c.src, call.Name, c.name) + } + } +} + // --- Feature 8: safe-navigation with an operator method --- func TestSafeNavOperatorMethod(t *testing.T) {