From 77d7928ff241ec9f31ba7b07b055bfd289bc4e9f Mon Sep 17 00:00:00 2001 From: Jiang Yi Date: Sun, 28 Aug 2022 11:58:51 +0200 Subject: [PATCH] [cling] Treat operator overload as normal function. Do not wrap it. Fixes https://github.com/root-project/root/issues/9449 so it is possible to define operator overload in cling cmd prompt. btw, Make SkipPointerRefs() to not assume next token being a tok::raw_identifier since it can be a global-scoped identifier, e.g. int* ::class_a::func_b(short c) { return nullptr; } --- .../cling/lib/Utils/SourceNormalization.cpp | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/interpreter/cling/lib/Utils/SourceNormalization.cpp b/interpreter/cling/lib/Utils/SourceNormalization.cpp index b6115c95d41d5..dc2fa148aff3c 100644 --- a/interpreter/cling/lib/Utils/SourceNormalization.cpp +++ b/interpreter/cling/lib/Utils/SourceNormalization.cpp @@ -21,12 +21,19 @@ namespace { ///\brief A Lexer that exposes preprocessor directives. class MinimalPPLexer: public Lexer { - ///\brief Jump to last Identifier in a scope chain A::B::C::D + ///\brief Jump to the next token after a scope chain A::B::C::D /// bool SkipScopes(Token& Tok) { + Token LastTok; + return SkipScopes(Tok, LastTok); + } + + bool SkipScopes(Token& Tok, Token& LastTok) { + LastTok = Tok; + if (getLangOpts().CPlusPlus) { while (Tok.is(tok::coloncolon)) { - if (!LexClean(Tok) || Identifier(Tok).empty()) + if (!LexClean(LastTok) || Identifier(LastTok).empty()) return false; if (!LexClean(Tok)) return false; @@ -38,9 +45,7 @@ class MinimalPPLexer: public Lexer { ///\brief Skips all contiguous '*' '&' tokens /// bool SkipPointerRefs(Token& Tok) { - while (Tok.isNot(tok::raw_identifier)) { - if (!Tok.isOneOf(tok::star, tok::amp)) - return false; + while (Tok.isOneOf(tok::star, tok::amp)) { if (!LexClean(Tok)) return false; } @@ -71,14 +76,34 @@ class MinimalPPLexer: public Lexer { return false; } - // Function or class name should be in Tok now - if (Identifier(Tok).empty()) + auto LastTok{Tok}; + // skip scopes in function name + // e.g. int ::the_namespace::class_a::mem_func() { return 3; } + if ((Tok.is(tok::coloncolon) && !SkipScopes(Tok, LastTok)) || + (!LexClean(Tok) || + (Tok.is(tok::coloncolon) && !SkipScopes(Tok, LastTok)))) return false; - // Advance to argument list or method name - if (!LexClean(Tok)) + const auto Ident{Identifier(LastTok)}; // function, operator or class name + + if (Ident.empty()) return false; + if (Ident.equals("operator")) { + // Tok is the operator, e.g. <=, ==, +... + // however, for operator() and [], Tok only contains the + // left side so we need to parse the closing right side + // TODO: tok::spaceship operator<=> + if ((Tok.isOneOf(tok::l_paren, tok::l_square) && !CheckBalance(Tok)) || + // user-defined literal, e.g. double operator "" _dd(long double t) + // TODO: parse without the space right after "", + // e.g. double operator ""_dd(long double t) + (Tok.is(tok::string_literal) && !LexClean(Tok)) || + // Advance to argument list or method name + !LexClean(Tok)) + return false; + } + if (!SkipScopes(Tok)) return false; @@ -228,7 +253,7 @@ class MinimalPPLexer: public Lexer { return kNONE; // Advance to argument list, or next scope - if (!LexClean(Tok)) + if (!SkipIdentifier(Tok)) return kNONE; // Function name should be last on scope chain